UTA ↔ J.P. Morgan Global Payments 2 Integration Specification — v3.0
Bank: J.P. Morgan Chase — Global Payments 2 (GP2) platform + ancillary APIs UTA System: Client Processing (replacing NetSuite AR) Document Status: Draft v3.0 — In ReviewLast Updated: 2026-05-12 Supersedes: UTA JPM GP2 Integration Specification v2.2.md (retained for historical reference; do not edit) Authors: Cliff Song & Andrew (Product), with engineering review by Amir Hajizadeh; pending input from JPM Integration Manager
How to Read This Document
This spec is organized by integration capability. Each service is documented in one place, with its confirmation status, channel choice, and rollout sequencing attached as metadata. If you want to see what's shipping first, see §11 Rollout Sequencing — but every service lives in its capability section regardless of when we build it.
Scope boundary — and who owns what. This document covers the JPM ↔ UTA integration boundary only at two layers:
- The wire contract — what data crosses, in what format, on what schedule, via which channel, with which credentials. Documented per service in §6 / §7.
- The business requirements UTA imposes on each call at the integration boundary — when to call each endpoint, what to do with the response payload, how to handle each exception class at the integration boundary. Examples already documented inline: §6.1's
postCodePending-vs-Settled treatment, §6.5's Payment Receipts dedup-by-endToEndIdrule, §7.1's Pre-Flight pass/fail/manual-review gate, §7.2–§7.5's idempotency + polling-fallback rules, §7.9's Positive Pay Phase-1 decisioning posture, §7.11's inbound-credit-refund rail-selection, §8 polling cadences, §9 Three-Way Match. Cliff (Product) owns this layer.
Three-document set required for full implementation:
| Doc | Owner | Covers | Status |
|---|---|---|---|
| (A) This spec — JPM ↔ UTA integration spec | Cliff | The integration boundary: wire contract + integration-boundary requirements (above) | In flight (~99% populated; open items in §12) |
| (B) Client Processing behavior spec — what inside Client Processing triggers integration calls and processes the resulting payloads | Cliff (Product) | The upstream business-rules layer: e.g., "when an athlete's commission is finalized, schedule a settlement payout that fires §7.2 / §7.3 / §7.5"; refund-authorization workflow; rail-selection policy; AR-side matching rules; GL-posting cadence; manual-review queue ownership | Not yet started — Cliff to scope and draft |
| (C) Engineering design doc — class decomposition, queue architecture, retry semantics, error-handling matrices, callback-receiver structure | Amir's engineering team | The technical implementation of (A) + (B) | Drafted by Amir's team after (A) and (B) are both ready |
This spec (A) alone is not sufficient input for engineering — (C) needs both the integration contract (A) AND the Client Processing behavior (B) to design against. Without (B), the engineering team can build the JPM-facing plumbing but won't know what inside Client Processing fires it or how the data is consumed once received.
Within this spec (A) only: if implementation surfaces a requirement gap at the integration boundary (an exception class with no documented handling rule, an unspecified call cadence on a JPM endpoint), Amir's team flags it back to Cliff for a requirements decision, which gets landed in this spec — not in the engineering design. Requirement gaps inside Client Processing (when to trigger, business-rule branching, refund authorization) land in (B), not (A).
| If you are... | Read sections |
|---|---|
| Business stakeholder (skim, 5 min) | §1 Executive Summary, §2 What's Changed in v3.0, §11 Rollout Sequencing |
| JPM Integration Manager / RM | §1, §3 Architecture, §6 Inbound Data, §7 Outbound Payments, §8 Status, §12 Open Items |
| Dev team (Amir and engineers) | All sections; a separate engineering design doc will follow |
| Product team (Andrew + Cliff) | All sections; §11 Rollout, §12 Open Items, §13 Next Actions |
Source citation policy: Every endpoint, field, schedule, and behavior is cited to either (a) the JPM developer portal page (URL inline on each "Source basis" line, plus a consolidated index in §14 References), (b) the 2026_GP2_Client_Integration_Guide_Version_2_2.pdf with page number, or (c) a dated conversation with the JPM Integration Manager. Anything inferred or not yet confirmed is tagged [CONFIRM with JPM]. No Dev Test Cases or UAT Scenarios are written against a feature with open [CONFIRM] items — those features carry a Confirm-Blocked tag at the feature level.
Per-service metadata block: Each service in §6–§7 carries a small header block:
Status: Cleared | Confirm-Blocked | Deferred | Not Yet Discussed
Channel: REST | Webhook | Polling
Sequence: (which rollout wave, see §11)No cross-bank contamination. This document covers JPM only. CNB EASI-Link and BofA references must never appear here. Likewise, JPM-specific patterns (CloudEvents, mTLS + JWS) must not bleed into the CNB or BofA specs.
1. Executive Summary
UTA is replacing the AR functions of NetSuite with a custom system (Client Processing). This document specifies the integration between Client Processing and J.P. Morgan Chase via the Global Payments 2 (GP2) platform and its ancillary APIs.
The all-REST architecture (no SFTP, no SOAP):
- REST / JSON over mTLS + JWS — All outbound payment submissions, status inquiries, validation, account/transaction reporting, and check management. Authentication is X.509 mutual TLS for transport identity plus a separate Digital Signature certificate that signs each POST body via JWS/RS256, plus an OAuth Bearer token (signed JWT assertion in CAT/Prod) carrying authorization.
- CloudEvents Webhooks (push) — JPM pushes real-time status updates for every outbound payment (GP2 Callbacks) and notifications for every inbound RTP credit (Payment Receipts API). UTA hosts the callback receiver; JPM authenticates to it via a callback certificate.
No BAI2 SFTP file delivery is in scope for the GP2 surface. Account-level balances come from the Account Balances API (§6.2) and transaction history from the Transaction Details API (§6.1) — both REST products with BAI codes embedded in the JSON transaction objects. BDC (FDX v6) is JPM's commercial-segment alternative; UTA is corporate-segment and ineligible (per Jessica Jin 2026-05-12). If UTA later requires bulk BAI2 batch files, that is a separate JPM Treasury Services product outside this spec.
Current state (2026-05-12):
- All inbound flows scope-locked or Confirm-Blocked. GP2 Callbacks (outbound status), Payment Receipts (inbound RTP credits), Transaction Details API + Account Balances API (intraday + prior-day reporting, EOD balance lock), Check Image retrieval. Inbound wire and inbound ACH credits depend on Transaction Details API polling (§6.1) — no webhook product covers them today.
- All outbound payment flows scope-locked on REST. RTP (US TCH + FedNow), ACH (both credit disbursements and authorized debit pulls, with NACHA SEC codes), Domestic Wire (same-currency), Cross-Currency Wire / FX (RFQ Quote → Trade → GP2 Wire with
/FXA/<contractId>— see §7.6), Stop Payment, Check Revoke, Check Issuance, Check Print. - Status strategy locked: Webhook-first via GP2 Callbacks (CloudEvents 1.0). Polling fallback via
GET /payment/v2/payments/{paymentId}only if no callback is received within rail SLA (§8). - Phase 1 deferrals: Positive Pay exception decisioning REST API (still pending JPM GA), Push to Card / Push to Wallet / Zelle / Kinexys / Interac (out-of-scope rails on the same GP2 endpoint), JPM Wallet (separate product not in scope unless required for FX wires per §7.6).
- GP2 pilot status: As of March 2026, GP2 was in pilot phase per JPM Integration Manager. UTA evaluated as strong candidate for the pilot program. v2.2 of this spec captured this; the developer portal
2026-03-20changelog and continued public publication of GP2 docs imply broader access today, but UTA's enrollment status must be confirmed before production go-live — see §12 Open Item #1. - PoC status: No live PoC has been executed against JPM. CNB's PoC validated end-to-end on SOAP. JPM PoC is a §13 next action.
Production target: October 2026 (~5 months out) — same target as the CNB integration to keep the program coherent. Test readiness: 2–3 months for connectivity, callback configuration, validation, and API testing. The 13-step JPM onboarding process documented in the GP2 Integration Guide is estimated at 29–75 business days, which fits the 2–3 month window only if onboarding starts immediately after this spec is approved.
Open items from JPM:
- JPM Integration Manager owes (a) the inbound webhook signature scheme for GP2 Callbacks + Payment Receipts — no public docs surface mTLS-reverse, HMAC, or signature-header semantics (§12 #2), (b) the complete CloudEvent
typeenumeration per rail — public portal shows onlyPayment.CompletedandPayment.Rejected, OAS implies many more (§12 #3, #25), (c) Payment Receipts rail coverage for inbound wire and inbound ACH credits — OAS schema is rail-agnostic but public narrative framed RTP-only (§12 #36), (d) Positive Pay decisioning REST API GA timing — Q2 2026 tentative per Jessica Jin 2026-03-03 (§12 #7). - JPM RM owes UTA's GP2 pilot enrollment confirmation and the certificate exchange to enable Client Acceptance Testing (CAT) access.
Open items from UTA:
- Stand up the callback receiver endpoint (HTTPS) UTA will publish to JPM for both GP2 Callbacks and Payment Receipts. Architecture TBD — pending Amir's review (candidate approach floated in early discussions: AWS API Gateway + Lambda fronted by an mTLS-terminating load balancer, but not confirmed by UTA Engineering). The callback cert UTA installs is JPM's, not UTA's.
[ACTION — Amir, UTA Engineering: confirm or propose alternative architecture] - Klutch account list for CAT entitlement — confirmed 2026-05-12. JPM serves Klutch only (touring, endorsements, and voiceovers are at CNB). Accounts in scope: 900867182 (KSG Operating USD) and 900867232 (KSG Client Trust USD). Closes §12 #18.
2. What's Changed in v3.0 (vs. v2.2)
| Area | v2.2 said | v3.0 says | Why it changed |
|---|---|---|---|
| Document organization | Outbound Command Layer / Inbound Audit Layer / Reconciliation / Errors | Capability-organized with per-service Status / Channel / Sequence metadata blocks; matches the CNB v5 structure for cross-bank consistency | Editorial — easier to read, easier to keep in sync with CNB and BofA specs |
| GP2 endpoint path | POST https://api.payments.jpmorgan.com/payment/v2 | POST https://api.payments.jpmorgan.com/payment/v2/payments (note trailing /payments). Sibling endpoints: GET /payment/v2/payments/{paymentId} (status), POST /payment/v2/payments/returns (RTP returns only), GET /payment/v2/payments/returns/{returnId} (return status). Optional ?view=FULL|SUMMARY on GET. | Confirmed against developer portal RTP/ACH/Wire how-to pages |
| Sandbox host | api-mock.payments.jpmorgan.com | api-sandbox.payments.jpmorgan.com (the actual sandbox host per JPM public certs page). api-mock.payments.jpmorgan.com is the mock host. The global sandbox tier is api-sandbox.*. | Public certs page enumerates Sandbox / CAT / Production hosts |
| OAuth audience / scope | Sandbox client_credentials with scope jpm:payments:sandbox | Audience format is jpm:uri:environment:product (e.g., jpm:uri:prod:payments). Sandbox uses Basic auth (client_id + client_secret); CAT and Production use signed-JWT assertion. Scopes are optional. | OAuth page at developer portal |
| Certificate stack | 4 cert types (mTLS, Digital Signature, Callback, Encryption) | 5 cert types — adds the OAuth Signed-JWT Assertion certificate (used to sign client_assertion in CAT/Prod). All 5 documented in §5.1. | Authentication page at developer portal |
| Cert validity | Not specified | Cannot exceed 1 year from issuance. Max 2 certificates may share the same Common Name. | Authentication page |
| Cert installation cadence | Not specified | JPM publishes a 2026 callback/encryption cert installation calendar with 24 release windows (~every 2 weeks). Cutoff dates are strict — "Certificates submitted after the listed cutoff date will be installed in the next available release window. Exceptions cannot be accommodated." | Environments page at developer portal |
| Inbound reporting product direction | "Account Balances API" + "Transaction Details API" as standalone ancillary products | Confirmed permanent. Earlier v3.0 drafts pointed at BDC (FDX v6 REST API) as the modern consolidation path. Jessica Jin clarified 2026-05-12 that BDC is JPM's commercial-segment product and UTA (corporate-segment) is ineligible — standalone Transaction Details API v3.1.8 (§6.1) and Account Balances API v1.0.5 (§6.2) are UTA's permanent reporting path. See §14.9 BDC entry marked OUT OF SCOPE. | Jessica Jin 2026-05-12 (closes §12 #9 / #10 / #11 / #26 / #28) |
| Payment Receipts / Credit Confirmation API | Documented but PDP path partially correct | Confirmed live and separate. Path on UTA's side: {YOUR-SERVER-DOMAIN.com}/creditConfirmation. JPM-side OAS path: /webhook/credit-confirmation. Webhook event paymentReceipts. Currently RTP-network only — TCH, FedNow, UK FPS, SEPA Inst, AU NPP, HK FPS, ID/MY/SG/MX SPEI/BR PIX. Wire and ACH inbound credits are NOT documented as supported — UTA's only inbound visibility for wire/ACH is Transaction Details API polling (§6.1). | Payment Receipts overview + OAS at developer portal |
| NACHA SEC codes (ACH debit) | Not specified | paymentTypeInformation.localInstrumentCode.code must be set to CCD, PPD, WEB, TEL, or IAT for ACH debit (transferType = DEBIT). These map to the NACHA SEC codes UTA already uses on the existing legacy ACH file flow. | ACH debit parameters page |
| endToEndId reuse window | Conflated 24h vs 60d | Per-rail clarification. ACH and Wire: 60 days. RTP: not explicitly published — treat as 24h conservative until JPM confirms. Duplicate detection fires as 11585 / 11587 / 11630 (HTTP 4xx). | ACH debit parameters + Wire resources pages |
| endToEndId length | Generic 32-char hex | Per-rail. RTP: 1–35 chars alphanumeric. ACH: 1–15 chars alphanumeric only (stricter). Wire: max 35 chars; industry best practice 16. | Per-rail parameters pages |
| Cross-currency wire / FX flow | Three-step RFQ: Quote → Trade → inject Contract ID via instructionForDebtorAgent: /FXA/<id> | Cleared — end-to-end flow documented (2026-05-11). Upstream RFQ now anchored on Request for Quote API v1.0.1 OAS: POST /tsapi/v1/quotes → /tsapi/v1/trades, returning jpmContractId (T… 30-char). Wire-body field instructionForDebtorAgent: /FXA/<jpmContractId> confirmed by Jessica Jin (2026-03-03). FX Rate Sheet API v1.0.2 documented as alternative published-rate path (CNB §5.6 functional equivalent). See §7.6.1–§7.6.6; §12 #4 closed. | Request for Quote API v1.0.1 OAS + FX Rate Sheet API v1.0.2 OAS + Jessica Jin 2026-03-03 |
| Wire returns | Not specified | Wires are irrevocable. GP2 has no /returns endpoint for paymentType=WIRE. Recall must be initiated bilaterally with JPMC ops. | Same-currency wire overview |
| ACH returns | Polling | No client-initiated return endpoint for ACH. RDFI returns surface as a status update on the original payment: paymentStatus = RETURNED. Only RTP supports client-initiated returns via POST /payment/v2/payments/returns, and currently only for Brazil PIX. | RTP returns + ACH overview |
| Payment Cancellation | POST /payment/v2/payments/{paymentId}/cancel [CONFIRM] | Still [CONFIRM]. Cancellation is referenced verbally ("possible while paymentStatus is PROCESSING with sub-statuses SCHEDULED or PENDING_COMPLIANCE_REVIEW") but the exact endpoint path is not surfaced in any public docs. JPM Integration Manager owes the canonical path. | Developer portal does not expose path |
| GP2 Callbacks / CloudEvents | Payment.Accepted, Payment.Processing, Payment.Settlement.Sent, Payment.Completed, Payment.Rejected | The public portal documents ONLY Payment.Completed and Payment.Rejected verbatim. The OAS callbacks block (paymentEvent callback under createPayment, x-tags: Webhooks) implies many more event types per rail (Push to Card, ACH Batch, RTP-BR PIX Return) but does not enumerate them. JPM Integration Manager owes the complete type enum. | GP2 Callbacks page + GP2 OAS |
| Inbound webhook signature scheme | Not specified | Not specified on the public portal either. The OAS security stub is x-jpmc-security: {} — empty placeholder. UTA must require JPM to provide the inbound webhook authentication contract (mTLS reverse, HMAC, JWT bearer, signature header, or other) before opening the callback receiver to JPM's source IPs. | GP2 Callbacks page + Payment Receipts OAS |
| Checks API base URL | api-mock.payments.jpmorgan.com/payable/v2 | Confirmed by Jessica Jin 2026-03-03: mock api-mock.payments.jpmorgan.com/payable/v2; production analog api.payments.jpmorgan.com/payable/v2. v2.2 was correct on the base. Sub-paths reconciled against Checks API v2.1.1 OAS in §7.7 / §7.8 deep-scan. §12 #5 closed. | Jessica Jin 2026-03-03 + Checks API v2.1.1 OAS |
Multi-payee payees[] array | Confirmed for issuance | Confirmed in OAS v2.1.1 — both Issuance and Print support payees[] with priority, but with different limits. Issuance: up to 3 payees, names 1–50 chars, priority 1–3. Print: up to 2 payees, names 1–40 chars, priority 1–2. v2.2's claim about multi-payee on Issuance was correct; the v3.0 draft's framing (drawn from dev-portal narrative) was wrong and is corrected here. | Checks API v2.1.1 OAS |
| Stop vs Revoke vs Cancel | Conflated as "Cancellation" | Three distinct flows, all confirmed via Checks API v2.1.1 OAS (§12 #6 closed 2026-05-11). Cancellation (POST /checks/cancellations) — pre-issuance void before print/release. Stop (POST /checks/stops) — forward-looking; block before clearance. Revoke (POST /checks/stops/revoke) — unwinds a prior Stop using the stopId. | Checks API v2.1.1 OAS |
| Positive Pay decisioning | "Q2 launch tentative" | Still pending GA. Public developer portal does not expose any Positive Pay REST decisioning surface as of 2026-05-08. Until live, exception decisions remain manual via J.P. Morgan Access. | Developer portal Checks markdown |
| PACMan API | Referenced in older Integration Guide PDF, never sourced | Confirmed live at …/treasury/pacman/doc.md. Provides outage notifications and partner-bank availability, with webhook support specifically for U.S. RTP partner bank outages. New in v3.0 — recommend wiring into the RTP send path as an optional pre-flight check to pre-empt rejections. See §10. | Developer portal PACMan overview |
| GP2 changelog tracking | Not in v2.2 | Documented in §12. No breaking changes for UTA's RTP/ACH/Wire scope in last 6 months; v2.2.5 (2026-03-20) is the latest at time of writing. The 2025-10-22 release added transactionIdentifier field descriptions in callbacks/GET status — relevant for AR reconciliation joining. | GP2 Changelog page |
| Out-of-scope GP2 rails (one-line) | Not enumerated | Documented (§7.10). Push to Card, Push to Wallet, Zelle, Kinexys Digital Payments, Interac e-Transfer all reachable via the same POST /payment/v2/payments endpoint by paymentType value but not in scope for UTA. | GP2 capabilities page |
| Production target | Not pinned | October 2026 (~5 months out from 2026-05-08). Same target as CNB to keep the program coherent. | Cliff/Andrew alignment |
| Test-env readiness | "29–75 business days" onboarding | 2–3 months for connectivity, callback configuration, and API testing. The 13-step onboarding starts after this spec is approved and overlaps with development. | Cliff/Andrew alignment |
3. Integration Architecture at a Glance
JPM exposes the channels v3.0 uses for non-overlapping purposes. Unlike CNB (SOAP over a single EASISubmit operation + SFTP for files), JPM is all REST/JSON with CloudEvents webhooks — there is no SFTP or SOAP in this integration.
┌─────────────────────────────────────────────────────────────────────┐
│ J.P. Morgan Chase │
└─────────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────────┐
│ REST / JSON │ │ CloudEvents Webhooks │
│ (UTA → JPM) │ │ (JPM → UTA) │
├──────────────────┤ ├──────────────────────┤
│ mTLS (transport) │ │ Mutual TLS to UTA's │
│ + JWS RS256 │ │ callback receiver │
│ on POST bodies │ │ + JPM callback cert │
│ + OAuth Bearer │ │ Inbound webhook │
│ (signed JWT in │ │ signing scheme: │
│ CAT/Prod) │ │ [CONFIRM with JPM] │
├──────────────────┤ ├──────────────────────┤
│ GP2 Payments │ │ GP2 Callbacks │
│ (RTP, ACH, │ │ Payment.Completed, │
│ Wire) │ │ Payment.Rejected, │
│ Validation Svcs │ │ + per-rail variants │
│ Transaction │ │ Payment Receipts │
│ Details API │ │ /webhook/credit- │
│ Account Balances │ │ confirmation │
│ API │ │ (RTP only — not │
│ Checks API │ │ wire/ACH) │
│ │ │ │
└──────────────────┘ └──────────────────────┘
│ │
└──────────────┬───────────────┘
▼
┌───────────────────────────┐
│ UTA Client Processing │
│ (consumer system) │
└───────────────────────────┘Single GP2 operation across rails: every GP2 payment uses POST /payment/v2/payments over https://api.payments.jpmorgan.com/payment/v2/payments (Production) or https://api-sandbox.payments.jpmorgan.com/payment/v2/payments (Sandbox). The JSON body's paymentType field (RTP | ACH | WIRE) routes the rail; the transferType field (CREDIT | DEBIT) routes credit-push vs. debit-pull.
Status visibility via push, not pull: UTA's primary status path is the GP2 Callbacks webhook, not polling. Polling GET /payment/v2/payments/{paymentId} is a fallback used only when a callback has not arrived within rail SLA.
No raw bank data in NetSuite. NetSuite continues to receive Journal Entries only; raw GP2 callbacks, Transaction Details API responses, and check images stay inside Client Processing.
4. Authentication & Connectivity
4.1 Certificate Stack
JPM requires five distinct certificate types, each scoped to a specific function.
Per-environment, multi-cert math. "Separate credentials are required per environment (Client Testing and Production)" [JPM Authentication]. With 5 cert types × 2 environments = 10 unique certificates UTA must generate, install, rotate, and renew. CAT certs and Production certs share neither private keys nor lifecycle — they are independent stacks. Plan annual rotation (JPM hard-caps validity at 1 year) for all 10 in a single cycle to avoid per-bank fire drills — coordinate with the cross-bank cert ops runbook owned by Amir.
Client Authentication EKU is required on all UTA-presented mTLS certs. All UTA-presented mTLS certs must carry the Client Authentication Enhanced Key Usage (EKU) field. Some CAs (DigiCert specifically flagged by Jessica Jin 2026-05-12) are deprecating this from default cert templates as part of an industry shift toward narrower-purpose certs. UTA must explicitly request the Client Authentication EKU at order time; Server-Auth-only certs will be rejected by JPM. If the chosen CA can't include it on the current template, switch CAs from JPM's approved list before ordering. Tracked as §12 #40.
| Cert | Required for | Purpose | Notes |
|---|---|---|---|
| Transport (mTLS) | All REST calls in CAT/Prod | TLS host identity ("carries no access permissions") | SSL cert from JPM-approved CA list (25+ CAs: Amazon, DigiCert, GlobalSign, Let's Encrypt, Microsoft, Sectigo, etc.) |
| Digital Signature | All POST/mutating GP2 calls | Signs request body via JWS / RS256 | Different key from mTLS; uploaded separately |
| OAuth Signed-JWT Assertion | CAT + Production OAuth token requests | Signs client_assertion JWT (RS256) | Sandbox uses Basic auth instead — no JWT cert needed |
| Callback | GP2 Callbacks + Payment Receipts (JPM → UTA) | Auths JPM's webhook pushes to UTA's receiver | UTA installs JPM's callback cert; mTLS cert may be reused |
| Encryption (optional) | Payload-level / PII-field encryption | Optional defense-in-depth | Recommended for PII; not required by GP2 |
Validity: "Certificate validity cannot exceed one year from issuance" [JPM Authentication]. Common Name limit: "Maximum of two certificates can share the same Common Name" [JPM mTLS+Digital Signature]. Upload role: "API Security role" required to upload certificates to the Developer Portal [JPM mTLS+Digital Signature].
Rotation: JPM rotates its public certs in advance — clients must "transition to the new certificate before the listed rotation date" [JPM Public Certificates]. No automatic-rotation feature on UTA's side; manual rotation required.
4.2 OAuth
Token endpoint (CAT and Prod, unified): https://login.jpmorgan.com/oauth2/token
Grant: client_credentials. Audience parameter: jpm:uri:<env>:<product> (e.g., jpm:uri:prod:payments, jpm:uri:cat:payments). Scopes are optional.
Sandbox flow (Basic auth):
curl --location 'https://id.payments.jpmorgan.com/am/oauth2/alpha/access_token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=<client_id>' \
--data-urlencode 'client_secret=<client_secret>'CAT / Production flow (signed JWT assertion):
curl --request POST 'https://login.jpmorgan.com/oauth2/token' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode 'audience=jpm:uri:prod:payments' \
--data-urlencode 'client_assertion=<RS256-signed JWT>'JWT assertion shape:
| Claim | Value |
|---|---|
Header alg | RS256 |
Header kid | Thumbprint from Developer Portal Security page |
sub + iss | ClientId from Developer Portal Security page |
aud | https://login.jpmorgan.com/oauth2/token |
iat | Current Unix timestamp |
exp | iat + 30 (30-second JWT lifetime; the access token below is much longer-lived) |
nbf | Optional; iat if present |
jti | Optional unique JWT ID |
Token response:
{ "access_token": "eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 28800 }| API surface | Access token TTL | Refresh model |
|---|---|---|
| GP2, Validation Services, Checks, PACMan, Transaction Details, Account Balances | 28,800 sec (8 h) | Re-issue (no refresh token); proactive re-issue at ~7 h |
Critical: never reactively refresh on 401. A background job re-issues on schedule per surface.
4.3 Digital Signature on POST Bodies
POST/mutating calls must sign the JSON body using JWS RS256:
- UTF-8-encode the JSON payload, Base64URL-encode it
- Populate the JWS header with
alg: RS256 - Load the Digital Signature private key
- Sign the encoded payload with
SHA256withRSA(Java) /SHA256(JS) - Construct the JWS as
<encodedHeader>.<encodedBody>.<signature>
Header on the wire: Content-Type: application/jose (vs. application/json for unsigned GETs). Example:
curl --request POST --url <API endpoint> \
--header "Content-Type: application/jose" \
--header "Authorization: Bearer <access_token>" \
--cert <transport-cert> --key <transport-key> \
--data '<signed JWS payload>'Reporting / GET-only APIs (Account Balances, Transaction Details, GET status) require mTLS but do not require Digital Signature — Content-Type: application/json is fine on GETs.
4.4 Environments
Reconciled against the GP2 OAS v2.4.7 servers block (2026-05-08), the Transaction Details API v3.1.8 + Account Balances API v1.0.5 OAS servers blocks, and the developer-portal public-certs page:
| Tier | Hosts | OAS-confirmed assignment | Use |
|---|---|---|---|
| Mock (stub responses) | api-mock.payments.jpmorgan.com | GP2 OAS: "MOCK" tier | Functional development against simulated responses; no real auth required |
| Client Acceptance Testing (CAT) / Sandbox | api-sandbox.payments.jpmorgan.com | GP2 OAS labels this host "CLIENT TESTING - MTLS" — i.e., CAT, not standalone sandbox. UAT happens here with real mTLS + OAuth flow | Pre-production validation against JPM-side test environment with full auth stack |
| CAT (older alias) | api-cat.payments.jpmorgan.com, apigatewayqaf.jpmorgan.com | Listed on the JPM public-certs page; [CONFIRM with JPM] whether api-cat is deprecated in favor of api-sandbox or both are active for different products | Some JPM products may still route CAT through api-cat |
| Production | api.payments.jpmorgan.com, apigateway.jpmorgan.com | GP2 OAS: "PRODUCTION - MTLS"; Transaction Details / Account Balances: apigateway.jpmorgan.com/tsapi/v3 (mTLS) and openbanking.jpmorgan.com/tsapi/v3 (OAuth) | Live |
| PCI | dedicated PCI PROD / CAT / UAT endpoints | — | Card-present / Push-to-Card; out of scope for UTA |
Important correction from earlier v3.0 drafts: earlier drafts of this spec listed api-sandbox.payments.jpmorgan.com under "Sandbox / Mock" tier. The GP2 OAS explicitly labels it CAT (Client Testing). api-mock is the true sandbox/mock host. Use api-mock for stub testing; use api-sandbox only once CAT is provisioned and certs are exchanged.
Credential separation: "Separate certificates and credentials must be managed independently for each environment. Certificates cannot be shared across environments." [JPM Authentication].
JPM public certificate expirations (most recent published):
- Production
api.payments.jpmorgan.commTLS — valid through 2030-07-02 - Production
apigateway.jpmorgan.commTLS — valid through 2026-05-28 and 2026-10-22 (two certs; verify which UTA pins) - CAT
api-cat.payments.jpmorgan.commTLS — valid through 2030
UTA must monitor these dates and re-pin before expiry. The apigateway.jpmorgan.com 2026-05-28 expiry is the earliest material risk — it lands inside our development window; track it explicitly.
2026 callback / encryption certificate installation calendar. JPM does not install client-side callback or encryption certificates automatically. There are 24 release windows in 2026 (~every 2 weeks). Each has a strict cutoff:
"Production callback and encryption certificate installations follow a scheduled release calendar and are not processed automatically. Certificates submitted after the listed cutoff date will be installed in the next available release window. Exceptions cannot be accommodated." [JPM Environments]
Earliest cutoff: 2025-12-26 → install 2026-01-15. Latest cutoff: 2026-11-27 → install 2026-12-17. Releases on 2026-07-16, 2026-07-30, 2026-11-19, 2026-12-17 are flagged with double asterisks (significance not documented — [CONFIRM with JPM]). UTA's certificate-rotation runbook must align with this calendar.
4.5 Callback Receiver Configuration (UTA hosts; JPM pushes)
For both GP2 Callbacks and Payment Receipts, UTA hosts the HTTPS receiver and JPM pushes to it.
Conceptual primer. A callback is JPM pushing data TO UTA — the reverse of UTA calling JPM's API. Normal direction: UTA → POST → JPM, JPM responds synchronously. Callback direction: at some later time (seconds/minutes after the original call), JPM has new info — payment status changed, RTP credit landed, payment returned — and JPM POSTs that event to a URL UTA hosts. Without callbacks, UTA must poll GET /payment/v2/payments/{paymentId} to discover status changes (wasteful + minutes-of-delay). With callbacks, JPM pushes status changes in near-real-time and UTA's sub-ledger reacts immediately.
For UTA's Phase 1, two callback URLs are required — one per JPM product (GP2 Callbacks for outbound payment status across all rails; Payment Receipts for inbound RTP credits). PACMan's webhook (POST /client-domain) is a third potential URL deferred to Phase 2 per §10.
Authentication on inbound: when UTA submits a callback URL to JPM via the Payments Developer Portal (PDP), UTA also associates the JPM-issued Callback Certificate with that URL — JPM presents this cert when calling UTA's receiver so UTA's server can verify the inbound POST is genuinely from JPM (not a spoof).
UTA-side configuration steps:
- Stand up the HTTPS callback receiver. Architecture TBD pending Amir's review — candidate approach is AWS API Gateway + Lambda fronted by an mTLS-terminating ALB, but UTA Engineering owns the final design decision.
- Generate the URL UTA will publish to JPM (e.g.,
https://callbacks.uta.example/jpm/gp2/payment-eventsandhttps://callbacks.uta.example/jpm/payment-receipts/credit-confirmation). Both endpoints will be specified in §6. - Install JPM's callback certificate on the load balancer (downloaded from the JPM developer portal Security tab).
- Optionally upload UTA's encryption certificate if PII-field encryption is enabled.
JPM-side configuration steps:
- UTA's representative goes to the Global Payments screen → Security tab in the Payments Developer Portal.
- Selects the environment (CAT or Production).
- Under Response → Callbacks, clicks "Configure callbacks".
- Enters UTA's callback URL.
- Selects/uploads the authentication certificate (mTLS cert may be reused).
- Optionally uploads UTA's Encryption Certificate.
- Clicks "Configure callbacks" and confirms the configuration is active.
- Submits the callback cert via the cert-installation calendar window (§4.4).
Inbound webhook signature scheme: [CONFIRM with JPM]. The public developer portal does not document an HMAC, JWT, or signature-header scheme on inbound webhooks — both the GP2 Callbacks OAS and the Payment Receipts OAS show x-jpmc-security: {} (empty placeholder). Until JPM provides the contract, UTA's callback receiver must validate JPM's source identity via mTLS only (the callback cert in step 3 above) and must not open authenticated processing to traffic that lacks a valid mTLS handshake against that cert.
5. Onboarding & Connectivity Sequence
Spec basis: GP2 Integration Guide v2.2 (2026_GP2_Client_Integration_Guide_Version_2_2.pdf) onboarding section, plus developer portal Treasury Global Payments getting-started page.
The 13-step onboarding process (estimated 29–75 business days) gates production go-live behind two checkpoints: Client Testing Environment and Production Verification Testing. Both require certificate exchange between JPM and UTA before access is granted [Developer Portal — Treasury Global Payments getting-started].
UTA prerequisites — confirm before formal kickoff (per Jessica Jin 2026-05-12):
Before sending the formal implementation request to Sam Bomes + Joey at JPM, UTA must have ready:
- Accounts in scope — confirmed 2026-05-12. Two Klutch accounts at JPM: 900867182 (KSG Operating USD) and 900867232 (KSG Client Trust USD). JPM provisions these for CAT and Production entitlement (closes §12 #18).
- Payment types in scope — explicit list of which
paymentTypevalues UTA will use in Phase 1 (RTP, ACH credit, ACH debit, Wire, FX Wire, plus Checks: Issuance, Print, Cancel, Stop, Revoke). The book-transfer use case (§7.5.1) ispaymentType: WIREwith intra-JPMC routing — no separate scope flag needed. - Certificates obtained — all 5 cert types per §4.1. Note: Jessica flagged industry-wide DigiCert renewal-timeline changes (§12 #40) — research current DigiCert timelines before generating UTA's certs to avoid window misalignment with the JPM 2026 cert-installation calendar.
- POC list registered in JPM's Developer Portal (PDP) — per Jessica 2026-05-12: "All POCs will have to be registered within PDP, even though they are not utilizing the tech first hand." UTA's POC slate: Cliff (Product), Andrew (Product), Amir (Engineering — API Security role for cert ops), Stan (Business sponsor — read-only / compliance visibility). Each registers their own named account; UTA does not use a shared-mailbox account.
Items to cover during the JPM implementation kickoff call (with Jessica + the assigned technical implementation manager + Sam Bomes / Joey):
- PDP organization + project structure. UTA preference: single broadly-named project (e.g., "UTA — JPMorgan Payments" or "UTA Bank Integration — JPM"), not Klutch-specific. UTA serves Klutch on JPM today but plans to add other UTA entities to JPM over time; a non-entity-specific project name allows additive expansion without spinning new projects per entity. Confirm with the implementation team that the single-project pattern is the recommended approach for multi-entity corporate clients (vs. one project per entity).
- PDP POC roles and accounts. UTA's proposed account structure (per prerequisite #4 above): Amir on API Security; Cliff, Andrew as Product roles; Stan as business-sponsor read-only. Confirm role taxonomy and any other JPM-required roles UTA must fill.
- Validation Services per-customer values (§12 #38). The
x-client-idandx-program-idvalues for each Validation Services profile UTA enables (Standard, Global, Account Confidence Score, Microdeposit) are issued at customer onboarding. Get these assigned during kickoff. - Inbound webhook authentication scheme (§12 #2). Public OAS shows
x-jpmc-security: {}(empty placeholder) for both GP2 Callbacks and Payment Receipts. UTA needs the canonical scheme JPM uses when calling UTA's receiver — mTLS-reverse, HMAC, JWT, signature header, or other. - CloudEvent
typeenum per rail (§12 #3, #25). Public portal documents onlyPayment.Completed/Payment.Rejected. OAS implies many more event types per rail. UTA's callback dispatcher routing depends on the complete enum — request the full list during kickoff. - Positive Pay Phase 1 decisioning posture (§7.9). Positive Pay protection is active in Phase 1 via §7.7 Issuance (every UTA-issued check is registered with JPM, exceptions are flagged on mismatch). The programmatic decisioning REST API is Q2 2026 launch tentative (§12 #7) — so for Phase 1 UTA must choose how exceptions get decisioned: (a) Manual JPM Access UI — UTA operator(s) log in daily during JPM's cutoff window to review exceptions and click PAY/RETURN, OR (b) Default decisioning rules configured at onboarding (e.g., auto-return-all, or auto-pay-below-$X). UTA decisions to lock in during kickoff: which path; if (a), which UTA operator(s) own the daily workflow + escalation path; if (b), what the default-rule policy is. The JPM REST decisioning API will be wired in additively in Wave 3 when GA — no Phase 1 architectural pre-investment needed.
Stages relevant to UTA:
- Formal implementation request to Sam Bomes + Joey at JPM (per Jessica 2026-05-12) — triggers implementation-team assignment + UAT environment setup. Jessica will be on the kickoff call to provide context.
- Spec approval (this document).
- Cert Authority chosen + certs generated (UTA side, all 5 types per §4.1) — see prerequisite #3 + §12 #40 (DigiCert timelines).
- JPM enables UTA's account in the Developer Portal Security tab.
- UTA uploads certs through the Security tab.
- Certificate exchange — JPM sends callback cert to UTA; UTA's mTLS pinned on JPM side.
- CAT access opened.
- Test plan executed — every service in §6 + §7 with a positive and negative test.
- Production Verification Testing — small-volume validation runs in Prod.
- Go-live.
Account list for CAT entitlement — confirmed 2026-05-12. Two Klutch accounts UTA needs JPM to provision: 900867182 (KSG Operating USD) and 900867232 (KSG Client Trust USD). JPM serves Klutch only — touring, endorsements, and voiceovers are at CNB and out of scope for this spec. These accounts are included in the formal implementation request to Sam Bomes + Joey (closes §12 #18).
Onboarded Accounts verification (one-time, at CAT-access opened and again at Prod go-live). Use the JPM Onboarded Accounts API v1.0.1 (Playbook/Onboarded Accounts 1.0.1.yaml) to enumerate Klutch's provisioned accounts and the JPM products active on each at each environment transition. Confirms (a) the account list matches what UTA requested, (b) entitlements for all in-scope products (Transaction Details, Account Balances, GP2, Checks, Validation Services, FX Rate Sheet, Payment Receipts, Request for Quote) are active, and (c) no unexpected accounts or products are attached. One-time verification at the env-transition checkpoint — not part of UTA's per-transaction request flow.
6. Inbound Data Services
Every service in this section delivers data from JPM into UTA's environment. The data-feed services (Transaction Details API, Account Balances API, Statements — manual download in Phase 1, Check Images) come first because they are the structural equivalent of CNB v5's §5.1–§5.9 — the bank-side ledger feed UTA reconciles against. The push-event services (Payment Receipts, GP2 Callbacks) follow because they ride on top of the same accounts and arrive only when something happens on those accounts.
Two inbound channels — when each one fires:
| Service | What it covers | Channel | Latency |
|---|---|---|---|
| §6.1 Transaction Details API | Comprehensive — every transaction that hits the account (inbound wires, ACH credits/debits, check deposits, lockbox items, RTP credits, fees, returns, reversals) | REST polling (every 15 min during business hours) | Up to 15 min + JPM posting cadence |
| §6.5 Payment Receipts API | Inbound RTP credits only (TCH RTP, FedNow) — a narrow, push-notified subset of what Transaction Details also reports | Webhook push (JPM → UTA receiver) | Seconds |
The two are complementary, not redundant. Transaction Details is UTA's authoritative ledger feed for reconciliation (§9 Three-Way Match) and covers every rail. Payment Receipts is a narrow real-time push for the one rail where the funds are final-and-irrevocable on arrival (RTP) and where the originator typically expects an acknowledgement faster than a 15-min poll cycle can provide.
Overlap vs disparate data:
- RTP credits appear in both channels — Payment Receipts pushes within seconds; Transaction Details surfaces the same item on the next poll cycle with full BAI-coded ledger context. UTA's reconciler must dedupe by
endToEndId/ bank reference, treating the Transaction Details record as the system-of-record entry and the Payment Receipts event as the early-trigger signal. - Inbound wire, ACH, and check deposits — visible only through Transaction Details polling. Payment Receipts does not cover these rails.
- Outbound payment status — handled by GP2 Callbacks (§6.6), a separate webhook product, not Payment Receipts.
Why both channels in Phase 1 (the non-latency case): Even setting aside the seconds-vs-minutes argument, Payment Receipts adds value for RTP specifically because (a) settlement certainty — an RTP credit pushed via Payment Receipts is final the moment it arrives, so downstream auto-application can fire immediately rather than waiting for the next poll to confirm; (b) scalability headroom — if RTP credit volume grows, push-on-event scales independently of the polling cadence and does not require shortening the poll interval (which would multiply API call cost across all accounts); and (c) cost decoupling — the polling cost stays flat regardless of RTP volume.
For UTA's reconciliation model: Transaction Details + Account Balances together feed the EOD Three-Way Match (§9 Brakes). Payment Receipts is an operational accelerator for the RTP receivables sub-flow, not part of the ledger-of-record reconciliation chain.
6.1 Transaction Details API — Intraday + Prior-Day Activity (CNB §5.1 + §5.2 replacement)
Status: Cleared (Phase 1) — JPM-prescribed product per the Treasury Reporting Playbook | Channel: REST polling (OAuth or mTLS) | Sequence: Wave 1
Purpose: Intraday + prior-day transaction detail with explicit BAI Type Codes — the direct functional replacement for CNB's BAI2 DDA Current Day (§5.1) and DDA Prior Day (§5.2) feeds, plus richer EDI 820 NACHA equivalent (CNB §5.3) and lockbox deposit detail (CNB §5.4) embedded in the response. JPM's implementation manager prescribes this API for UTA's treasury reporting; see US JPM API Playbook — Reporting v1.
OAS verified against Transaction Details API v3.1.8 OpenAPI 3.0.0 spec on 2026-05-11 — see Playbook/Transaction Details API 3.1.8.yaml. Lifecycle: LIVE but flagged tier: LEGACY — production-ready today; LEGACY tier reflects that JPM's commercial-segment clients use BDC (FDX v6), but UTA is corporate-segment and ineligible for BDC per Jessica Jin 2026-05-12. Transaction Details API is UTA's permanent inbound transaction-reporting path, not a transitional one.
Why Transaction Details API is the right product for UTA (not BDC). Earlier v3.0 drafts pointed at BDC v6.2.16 because BDC's OAS mentioned BAI codes and the dev portal positions BDC as the modern FDX-v6 successor. The JPM-issued Reporting Playbook actually prescribes Transaction Details API for UTA's tier of client, and Jessica Jin reconfirmed 2026-05-12 that BDC is JPM's commercial-segment product — UTA (corporate-segment, on Access platform) cannot use it. Transaction Details API is purpose-built for the BAI2-replacement use case: explicit baiType.typeCode field (not buried in a generic commercialCode), built-in CURRENT_DAY / PRIOR_DAY query modes, multi-account in a single call, lockbox remitter + invoiceDetail shapes, ACH batch + addenda inline, wire-specific fields (wireType, repairCode, reversal), and a postCode field (P/I) that signals prior-day vs intraday in every record.
| Attribute | Value |
|---|---|
| Endpoint | GET /transactions (operationId getTransactions) — single endpoint, mode-switched by query params |
| Base URLs (from OAS) | Production OAuth: https://openbanking.jpmorgan.com/tsapi/v3 · Production mTLS: https://apigateway.jpmorgan.com/tsapi/v3 · CAT OAuth: https://openbankingcat.jpmorgan.com/tsapi/v3 · UAT OAuth: https://openbanking-uat.jpmorgan.com/tsapi/v3 · CAT mTLS: https://apigatewaycat.jpmorgan.com/tsapi/v3 · QAF mTLS: https://apigatewayqaf.jpmorgan.com/tsapi/v3 |
| Auth model | mTLS and/or OAuth 2.0 (JPMC-OAuth2 with Reader role for read-side). Per OAS x-jpmc-security, either auth method is accepted on its own; mTLS+OAuth combined is the production recommendation |
| CNB §5.1 equivalent — Intraday | GET /transactions?accountIds=<ids>&relativeDateType=CURRENT_DAY — returns same-day posted + memo-posted activity. Direct replacement for CNB BAI2 Current Day file |
| CNB §5.2 equivalent — Prior Day | GET /transactions?accountIds=<ids>&relativeDateType=PRIOR_DAY — returns settled prior-day activity. Direct replacement for CNB BAI2 Prior Day file |
| Multi-account in one call | accountIds is an array (comma-separated). One call returns transactions across multiple accounts — on-par with CNB's whole-relationship BAI2 file |
| Optional date range (alternative to relativeDateType) | startDate + endDate (both YYYY-MM-DD). Cannot be combined with relativeDateType (errors: GCA-018 for startDate+relativeDateType conflict, GCA-019 for endDate+relativeDateType). Maximum window: 5 days (error GCA-065) — for back-fill / catch-up only, not steady-state polling |
| Lockbox enrichment | lockbox information=true query param (note the literal space in the parameter name per the OAS) — returns full lockbox remitter, lockboxPaymentDetail, and invoiceDetail blocks for any credit transactions sourced from a lockbox deposit. Direct replacement for CNB §5.4 Image Deposit Item File metadata (image retrieval is separate — see §6.5) |
| Pagination | Offset-based via pageNumber query param (integer, ≥1). Response pagination block carries pageSize, totalPages, pageNumber, totalRecords |
| OAS schema marker | x-jpmc-api-maturity: { lifecycle-status: LIVE, tier: LEGACY }. LEGACY reflects JPM's commercial-segment migration path (to BDC), not UTA's situation. UTA is corporate-segment and stays on Transaction Details API permanently (Jessica Jin 2026-05-12 — closes §12 #28). No migration abstraction layer needed |
Response payload — top-level shape:
{
"pagination": {
"pageSize": 100,
"totalPages": 3,
"pageNumber": 1,
"totalRecords": 257
},
"data": [ /* array of transaction objects — see below */ ]
}data[] transaction object — fields (verified against OAS v3.1.8):
| Field | Type | Notes — CNB BAI2 equivalent and UTA usage |
|---|---|---|
account.accountId | string | UTA's account number for this transaction |
account.accountName | string | Friendly account label |
account.bankId | string | Routing transit number (US) or SWIFT BIC (international) or multibank info |
account.branchId, account.bankName | string | Branch + bank descriptor |
account.currency.code | string | ISO 4217 (Klutch is USD) |
account.aba, account.swift | string | Routing identifiers per network |
receivedTimestamp | ISO 8601 date-time | When JPM made this transaction available for reporting — the API's freshness anchor; differs from posting time |
asOfDate | string (date) | When transaction posted to the account (T-0 for intraday; T-1 for prior-day) |
valueDate | string (date) | When funds become available (credits) or cease to be available (debits) |
debitCreditCode | string | D (Debit) or C (Credit) — primary direction indicator |
baiType.typeCode | string | THE BAI Type Code — direct replacement for CNB BAI2 Type Code (e.g., 165 for wire debit, 115 for wire credit, 195 for ACH credit, 475 for ACH debit). UTA's existing BAI2 parser keys off this exact code |
baiType.description | string | Human-readable BAI category (e.g., "Wire In", "ACH Credit") |
baiType.btrsTypeCode | string | X9 BTRS/BTR3 equivalent (FDX-standard transaction code) |
fundsTypeCode | enum | Availability: 0 = Immediate, 1 = Day-1, 2 = Two+ Days, S = Distributed (split), V = Value-dated, Z = Unknown |
currency.code | string | Transaction currency (ISO 4217) |
amount | number | Transaction amount in account currency (decimal, e.g., 7783.94) |
immediateAvailable, day1Available, day2Available, day2PlusAvailable, day3PlusAvailable | number | Float availability tracking — replicates CNB BAI2 fund-type breakdown for cash-position calculations |
bankReferenceSearchable.standardValue | string | Bank-assigned reference (trace number for ACH, Fed Reference for wire) — primary join key for outbound payment reconciliation |
customerReferenceSearchable.standardValue | string | Customer-assigned reference (check number, lockbox number, originator's endToEndId) — primary join key for AR auto-match |
repairCode | string | Wire-only; non-null if JPM repair desk modified the wire instruction |
reversal | string | Non-null if this entry is a reversal of a prior posting |
wireType | string | Wire transaction subtype |
shortDescription | string | Transaction type summary |
postCode | string | P = prior-day (settled), I = intraday (memo-posted, may not yet be settled) — the freshness signal that lets UTA's AR auto-match distinguish provisional from final |
checkNumber | number | Check number for check-related entries |
lockbox | object | Returned for lockbox deposit credits: { lockboxSequenceCode, lockboxItems, lockboxNumber, lockboxDepositDate, lockboxDepositTime } |
lockboxInformation | object | Rich lockbox detail (when lockbox information=true is queried): { number, siteName, remitter: { batchNumber, batchItemCount, batchAmount, debitCreditCode, entryDate, creditDate, depositDate, depositTime, transactionDescriptionType (LBX/ACH/WIRE/PCX/BRANCH/MISC/VRD/VRM), ddaNumber, lockboxPaymentDetail: { itemNumber, remitterBank, checkNumber, routingNumber, itemAmount, remitterName, transactionId, paymentSequenceNumber, invoiceDetail: { invoiceNumber, invoiceAmount, invoiceDate, invoiceRefNumber } } } } |
narrativeText | object | Free-form narrative; VRN (Virtual Reference Number) information carried after the VXR tag (per OAS description). VRN is a JPM virtual account / sub-account identifier — see Playbook §10 |
sepaDetailsXml | string | Full SEPA payment detail (XML blob) for SEPA transactions — not applicable to UTA's US-only flows |
supplementalTextSet, supplementalText, supplementalTextRecordList | object/string/array | Narrative text in additional languages (for international wires) |
achBatchItems[] | array of AchBatchWithItems | The CNB §5.3 EDI 820 NACHA equivalent — INLINE, no separate file. Each batch carries: achCompanyDescription, achCompanyId, achCompanyName, batchCreditAmount, batchDebitAmount, batchItemCount, batchNetAmount, debitCreditCode, entryDate, originatorBatchSequenceNumber, standardEntryClass (NACHA SEC: CCD/PPD/WEB/TEL/etc.), items[] of AchIndividualItem (each with baiTypeCode, clientOriginatingTraceNumber, dfiAccountId, dfiBankId, individualId, individualName, itemAmount, and achAddendaList[] with addenda text records) |
addenda | string | Raw addenda text (additional to the achBatchItems structured breakdown) |
transactionId | string | Unique within Current Day, unique within Historical — but NOT across. Per OAS: "Cannot be used to uniquely identify a transaction in the Current Day, and then identify that same transaction days later after the transaction has been hard-posted." UTA's reconciliation must rely on bankReferenceSearchable.standardValue + customerReferenceSearchable.standardValue for cross-day joins, not transactionId |
Treatment of same-day wire credits — UTA DECISION: Conservative (Pending). Current-day wire credits with postCode: "I" (intraday) are treated as memo-posted / not finalized until the prior-day pass with postCode: "P" settles them. The postCode field gives UTA a direct, per-record signal — UTA's parser branches on this value. AR auto-match (§6.5) and the Three-Way Match (§9) gate cash application on postCode: "P", not on intraday appearance.
| Approach | Description | Status |
|---|---|---|
| Conservative (Pending) | Treat postCode: "I" entries as unposted until same record returns with postCode: "P" | ✅ Selected. Lower risk; delays same-day cash application |
| Aggressive (Booked) | Treat any wire credit visible in the API as fully booked, regardless of postCode | Rejected — UTA chose lower-risk path |
Rationale: Wires are technically irrevocable on JPM's side once received, so Aggressive would have been defensible. UTA chose Conservative because (a) the postCode field gives explicit JPM-side acknowledgment of which entries are final, (b) overnight reconciliation catches any sanctions-driven reversal or beneficiary dispute before it touches AR, and (c) the operational benefit of same-day cash application is small relative to the audit clarity of waiting for postCode: "P".
Recommended polling cadence (carries from v2.2 + Playbook §5):
| Use case | Cadence | Query |
|---|---|---|
| Intraday refresh (Current Day) | Every 15 minutes during business hours (4 AM – 7:45 PM PT Mon-Fri) | ?relativeDateType=CURRENT_DAY |
| Prior-day confirm | Once daily at ~7:30 AM local time | ?relativeDateType=PRIOR_DAY |
| Back-fill / catch-up (after outage) | On demand, max 5-day window | ?startDate=YYYY-MM-DD&endDate=YYYY-MM-DD |
Sandbox example (Postman / curl) — to be validated once UTA has Transaction Details API mock or CAT access. Mock URL [CONFIRM with JPM Integration Manager] — the OAS only declares production + CAT servers, no separate mock.
Intraday call (CNB §5.1 equivalent):
GET https://openbanking.jpmorgan.com/tsapi/v3/transactions
?accountIds=123456789,987654321
&relativeDateType=CURRENT_DAY
&lockbox%20information=true
Headers:
Accept: application/json
Authorization: Bearer <OAuth-access-token> ← Reader role required
(mTLS handshake at the transport layer)Prior-day call (CNB §5.2 equivalent):
GET https://openbanking.jpmorgan.com/tsapi/v3/transactions
?accountIds=123456789,987654321
&relativeDateType=PRIOR_DAY
&lockbox%20information=true
Headers: same as aboveCustom range (backfill, max 5 days):
GET https://openbanking.jpmorgan.com/tsapi/v3/transactions
?accountIds=123456789
&startDate=2026-05-06
&endDate=2026-05-10
&lockbox%20information=true
&pageNumber=1Note on lockbox information parameter: the OAS literally declares the parameter name with a space — name: lockbox information. URL-encoded that's lockbox%20information. Test in CAT whether JPM's validator accepts the literal space or only the URL-encoded form; some HTTP clients refuse to send unencoded spaces in query strings. [CONFIRM in Postman / CAT]
Error codes (verbatim from OAS v3.1.8):
| HTTP | Code | Meaning |
|---|---|---|
| 400 | GCA-006 | End Date cannot be less than the Start Date |
| 400 | GCA-018 | Invalid parameter combination: startDate + relativeDateType |
| 400 | GCA-019 | Invalid parameter combination: endDate + relativeDateType |
| 400 | GCA-020 | relativeDateType value invalid (must be CURRENT_DAY or PRIOR_DAY) |
| 400 | GCA-026 | Date format invalid (use yyyy-MM-dd) |
| 400 | GCA-065 | Date range cannot exceed 5 days |
| 400 | GCA-106 | lockbox information must be true or false |
| 400 | GCA-107 | Date format invalid (use yyyy-MM-ddTHH:mm:ss.SSSSSS) — applies to a sub-field |
| 400 | GCA-132 | pageNumber must be greater than 0 |
| 403 | GCA-001 / GCA-003 | Client not eligible for the API service |
| 403 | GCA-009 | The requested accounts were not found |
| 403 | GCA-022 | No eligible accounts were found |
| 503 | GCA-099 | System is unavailable |
Error envelope shape: { "errorCode": "GCA-006", "errorMsg": "End Date cannot be less than the Start Date" }. Flat envelope with no nested context[] array.
Open items specific to this section:
- The OAS doesn't declare a Mock server, only Production + multiple CAT/UAT — confirm whether sandbox testing is via CAT (with sandbox credentials) or via a separate mock host.
[CONFIRM with JPM Integration Manager] - BAI Type Code list — the OAS doesn't enumerate every BAI Type Code JPM returns. UTA's existing CNB BAI2 parser already handles the standard BAI2 codes (115, 165, 195, 475, 935 RETURN WIRE, etc.); confirm JPM uses the same code dictionary.
[CONFIRM with JPM] lockbox informationparameter — literal space vs URL-encoded space — see note above- EOL timeline for Transaction Details API (LEGACY tier) — closed/de-prioritized 2026-05-12 (§12 #28). Per Jessica Jin, UTA cannot migrate to BDC regardless of EOL timing (corporate-segment ineligibility). Re-open only if JPM announces an Access-platform replacement for corporate clients.
6.2 Account Balances API — EOD Balance Anchor for Three-Way Match (CNB §9 "Brakes")
Status: Cleared (Phase 1) — JPM-prescribed product per the Treasury Reporting Playbook | Channel: REST polling (OAuth or mTLS) | Sequence: Wave 1
Purpose: Bank-side balance snapshot for the "Brakes" half of the Three-Way Match (§9). Confirms the closed-cycle ledger balance UTA's sub-ledger must match against before closing each reconciliation cycle. Companion to §6.1 Transaction Details API; both are prescribed by JPM's Reporting Playbook.
OAS verified against Account Balances API v1.0.5 OpenAPI 3.0.0 spec on 2026-05-11 — see Playbook/Account Balances API 1.0.5.yaml.
| Attribute | Value |
|---|---|
| Endpoint | POST /balance (operationId retrieve-balances). NOTE: this is a POST — accountList and date params live in the request body, not query string |
| Base URLs (from OAS) | Production OAuth: https://openbanking.jpmorgan.com/accessapi · Production mTLS: https://apigateway.jpmorgan.com/accessapi · CAT/UAT OAuth: https://openbankinguat.jpmorgan.com/accessapi · CAT mTLS: https://apigatewayqaf.jpmorgan.com/accessapi. Different base path than Transaction Details (/accessapi vs /tsapi/v3) — UTA's HTTP client config must support both |
| Auth model | OAS x-jpmc-security: {} is an empty placeholder, but the server descriptions explicitly call out OAUTH and MTLS tiers — same dual-auth model as Transaction Details. [CONFIRM with JPM] the exact OAuth scope/role for the Account Balances API |
| Request modes (mutually exclusive) | (A) Date range: startDate + endDate (both YYYY-MM-DD), max 31-day window (error GCA-005) — more lenient than Transaction Details' 5-day cap, which makes sense for balance snapshots that don't change minute-to-minute. (B) Relative date: relativeDateType: CURRENT_DAY | PRIOR_DAY |
| Multi-account in one call | accountList[] array of { accountId } objects — single POST returns balances across multiple accounts |
| Conflict errors | GCA-018/019 if startDate/endDate combined with relativeDateType; GCA-021 if accountId missing |
Request body shape (verified against OAS):
{
"relativeDateType": "CURRENT_DAY", // OR: startDate + endDate
"accountList": [
{ "accountId": "00000000000000304266256" },
{ "accountId": "00000000000000010962009" }
]
}OR for a date range:
{
"startDate": "2026-05-06",
"endDate": "2026-05-10",
"accountList": [
{ "accountId": "00000000000000304266256" }
]
}Response body shape (verified against OAS):
{
"accountList": [
{
"accountId": "123456789",
"accountName": "ABC INC",
"branchId": "",
"bankId": "2100002",
"bankName": "JPMORGAN CHASE BANK, N.A. - NEW YORK",
"currency": {
"code": "USD",
"currencySequence": 0,
"decimalLocation": 2,
"description": "US DOLLAR"
},
"balanceList": [
{
"asOfDate": "2023-01-17",
"recordTimestamp": "2023-01-17T13:47:41Z",
"currentDay": true,
"openingAvailableAmount": 7783394.91,
"openingLedgerAmount": 7783394.91,
"endingAvailableAmount": 21311879.19,
"endingLedgerAmount": 21311879.19
}
]
}
]
}Balance fields explained (carry into §9 Three-Way Match):
| Field | Meaning | UTA usage |
|---|---|---|
asOfDate | The business date this balance represents | Match against UTA's GL cycle date |
recordTimestamp | When JPM recorded this balance snapshot (ISO 8601 datetime, UTC) | For audit trail |
currentDay (boolean) | true = this is today's balance; false = historical/prior-day | UTA's logic distinguishes provisional vs settled |
openingAvailableAmount | Available balance at start of day (excludes float not yet available) | T-1 closing should match T0 opening |
openingLedgerAmount | Ledger balance at start of day (includes all posted items, no float adjustment) | Audit ledger continuity |
endingAvailableAmount | Available balance at end of day | PRIMARY "Brakes" field for Three-Way Match §9 |
endingLedgerAmount | Ledger balance at end of day | Cross-check against endingAvailableAmount to detect float discrepancies |
Recommended polling cadence (carries from v2.2 + Reporting Playbook):
| Use case | Cadence | Mode |
|---|---|---|
| End-of-day balance lock | ~10:00 PM local time Mon–Fri | relativeDateType: CURRENT_DAY — captures endingLedgerAmount after settlement |
| Prior-day opening balance confirm | ~7:30 AM local time Mon–Sat | relativeDateType: PRIOR_DAY — confirms T-1 ending matched UTA's books |
| Back-fill / catch-up | On demand, max 31-day window | startDate + endDate |
Unavailability fallback (carries from prior spec drafts): if the API is unavailable at the scheduled EOD close: (1) log failure with timestamp, (2) retry at 10-min intervals for up to 60 min, (3) if still unavailable, flag the cycle as PENDING_BANK_CONFIRMATION and alert the GL manager. Do not close the reconciliation cycle without a confirmed bank balance.
Sandbox example (Postman / curl) — to be validated once CAT access is provisioned:
End-of-day balance lock (current-day):
POST https://openbanking.jpmorgan.com/accessapi/balance
Headers:
Accept: application/json
Content-Type: application/json
Authorization: Bearer <OAuth-access-token>
(mTLS handshake at transport layer)
Body:
{
"relativeDateType": "CURRENT_DAY",
"accountList": [ { "accountId": "<klutch-account-number>" } ]
}Prior-day confirm:
POST https://openbanking.jpmorgan.com/accessapi/balance
Headers: (same)
Body:
{
"relativeDateType": "PRIOR_DAY",
"accountList": [ { "accountId": "<klutch-account-number>" } ]
}Error codes (verbatim from OAS v1.0.5 — note: many return HTTP 200 with an errors[] body, per the OAS 200 Errors response):
| Code | Description |
|---|---|
GCA-001 / GCA-003 | Unauthorized Access |
GCA-005 | Date range cannot exceed 31 days (more lenient than Transaction Details' 5 days) |
GCA-006 | End Date cannot be less than the Start Date |
GCA-009 | The requested accounts were not found |
GCA-010 | The account was not found |
GCA-018 | Invalid parameter combination: startDate + relativeDateType |
GCA-019 | Invalid parameter combination: endDate + relativeDateType |
GCA-020 | relativeDateType value invalid (must be CURRENT_DAY or PRIOR_DAY) |
GCA-021 | Account ID is required |
GCA-022 | No eligible accounts were found |
GCA-023 | Request format invalid |
GCA-024 | No transaction was found for this transaction on the requested day |
GCA-025 | No transactions were found for this account in the requested date range |
GCA-026 | Date format invalid (use yyyy-MM-dd) |
GCA-068 | Access Denied to all accounts: Not entitled to the required countries via the Preta Registry Role |
GCA-076 | Access Denied: Not entitled to required country via Preta Registry Role |
GCA-099 | System is Unavailable |
Error envelope shape: { "errors": [ { "errorCode": "GCA-006", "errorMsg": "..." } ] }. Slightly different from Transaction Details (which uses a flat { errorCode, errorMsg } not an errors[] wrapper).
Open items specific to this section:
- OAS
x-jpmc-security: {}is an empty placeholder.[CONFIRM with JPM Integration Manager]the exact OAuth scope/role for Account Balances (likely "Reader" by analogy to Transaction Details, but unverified) - Preta Registry Role error codes (
GCA-068,GCA-076) suggest country-level entitlements.[CONFIRM with JPM]what Preta Registry Role UTA needs for US accounts - HTTP status codes for errors — OAS bundles them as "200 Errors". Test in CAT whether errors actually come back with HTTP 200 +
errors[]body, or with non-200 status codes.[CONFIRM in Postman/CAT]
Source basis: Account Balances API OAS v1.0.5 — authoritative · US JPM API Playbook — Reporting v1 — Account Balances JSON sample on Playbook p. 36.
6.3 Monthly Statements (PDF) — Out of API scope in Phase 1
Status: Deferred — no API path available to UTA | Channel: Manual download from JPM Access UI (Phase 1); API path
[CONFIRM with JPM]| Sequence: Phase 2
Purpose: Monthly statement PDF retrieval for retention/compliance archive.
State (2026-05-12): JPM's documented Statements PDF API lives inside the Business Direct Connect (FDX v6) product — not available to UTA. Per Jessica Jin 2026-05-12, BDC is JPM's commercial-segment product; UTA is corporate-segment on the Access platform and cannot use BDC (see §14.9 BDC entry marked OUT OF SCOPE, §12 #9 / #10 / #11 / #26 / #28).
Phase 1 workaround: UTA's compliance team continues to download monthly PDF statements manually from the JPM Access UI, same as today's pre-integration workflow.
Open question for kickoff call with Jessica's implementation team: does JPM offer an Access-platform statement-retrieval API (analogous to BDC's /accounts/{accountId}/statements/{statementId} but on the corporate-segment side)? If yes, scope it into Phase 2. If no, the manual JPM Access download remains UTA's only path. Tracked as §12 #41.
Source basis: Jessica Jin 2026-05-12 (BDC ineligibility for UTA) · §14.9 Local Documents — OAS files BDC v6.2.16 row marked OUT OF SCOPE.
6.4 Check Image Retrieval — outgoing checks cleared
Status: Cleared (full OAS verified) | Channel: REST POST | Sequence: Wave 2
Purpose: Retrieve front + back images of cleared outgoing checks for audit and dispute support. (Electronic checks do not have associated images, per OAS CheckType enum.)
OAS verified against Checks API v2.1.1 OpenAPI 3.1.0 spec on 2026-05-12 — see Playbook/Checks API 2.1.1.yaml.
| Attribute | Value |
|---|---|
| Production base URL | https://api.payments.jpmorgan.com/payable/v2 |
| Mock base URL | https://api-mock.payments.jpmorgan.com/payable/v2 (matches Jessica Jin 2026-03-03 confirmation) |
| Endpoint | POST /checks/images/search |
| Auth | mTLS |
| Required body fields | debtor (with accountNumber), checks (with checkNumbers[] 1–5 items OR checkRange.{start, end}) |
| Filter fields | issueDateGte/issueDateLte (1-year window), postedDateGte/postedDateLte (1-year window), amountGte/amountLte, checkSequenceNumber |
| Pagination | limit (1–10, default 5; range searches max 10), offset (0–999) |
imageFormat | TIFF | PNG | JPEG (default PNG) |
| Response shape | CheckImageCollectionResponse — checkImages[] with frontImage and backImage as base64-encoded strings, plus pagination metadata and requestInvocationId |
Sample request — single check image:
{
"debtor": { "accountNumber": "1234567" },
"checks": { "checkNumbers": ["1005"] },
"issueDateGte":"2026-01-01",
"issueDateLte":"2026-03-31",
"imageFormat": "TIFF",
"limit": 1, "offset": 0
}Sample response (verbatim shape from OAS example):
{
"checkImages": [{
"checkNumber": "1005",
"checkAmount": { "amount": "205.05", "currency": "USD" },
"debtor": { "accountNumber": "1234567" },
"paidDate": "2026-04-01",
"frontImage": "<base64...>",
"backImage": "<base64...>",
"imageFormat": "TIFF",
"checkType": "CUSTOMER_CHECK"
}],
"pagination": { "offset": 0, "limit": 1, "totalCount": 1 },
"requestInvocationId": "n8a40v3r-3769-4o79-9z0l-ale1edc90389"
}Source basis: Checks API v2.1.1 OAS — authoritative · Checks → Check Image overview · Check Image parameters · Jessica Jin 2026-03-03 (mock base URL confirmation).
6.5 Payment Receipts API — inbound RTP credit confirmation
Status: Cleared (full OAS verified) — RTP only | Channel: Webhook (JPM → UTA) | Sequence: Wave 1
Purpose: Real-time push of every inbound credit on UTA's accounts — eliminates manual polling for incoming client payments (deal-payment intake from sports teams, brands, and sponsors on Trust; commission / agency-fee credits on Operating) on supported RTP networks. Conceptually a real-time alternative to discovering the same credit later via §6.1 Transaction Details API polling.
OAS verified against Payment Receipts v1.2.0 OpenAPI 3.0.0 spec on 2026-05-11 — see Playbook/Payment Receipts 1.2.0.yaml. Title in OAS: "Payment Receipts."
| Attribute | Value |
|---|---|
| Mechanism | Webhook push (JPM → UTA) — JPM-side declares this as a sample callback endpoint; UTA hosts the actual receiver |
| JPM-side OAS callback path | /webhook/credit-confirmation (POST, JSON body) |
| Receiver path (UTA-side) | {YOUR-SERVER-DOMAIN}/creditConfirmation per OAS callback example — UTA's actual URL will be configured during onboarding |
| Auth model | OAS x-jpmc-security: {} is empty placeholder. [CONFIRM with JPM Integration Manager] the inbound webhook signature scheme — same gap as GP2 Callbacks (§6.6, §12 #2) |
| Network coverage | RTP-only at time of writing. OAS examples cover Singapore IRCT, UK FPS Agency Banking. Per developer-portal narrative, also supports: US RTP (TCH), US FedNow, SEPA Inst, AU NPP, HK FPS, IDR, MYR, SGD, MXN SPEI, BRL PIX |
| No US RTP example in OAS | The OAS schema supports US RTP (clearing-system IDs, BIC, accountType: DDA, all present) but the 2 verbatim examples in the OAS are Singapore and UK — not US. The schema covers it; verify shape in CAT. [CONFIRM in CAT] the exact US RTP payload shape |
| Network coverage — wire / ACH | NOT documented as supported. UTA's only inbound visibility for wire / ACH credits is Transaction Details API polling (§6.1) and Account Balances API at EOD (§6.2) — [CONFIRM with JPM] whether wire / ACH inbound webhook is on the roadmap |
Webhook payload — top-level shape (verified against OAS):
{
"creditConfirmation": {
"eventId": "e24534b3-0251-4198-b408-e8f85a257d7e",
"createDateTime": "2021-12-13T14:00:57.751Z",
"transactionDetails": { /* see fields below */ }
}
}creditConfirmation.transactionDetails fields (full OAS v1.2.0 schema):
| Field | Type | Notes — UTA usage |
|---|---|---|
| Identifiers | ||
endToEndId | string | Customer-assigned reference; max length varies by market (UK FPS: 31 chars per OAS). Primary AR auto-match key |
firmRootId | string | JPM-assigned unique ID for this transaction. Preferred for cross-system joins within UTA's sub-ledger |
bankReferenceNumber | string | Bank-assigned reference (trace number, Fed Reference for wire) |
clearingSystemReference | string | Reference assigned by the clearing system (Central Bank, RTP network) |
transactionId | string | Unique ID from the first instructing agent (passed unchanged through interbank chain) |
instructionId | string | Unique instruction ID from instructing party for instructed party |
| Amounts and dates | ||
valueDate | date (YYYY-MM-DD) | When funds become available to UTA (the creditor) |
status | string | Transaction status (example: COMPLETED) |
paymentAmount | number | Amount credited to UTA |
paymentCurrency | string (ISO 4217) | Klutch credits will be USD |
| Payment type | ||
paymentTypeInformation.localInstrument.prtry | string (pattern ^[-_.A-Z0-9]{1,35}$) | Proprietary local-instrument code (e.g., ImmediatePayment for UK FPS) |
relatedParties.debtor | object | The party SENDING the money TO UTA |
relatedParties.debtor.debtorName | string | Required for some markets |
relatedParties.debtor.countryOfResidence | string (2-char ISO) | |
relatedParties.debtor.postalAddress | object | Full postal address with addressType (enum: ADDR/BIZZ/DLVY/HOME/MLTO/PBOX), streetName, buildingNumber, postalCode, townName, countrySubDvsn, country, addressLine[] (1-4 lines, max 40 chars each) |
relatedParties.debtor.debtorAccount.accountId | string | Debtor's account at the sending bank |
relatedParties.debtor.debtorAccount.accountType | enum: DDA | Currently only DDA in OAS |
relatedParties.debtor.debtorAccount.accountCurrency | string | |
relatedParties.debtor.ultimateDebtor | object | If the payment passed through an intermediary, the originator of the funds |
relatedParties.creditor | object | UTA (the party RECEIVING the money) |
relatedParties.creditor.creditorName | string | UTA's account name; required for India, UK, US RTP, SEPA Instant |
relatedParties.creditor.creditorAccount.accountId | string | UTA's Klutch account number |
relatedParties.creditor.creditorAccount.accountType | string | DDA expected |
relatedAgents | ||
relatedAgents.debtorAgent.financialInstitutionId.bic | string (max 11) | Sending bank's SWIFT BIC; required for UK/India/SG/AU/MY |
relatedAgents.debtorAgent.financialInstitutionId.clearingSystemId.id | string | Sending bank's clearing-system ID (alt to BIC) |
relatedAgents.creditorAgent.financialInstitutionId.bic | string | JPM's BIC (CHASGB2L, CHASUS33, etc.) — receiving bank |
| Purpose | ||
purpose.code | string | Payment purpose code (e.g., GDDS for goods) |
purpose.type | enum: CODE | PROPRIETARY | |
remittanceInformation | object | PRIMARY auto-match payload — read this for invoice numbers |
remittanceInformation.unstructuredInformation | array of strings | Free-form text remittance — example: ["FOR INVOICE: 2020-078-07-00001"]. Max 1 line × 140 chars for UK FPS. UTA's parser regex-matches invoice numbers out of this field. Shape note: outbound GP2 wires (§7.5) use [{text: "..."}] (array of objects) per Jessica Jin 2026-05-12 — UTA's builder/parser code must handle both directional shapes |
remittanceInformation.structuredInformation[].creditReference | string (max 140) | Structured payment reference — when present, contains the unambiguous payment reference. UTA matches on this directly |
remittanceInformation.structuredInformation[].additionalRemittanceInformation | string (max 250) | Applicable to MY FPS and UK FPS. Carries additional structured remittance |
relatedTransactions[] | array | Optional. If this payment is a response to a Request-for-Payment, links back to the original RFP transaction by endToEndId/firmRootId/bankReferenceNumber |
taxInformation | object | Mexico-specific (mandatory for MX credit confirmations) |
taxInformation.debtorTaxInformation.taxId | string | 12 chars for corporates, 13 for individuals (Mexico) |
taxInformation.debtorTaxInformation.taxpayerCategory | enum: INDIVIDUAL | CORPORATE | |
taxInformation.taxAmount | number |
OAS verbatim example — UK FPS Agency Banking inbound credit (GBP 250):
{
"creditConfirmation": {
"eventId": "972cf023-c185-4ffb-b63e-d47940c6c1e2",
"createDateTime": "2025-04-01T11:00:57.751Z",
"transactionDetails": {
"endToEndId": "RGB7000800901",
"bankReferenceNumber": "0RNFV599KLMN",
"clearingSystemReference": "KACE89HGT090877",
"firmRootId": "2ee43056-92df-496c-832d-da6453b3d6ad",
"valueDate": "2025-04-01",
"status": "COMPLETED",
"paymentTypeInformation": { "localInstrument": { "prtry": "ImmediatePayment" } },
"paymentAmount": 250,
"paymentCurrency": "GBP",
"relatedParties": {
"debtor": {
"debtorName": "Emily Davis",
"countryOfResidence": "UK",
"debtorAccount": { "accountType": "DDA", "accountCurrency": "GBP", "accountId": "8880000000" }
},
"creditor": {
"creditorName": "Softech Inc",
"creditorAccount": { "accountType": "DDA", "accountCurrency": "GBP", "accountId": "7770000000" }
}
},
"relatedAgents": {
"debtorAgent": { "financialInstitutionId": { "bic": "CHASGB2L" } },
"creditorAgent": { "financialInstitutionId": { "bic": "CHASGB2L" } }
},
"purpose": { "code": "GDDS", "type": "CODE" },
"remittanceInformation": {
"structuredInformation": [{
"additionalRemittanceInformation": "/TPP/0014H00001lFE7VQAW/SWI/SOFTWAREID/"
}]
}
}
}
}AR auto-match logic for UTA:
- First pass: match on
remittanceInformation.structuredInformation[].creditReference(when present) against UTA's open invoice list — exact match - Second pass: regex-extract invoice number patterns from
remittanceInformation.unstructuredInformation[]strings (e.g.,INV-\d{4,},PO-\d+) - Third pass (fallback): match on
endToEndIdif UTA originated a Request-for-Payment with that reference - Unmatched credits: queue for manual GL review with all received metadata for human disambiguation
Source basis: Payment Receipts OAS v1.2.0 — authoritative · OAS examples for Singapore IRCT and UK FPS Agency Banking verbatim · sandbox verification when CAT lands.
6.6 GP2 Callbacks — outbound payment status events (CloudEvents)
Status: Confirm-Blocked (event
typeenum; signature scheme) | Channel: Webhook | Sequence: Wave 1
Purpose: Real-time push of every status change on UTA-initiated GP2 payments — the primary status surface for outbound RTP, ACH, and Wire flows. Documented here in §6 because it arrives via webhook from JPM, but the polling fallback contract for the same events lives in §8 alongside the rest of the Status Inquiry strategy.
OAS verified against Global Payments v2.4.7 OpenAPI 3.0.1 spec on 2026-05-08. Webhook composition: Webhook = Event + PaymentEventData (per OAS Webhook schema, allOf: [Event, PaymentEventData]).
| Attribute | Value |
|---|---|
| Mechanism | Webhook push (JPM → UTA) — declared as a callbacks block under the createPayment operation in the GP2 OAS |
| Envelope | CloudEvents v1.0 (Event schema's specversion field defaults to "1.0") |
| Receiver path (UTA-side) | https://callbacks.uta.example/jpm/gp2/payment-events (UTA-defined; example) |
| OAS-required envelope fields | id (string), specversion ("1.0"), type (string), time (RFC 3339 date-time), source (URI-reference), data (object). dataschema is optional |
data payload type | `oneOf: PaymentEvent |
data.payments[] (PaymentEvent case) | Array of PaymentStatus objects, 1–50 items per webhook (per OAS — webhook can batch up to 50 status updates in one delivery) |
data.returns[] (PaymentReturnEvent case) | Array of PaymentReturnStatus objects, always 1 item (OAS minItems: 1, maxItems: 1) |
| Documented event examples in OAS | Alternate Payments - Push To Card Status, Alternate Payments - Push To Card - TP3 Status, Alternate Payments - Push To Card - TP3 Rejected Status, Alternate Payments - Kinexys Digital Payments (DDA to BDA) Completed Status, ACH Batch, RTP - BR PIX Payment Return. The exact CloudEvent type string for each (e.g., Payment.Completed, Payment.Rejected, or rail-specific variants) is NOT enumerated in the OAS — [CONFIRM with JPM] for the complete type enum |
PaymentStatus.paymentStatus enum (7 values) | RECEIVED | ACCEPTED | PROCESSING | CANCELED | REJECTED | COMPLETED | RETURNED |
PaymentStatus.paymentSubStatus enum (17 values) | RECEIVED, ACCEPTED, PROCESSING_BY_JPM, PENDING_CLIENT_ACTION, PENDING_COMPLIANCE_REVIEW, PENDING_FRAUD_REVIEW, PENDING_FUNDING_REVIEW, PENDING_JPM_REVIEW, SCHEDULED, PENDING_POSTING, CANCELED, REJECTED, REJECTED_BY_JPM, COMPLETED_BY_JPM, SENT_TO_CLEARING, DELIVERED_TO_RECIPIENT, RETURNED |
| PaymentStatus required fields | paymentId, paymentStatus, statusUpdatedAt, paymentIdentifiers, paymentType, transferType, requestedExecutionDate |
| PaymentStatus join keys | paymentId (JPM UUID — primary), paymentIdentifiers.endToEndId (UTA-supplied), clearingSystem.reference (network reference), and paymentIdentifiers.otherPaymentReferences.uetr (SWIFT GPI 36-char tracking, for wires/cross-border) |
PaymentStatus.exceptions[] | When status is REJECTED or CANCELED, populated with ErrorContext[] (1–100 items) carrying the 5-digit JPMC error code, message, location, field, and optional additionalContext (ISO 20022 / NACHA standard codes via StandardCodeContext) |
PaymentStatus.fxInformation | Read-only FX details on settled cross-currency wires — exchangeRate, exchangeRateType, rateId, contractId |
PaymentStatus.gpi.status | SWIFT GPI status for wire payments — separate from JPM's internal status, sourced from the SWIFT network directly |
| Delivery SLA | "Typically within 30 seconds" of the status change (per developer-portal docs; not stated in OAS) |
| Retry behavior | "Automatically retry the request until the error is resolved" (per developer-portal docs). Backoff curve, max attempts, and DLQ behavior [CONFIRM with JPM] |
| Ordering guarantees | Not specified — [CONFIRM with JPM] |
| Inbound signature scheme | OAS shows no security block on the webhook operation. [CONFIRM with JPM] what authentication JPM uses when pushing to UTA's receiver (mTLS-only, HMAC, JWT, etc.) — see §4.5 |
| Idempotency | Use the CloudEvent id field (Event.id) as UTA's dedup key. The contract is implied but not stated — [CONFIRM with JPM] |
Sample payload — Payment Completed:
{
"specversion": "1.0",
"id": "ec521d12-416e-4f48-a1b8-1d61e40146d2",
"time": "2025-07-18T07:03:22.503+00:00",
"type": "Payment.Completed",
"source": "payment/v2/payments?endToEndId=IMPS_0718123057",
"dataschema": "urn:com.jpmorgan.payments/payment-event",
"data": {
"payments": [{
"paymentId": "01981c56-0e48-7000-bfec-6fb5be1b3cc0",
"requestedExecutionDate": "2025-01-06",
"paymentStatus": "COMPLETED",
"paymentSubStatus": "COMPLETED_BY_JPM",
"statusUpdatedAt": "2025-07-18T07:03:22.503+00:00",
"paymentIdentifiers": { "endToEndId": "IMPS_0718123057" },
"paymentType": "RTP",
"transferType": "CREDIT",
"clearingSystem": { "reference": "D49KMSHY8GG2" }
}]
}
}Sub-ledger action mapping (subset; full table in §8):
paymentStatus × paymentSubStatus | GL action |
|---|---|
ACCEPTED × ACCEPTED | Create draft sub-ledger entry |
PROCESSING × PROCESSING_BY_JPM | No action; await next event |
PROCESSING × PENDING_COMPLIANCE_REVIEW | Flag for monitoring; do not post |
COMPLETED × COMPLETED_BY_JPM | Post to NetSuite GL |
COMPLETED × DELIVERED_TO_RECIPIENT | Post to NetSuite GL |
REJECTED × REJECTED_BY_JPM | Reverse draft entry; parse exceptions[].code |
RETURNED × RETURNED | Post return JE; notify AR |
Source basis: GP2 Callbacks · GP2 OpenAPI Spec · GP2 Status Responses & Error Codes · JPM Integration Manager (2026-03).
7. Outbound Payment Services
Every service in this section initiates an action from UTA into JPM via REST.
7.1 Validation Services — "Pre-Flight"
Status: Cleared (full OAS verified) — Pre-Flight gates §7.2–§7.5 | Channel: REST POST (sync) + optional
{client-url}/statuscallback (async) | Sequence: Wave 1
Purpose: Validate beneficiary account ownership AND entity identity/screening before any payment initiation. UTA runs every new payee through this gate before its first outbound payment, and re-runs on any payee whose details have changed. Reduces misdirected funds, mitigates fraud loss, and lowers payment-return rates.
OAS verified against Validation Services API v2.2.3 OpenAPI 3.0.1 spec on 2026-05-12 — see Playbook/Validation Services API 2.2.3.yaml. Title in OAS: "Validation Services API."
| Attribute | Value |
|---|---|
| Production base URL (mTLS) | https://apigateway.jpmorgan.com/tsapi/v2 |
| CAT base URL (mTLS) | https://apigatewaycat.jpmorgan.com/tsapi/v2 |
| Mock base URL | https://api-mock.payments.jpmorgan.com/tsapi/v2 |
| Entity validation endpoint | POST /validations/entities |
| Account validation endpoint | POST /validations/accounts |
| Request body shape | Array — both endpoints accept a batch of validations in one call (minItems: 0, no upper bound documented). Response is also an array, item-by-item correlated by requestId |
| Required headers | x-client-id (per-customer ID assigned at onboarding), x-program-id (per Validation Services product, e.g., VERIAUTH, VERIAUTHMULTI, VERIAUTHNONUS, VERIAUTHUS, SUREPAYVOP) |
| Optional header | x-program-id-type — defaults to AVS; identifies processing settings selected for the product |
| Auth | mTLS only — x-jpmc-securityDefinitions: MutualTLS (type: x509). No Digital Signature requirement on this API — distinct from GP2's JWS+RS256 stack. Closes the [CONFIRM] from v2.2 |
| Async callback support | Both endpoints declare a validationStatus callback at {client-url}/status (POST). Async path is used for validators that cannot return synchronously — primarily microdeposit Challenge flows. Callback payload = same ResponseCollection schema as the synchronous 200 |
| Per-customer values | x-client-id / x-program-id actual values are issued at customer onboarding (§12 #38 carries this open item) |
Profile selection (profileName body field, per OAS examples):
| Profile | x-program-id example | Use case |
|---|---|---|
Standard Account Validation (no profileName) | VERIAUTH | Synchronous account-ownership check — UTA's default for new US payees |
| Multi-line account validation | VERIAUTHMULTI | Batched account validation calls with transactions[] populated |
| Global Account Validation | VERIAUTHNONUS | International accounts (accountNumberType: IBAN, idType: SWIFT_ID / BIC) — UTA's path for cross-border wire beneficiaries |
| Account Confidence Score (ACS) | VERIAUTHUS | Returns RAG-banded numeric score in addition to verification — US-only |
Microdeposit (profileName: verificationauth) | PROGRAMID | Two-step flow: Initial call sends two small deposits to the target account; Challenge call asks the customer to confirm the amounts. ACH (idType: ABA) and RTP (idType: RTPABA) variants both supported |
SurePay VOP (profileName: SPIndividual / SPOrganization) | SUREPAYVOP | Verification of Payee for European IBAN beneficiaries |
Account Confidence Score (ACS) — OAS vs dev-portal mismatch (must resolve with Jessica before relying on ACS in Pre-Flight logic):
The OAS-confirmed AccountScore schema (lines 1093–1112 of Validation Services API 2.2.3.yaml) is {code: integer, message: string} — example values 1109 "Information Found" / 1209 "No Information Found". No numeric 0–1000 score field appears anywhere in the OAS. JPM's dev portal narrative documents a 0–1000 RAG-banded numeric score; the OAS does not expose it. Possibilities to confirm:
- The numeric score is returned inside the
detailsblock for VERIAUTHUS-profile responses (undocumented in OAS). - The dev-portal narrative is out of step with the current schema (OAS supersedes).
- The numeric score is computed internally and only the coded bucket (
1109/1209) surfaces.
Filed as §12 #42 — confirm with Jessica which slot/field carries the 0–1000 score for the ACS profile, or whether the only consumable signal is the coded AccountScore.code.
ACS bucketing per dev-portal narrative (treat as unconfirmed against OAS):
| Score | RAG | Meaning |
|---|---|---|
0 | RED | High risk of potential fraud or compromise |
1–199 | RED | Low-confidence range |
200–599 | AMBER | Medium-confidence range |
600–1000 | GREEN | High-confidence range |
ACS code prefixes per OAS examples: 11## = "Information Found", 12## = "No Information Found." US-only.
Account validation request fields — AccountDetails schema:
| Field | Type | Notes |
|---|---|---|
requestId (required) | string (max 75, ^[a-zA-Z0-9\-]+$) | UTA-generated unique ID per validation request; UUID recommended |
clientReferenceId | string (max 75) | Optional UTA-side reference (e.g., payee record ID) — echoed back |
account.accountNumber (required) | string (4–17 chars, alphanumeric) | The beneficiary account number |
account.accountNumberType | string | Examples: CLABE, DDA, IBAN |
account.financialInstitutionId.clearingSystemId.id (required) | string | Routing number / BIC / IBAN-derived ID |
account.financialInstitutionId.clearingSystemId.idType (required) | enum | CLABE | INFSC | IBAN | ABA | RTPABA | SWIFT_ID |
account.financialInstitutionId.bic | string | Optional alternate to clearingSystemId for SWIFT-routed accounts |
entity | oneOf: Individual | Organization | Optional but recommended — drives ownership-match logic populating Result.authentication |
transactions[] | array of Transaction | Required for microdeposit Challenge calls; carries the amounts the customer is confirming. Each item: context: ACCOUNT_VALIDATION, amount.{amount, currency} |
profileName | string | Selects the validation profile (see table above) |
Provider list (verbatim from OAS Response.provider description):
| Endpoint | Providers |
|---|---|
/validations/accounts | JPMC, JPMC_BENE, JPMC_ACH, GIACT, MICRODEPOSITS, EWS, EWS_VA, PATTERN_MATCH (OAS examples also show SUREPAY_VOP for the SurePay profile) |
/validations/entities | JPMC, JPMC_SCREENING, LEXISNEXIS, LEXISNEXIS_INSTANT_ID, LEXISNEXIS_BUSINESS_V2, GIACT_BUSINESS, GIACT_INDIVIDUAL, TRULIOO_INDIVIDUAL, TRULIOO_BUSINESS |
(Note: v2.2 spec listed SUREPAY_IBAN and JPMC_LIINK_CONFIRM — neither appears in OAS v2.2.3. Treat as deprecated/renamed; trust the OAS list.)
Response — ResponseCollection shape (echoed requestId, batch-aligned by index):
{
"requestId": "<echoed back>",
"clientReferenceId": "<echoed back>",
"profileName": "<echoed back>",
"responses": [
{
"codes": { /* ResultCollection — see below */ },
"provider": "JPMC_ACH",
"details": { /* provider-specific shape */ }
}
]
}ResultCollection — named result slots (Pre-Flight reads only the slots that apply to the profile run):
| Slot | Used for | Example code |
|---|---|---|
verification | Account is open and valid | 1002 "Open Valid" |
authentication | Account ownership matches the entity payload | 5002 "Ownership Match" |
individualID | Individual identity verification (Entity Validation) | 1101 "Pass" |
businessID | Organization identity verification (Entity Validation) | 2101 "Pass" |
individualScreening | Sanctions / PEP screening for an individual | 4609 "Potential Hit" |
businessScreening | Sanctions / PEP screening for an organization | 5609 "Potential Hit" |
verificationMicrodeposit | Microdeposit flow — verification step | — |
authenticationMicrodeposit | Microdeposit flow — authentication step | — |
limitAmount | Transaction-limit verification | — |
accountScore | ACS numeric score (separate AccountScore shape: {code, message}) | 1109 Information Found |
error | Operational error (see error-code table below) | 9005 Bad Request |
Result.message semantics — first digit of Result.code indicates result class (per OAS Result.message description):
| First digit | Class |
|---|---|
1 | Open Valid / Pass |
2 | Closed Invalid |
3 | No Information Found |
4 | Debit Return Likely / Potential Hit (screening) |
5 | Ownership Match |
6 | Ownership No Match |
7 | No Information Found |
9 | Operational error (see error-code table below) |
Sample request — Standard US account validation:
[
{
"requestId": "123e4567-e89b-12d3-a456-426614174000",
"clientReferenceId": "UTA-payee-12345",
"account": {
"accountNumber": "12345",
"financialInstitutionId": {
"clearingSystemId": { "id": "122199983", "idType": "ABA" }
}
},
"entity": {
"individual": { "firstName": "Jane", "lastName": "Abbot", "fullName": "Jane Abbot" }
}
}
]Sample response — Account open, ownership matches (verbatim from OAS):
[
{
"requestId": "123e4567-e89b-12d3-a456-426614174000",
"clientReferenceId": "UTA-payee-12345",
"responses": [
{
"codes": {
"verification": { "code": 1002, "message": "Open Valid" },
"authentication": { "code": 5002, "message": "Ownership Match" }
},
"provider": "JPMC_ACH",
"details": {
"paymentCheckContributingStatus": "Contributed",
"accountNumber": "XXXX5",
"financialInstitutionId": {
"clearingSystemId": { "id": "122199983", "idType": "ABA" }
}
}
}
]
}
]Sample response — Account Confidence Score (ACS) profile, x-program-id: VERIAUTHUS (synthesized from the OAS AccountScore schema — the OAS does not publish a full ACS response example; flagged as §12 #42):
[
{
"requestId": "123e4567-e89b-12d3-a456-426614174000",
"clientReferenceId": "UTA-payee-12345",
"responses": [
{
"codes": {
"verification": { "code": 1002, "message": "Open Valid" },
"authentication": { "code": 5002, "message": "Ownership Match" },
"accountScore": { "code": 1109, "message": "Information Found" }
},
"provider": "JPMC_ACH",
"details": {
"paymentCheckContributingStatus": "Contributed",
"accountNumber": "XXXX5",
"financialInstitutionId": {
"clearingSystemId": { "id": "122199983", "idType": "ABA" }
}
}
}
]
}
]Note on ACS shape: OAS-confirmed
accountScoreis{code, message}only. If JPM returns a numeric 0–1000 score (per dev-portal narrative), expected locations are (a) an additional field insidedetailsfor VERIAUTHUS profile, or (b) an undocumented field that may be added in a future OAS version. Until Jessica confirms (§12 #42), UTA's Pre-Flight ACS logic should key offaccountScore.codefirst-digit1(Information Found) vs2(No Information Found), not the un-located 0–1000 number.
Sub-ledger gate — Pre-Flight pass/fail logic for UTA:
- PASS → proceed to §7.2–§7.5:
codes.verification.codefirst digit is1ANDcodes.authentication.codefirst digit is5AND noindividualScreening/businessScreening"Potential Hit" / "Hit" - MANUAL REVIEW → block + queue for GL manager: any
individualScreeningorbusinessScreeningwithmessage: "Potential Hit"/"Hit"; anyauthenticationfirst digit6(Ownership No Match); anyverificationfirst digit4(Debit Return Likely) - FAIL → reject the payee record:
verificationfirst digit2(Closed Invalid);errorslot populated with any9###code - MICRODEPOSIT REQUIRED → when synchronous result returns first digit
3(No Information Found) on a US ACH/RTP beneficiary: switch toprofileName: verificationauthtwo-step flow (Initial + Challenge), receive Challenge result via{client-url}/statusasync callback
A payee that fails Pre-Flight must not proceed to §7.2–§7.5 without manual GL-manager override and audit-log entry.
Error codes:
| Code | HTTP | Meaning |
|---|---|---|
9001 | 200 | Data Provider Error |
9002 | 200 | Processing Error |
9003 | 200 | Timeout Error |
9004 | 200 | Client Configuration Error |
9005 | 200 / 429 | Bad Request — or rate-limit breached |
GCA-023 | 400 | Please re-send request in valid format |
GCA-129 | 400 | ProgramId is required |
GCA-001 / GCA-003 | 403 | Unauthorized Access |
GCA-103 | 403 | programId was not found |
GCA-099 | 500 | System is Unavailable |
Note: 9### codes are returned inside a normal 200 OK body in the error slot of ResultCollection, not as HTTP 4xx — UTA's client must inspect the body, not just the HTTP status.
Source basis: Validation Services API v2.2.3 OAS — authoritative · Validation Services overview · Account Validation overview · Account Validation parameters · Account Confidence Score how-to · Global Account Validation how-to · Verify Bank Account Status how-to · Entity Validation overview · Entity Validation parameters · Account Validation Global Coverage · Validation Services error codes.
7.2 RTP — Real-Time Payments
Status: Cleared | Channel: REST POST + Webhook callback | Sequence: Wave 1
Purpose: Instant credit-push payments on US TCH and FedNow rails (and other RTP networks if needed in future phases).
OAS verified against Global Payments v2.4.7 OpenAPI 3.0.1 spec on 2026-05-08 — see JPM/Playbook/Global Payments 2.4.7.yaml.
| Attribute | Value |
|---|---|
| Initiate endpoint | POST /payment/v2/payments (operationId createPayment) |
| Single-payment status endpoint | GET /payment/v2/payments/{paymentId} (operationId getPayment) with optional `?view=SUMMARY |
| Search-by-id endpoint | GET /payment/v2/payments?endToEndId=...&paymentType=... (operationId getPayments) — useful to look up by endToEndId if paymentId is lost |
| Returns endpoint | POST /payment/v2/payments/returns (operationId createPaymentReturns). Currently the OAS only shows a RealTimeBRPIXPaymentReturn example — i.e., Brazil PIX is the only verified return-supported rail. US TCH/FedNow client-initiated returns are not documented; must be initiated bilaterally with JPMC ops |
| Return status endpoint | GET /payment/v2/payments/returns/{returnId} (operationId getPaymentReturn) |
paymentType | "RTP" (fixed) |
transferType | "CREDIT" (fixed; RTP is credit-push only) |
| Required headers | Idempotency-Key (string, max 36 chars; example 1b036f9c-8c84-4ce6-b1dd-5979472945a1); Request-Id (string, max 128 chars); Authorization: Bearer <JWT> |
| Idempotency | Idempotency-Key reuse rules below; endToEndId reuse window not explicitly published in OAS — treat as 24h conservative for RTP |
| Limits | US TCH: USD 1,000,000. US FedNow: USD 500,000 (UTA's primary domestic RTP rail) |
| Hours / cutoffs | 24/7 — no cutoffs |
| Settlement | Seconds; immediate availability; irrevocable on COMPLETED |
Required body fields (per OAS Payment base schema — 8 required):
requestedExecutionDate(string,format: date, ISO 8601YYYY-MM-DD; must be current or future date)paymentIdentifiers.endToEndId(string, min 1, max 128 chars perEndToEndIdschema — much wider than my v3.0 spec's earlier "1-35 chars" claim. Rail-specific validators MAY be stricter than the base schema upper bound;[CONFIRM with JPM]the actual RTP-specific length validator in CAT before locking the AR generator)value.currency(Iso4217CurrencyCodeenum),value.amount(STRING with decimal, e.g."122.08", not a number — verified against OAS RTP exampleRealTimeUSRTPWalletWithdrawals)transferType="CREDIT"paymentType="RTP"debtor.account.accountNumber(string, max 128; USA RTP rail-specific max is 31 per OASAccountIddescription),debtor.name(string)debtorAgent.financialInstitutionIds[]withid(9-digit ABA for US, e.g.,021000021) andidType(USABAfor US ABA,BICfor SWIFT BIC,CLEARING_SYSTEM_IDfor clearing scheme IDs)creditor.account.accountNumberorcreditor.account.alternateAccountIdentifiers(proxy:EMAL,MOBN,NIDN,EVP,QRCD)
Note: creditorAgent is NOT in the OAS Payment.required[] list, but rail-specific validators likely require it for RTP. [CONFIRM with JPM] whether RTP requires creditorAgent always or only when creditor.alternateAccountIdentifiers is not used.
AccountType enum (full OAS list — debtor.account.accountType / creditor.account.accountType): DDA | BDA | CARD | LOAN | ODFT | NREX | CACC | SVGS | CACR | NROR | SNRR | TRAN | CLABE | VOSTRO | IBAN | BBAN. UTA's commercial accounts are DDA (Demand Deposit Account); my earlier spec's DDA | VAM was wrong (VAM is not in this enum).
About the OAS example name "Wallet Withdrawal": JPM's OAS labels this example
RealTimeUSRTPWalletWithdrawals/"RTP - Wallet Withdrawals Initiation - US RTP", but the payload is an ordinary outbound RTP credit-push to a third-party account — exactly the shape UTA uses to pay an athlete or loanout. Two carryovers in JPM's product-marketing taxonomy make the name misleading: (1) "Wallet" is product-line carryover from the separate JPM Wallet holding-account product (§12 #20 — closed; JPM Wallet is not required for UTA). The debtor account in this example (123456789) is a plain DDA, not a Wallet account. (2) "Withdrawal" is the debtor-account-side framing of a credit-push — funds are withdrawn from the debtor and credited to the creditor. Same operation UTA naturally describes as "paying the athlete." No special enrollment, no different field shape, no different endpoint.
OAS example — US RTP outbound credit-push initiation (from RealTimeUSRTPWalletWithdrawals — the misleading name notwithstanding):
{
"requestedExecutionDate": "2025-02-07",
"paymentIdentifiers": { "endToEndId": "USRTPWALLETTEST" },
"transferType": "CREDIT",
"value": { "currency": "USD", "amount": "122.08" },
"paymentType": "RTP",
"debtor": {
"name": "John Doe",
"account": { "accountNumber": "123456789" }
},
"debtorAgent": {
"financialInstitutionIds": [{ "id": "021000021", "idType": "USABA" }]
},
"creditor": {
"account": { "accountNumber": "98765432100" },
"name": "Jane Doe"
},
"creditorAgent": {
"financialInstitutionIds": [{ "id": "063100277", "idType": "USABA" }]
}
}Optional fields used by sub-ledger:
additionalParties.ultimateDebtorandultimateCreditorremittanceInformation.unstructuredInformation[].text(array per OAS, each item with.text)remittanceInformation.structuredInformation[].creditReference.reference(max 140)paymentPurpose.categoryPurpose.proprietary(e.g.,SALA,CXBSNS,ACCTVERIFY)paymentIdentifiers.otherPaymentReferences.uetr(36-char SWIFT GPI tracking; primarily for wires)
Note: instructionForDebtorAgent is not in the OAS Payment schema — do not attempt to use it. FX context lives on fxInformation (see §7.6).
Optional fields used by sub-ledger:
additionalParties.ultimateDebtorandultimateCreditorremittanceInformation.unstructuredInformation.text(70–140 chars)remittanceInformation.structuredInformation[].creditReference.reference(max 140)paymentPurpose.categoryPurpose.proprietary(e.g.,SALA,CXBSNS)
Note: instructionForDebtorAgent is not documented for RTP — do not attempt to use it on RTP payments.
Status lifecycle:
paymentStatus:RECEIVED,ACCEPTED,PROCESSING,CANCELED,REJECTED,COMPLETED,RETURNED- Terminal:
COMPLETED,REJECTED,RETURNED,CANCELED. Polling MUST stop on terminal. - Non-terminal:
RECEIVED,ACCEPTED,PROCESSING
Idempotency:
Idempotency-Keyreused with same payload → returns prior responseIdempotency-Keyreused with different payload → error10106(HTTP 422)- Concurrent same key → error
10107(HTTP 409) — wait + poll status; do not retry immediately
Optional reliability uplift: before initiating RTP, optionally call PACMan (§10) to check partner-bank availability and pre-empt rejections.
Source basis: RTP overview · RTP payment parameters · RTP resources (rails, limits, response types) · Initiate a Real-Time Payment request how-to · Retrieve transaction status how-to · Initiate a return request how-to · Return status how-to · GP2 error codes.
7.3 ACH — Credit Disbursements
Status: Cleared | Channel: REST POST + Webhook callback | Sequence: Wave 1
Purpose: Standard NACHA credit-push disbursements — UTA's primary use case is settlement payouts to athletes and loanouts (per the volume analysis: ~236/month to 357 distinct CustJob entities). UTA does not have a traditional Accounts-Payable function on the Klutch JPM accounts; outbound ACH on this integration is payout, not vendor payment.
OAS verified against Global Payments v2.4.7 OpenAPI 3.0.1 spec on 2026-05-08.
| Attribute | Value |
|---|---|
| Initiate / status endpoints | Same as RTP: POST /payment/v2/payments, GET /payment/v2/payments/{paymentId} |
paymentType | "ACH" |
transferType | "CREDIT" |
paymentTypeInformation.serviceLevelCode | "NURG" (Non-Urgent — default for ACH per OAS example). Other valid ServiceLevelCode enum values: SEPA, SDVA (Same Day Value), URNS (Urgent Net Settlement), BKTR (Book), URGP (Urgent) |
paymentTypeInformation.localInstrumentCode.code | NACHA SEC code. Mandatory 3-char for US ACH. Full OAS enum: SDCL, IN, CCD, IAT, PPD, CTX, CIE, ARC, POP, RCK, BOC, POS, WEB, TEL. Most common for UTA's flows: CCD (Corporate Credit/Debit — example uses this), PPD (Pre-arranged Payment), CTX (Corporate Trade Exchange) |
endToEndId | OAS EndToEndId schema: min 1, max 128 chars, no character pattern restriction in the schema (OAS example USACHCRTEST is 11 alphanumeric chars). The 1-15 char "alphanumeric only" claim in earlier spec drafts was from developer-portal docs that may reflect rail-specific NACHA file format constraints, not the API schema. [CONFIRM with JPM] the rail-specific max for US ACH in CAT |
endToEndId reuse window | 60 days for ACH (per developer-portal docs) |
requestedExecutionDate | OAS format: date, YYYY-MM-DD, current or future (per Payment schema description). US ACH allows future dating per dev-portal docs |
value.currency | "USD" (or "CLP" for Chile). Iso4217CurrencyCode enum is wider but US ACH is USD-only |
value.amount | STRING with decimal, e.g. "1.00" (verified against OAS AchUSCreditTransfer example) — NOT a number |
| Limits | USD 1M same-day / USD 99,999,999.99 next/2nd-day (per dev-portal docs) |
| Hours / cutoffs (US) | Same-day ACH: 13:10 ET prefunded / 14:10 ET non-prefunded. Next-day ACH: 21:10 ET prefunded / 22:55 ET non-prefunded |
| No client-initiated return endpoint | RDFI returns surface as a status update (paymentStatus = RETURNED) on the original payment. OAS confirms only Brazil PIX returns are exemplified |
| Cancellation | Possible on SCHEDULED (future-dated) — mechanism [CONFIRM with JPM] |
Additional fields used by US ACH (from OAS AchUSCreditTransfer example):
debtor.account.accountNumber(string, US ACH non-IAT max 17 chars per OASAccountIddescription; US ACH IAT max 35 chars)debtor.account.companyId(string, 10 chars — NACHA Company ID — required for US ACH origination, identifies the originator on the NACHA file)debtor.name,debtor.postalAddress(country, buildingNumber, streetName, city, postalCode, countrySubDivision)debtorAgent.financialInstitutionIds[]withid= 9-digit ABA,idType = "USABA"creditor.name,creditor.account.accountNumber,creditor.account.accountCurrency(e.g.,"USD")creditor.partyId.individualIds[]withindividualId(e.g., taxpayer ID — used for IAT and per-rail compliance)creditorAgent.financialInstitutionIds[](same shape as debtorAgent)creditor.postalAddress(full address)
Sub-ledger / reconciliation fields:
remittanceInformation.unstructuredInformation[]— array per OAS (each item withtext); example usestext: "MISC services INV#09900". For US ACH the NACHA file format constrains this to ~80 chars per line; UTA's serializer must respect thatpaymentPurpose.categoryPurpose.proprietary(e.g.,ACCTVERIFYin OAS example;PAYROLL,PURCHASEalso used)taxInformation.type(e.g.,TAX_PAYMENT)paymentIdentifiers.otherPaymentReferences.relatedReferenceId— per OAS, "applicable for ACH and WIRES only"
OAS example — US ACH Credit Transfer (verbatim from AchUSCreditTransfer):
{
"requestedExecutionDate": "2025-01-10",
"paymentIdentifiers": { "endToEndId": "USACHCRTEST" },
"value": { "currency": "USD", "amount": "1.00" },
"transferType": "CREDIT",
"paymentType": "ACH",
"paymentTypeInformation": {
"serviceLevelCode": "NURG",
"localInstrumentCode": { "code": "CCD" }
},
"debtor": {
"account": { "accountNumber": "12345678910", "companyId": "1115559990" },
"name": "John Doe",
"postalAddress": { "country": "US", "buildingNumber": "000", "streetName": "Smoking Lane", "city": "Chicago", "postalCode": "60603", "countrySubDivision": "IL" }
},
"debtorAgent": {
"name": "JP Morgan Chase",
"financialInstitutionIds": [{ "id": "021000021", "idType": "USABA" }],
"postalAddress": { "country": "US" }
},
"creditor": {
"name": "Jane Doe",
"account": { "accountNumber": "987654321", "accountCurrency": "USD" },
"postalAddress": { /* ... */ "country": "US" },
"partyId": { "individualIds": [{ "individualId": "4444444" }] }
},
"creditorAgent": {
"name": "JP Morgan Chase",
"financialInstitutionIds": [{ "id": "021000021", "idType": "USABA" }],
"postalAddress": { "country": "US" }
},
"remittanceInformation": {
"unstructuredInformation": [{ "text": "MISC services INV#09900" }]
},
"paymentPurpose": { "categoryPurpose": { "proprietary": "ACCTVERIFY" } },
"taxInformation": { "type": "TAX_PAYMENT" }
}Status lifecycle: Use the canonical PaymentStatus/PaymentSubStatus enums from §6.6 (7 paymentStatus values × 17 paymentSubStatus values). Terminal: COMPLETED (sub: COMPLETED_BY_JPM), REJECTED, RETURNED.
Source basis: GP2 OpenAPI Specification v2.4.7 — AchUSCreditTransfer example, Payment, PaymentTypeInformation, LocalInstrument schemas · ACH overview · ACH payment parameters (credit) · ACH resources (limits, cutoffs).
7.4 ACH — Authorized Debit Pulls
Status: Cleared | Channel: REST POST + Webhook callback | Sequence: Wave 2
Purpose: UTA pulls funds from a third-party account where UTA holds a valid NACHA authorization (e.g., recurring producer settlements). Authorization capture / storage / R-code handling are UTA's responsibility outside JPM.
OAS verified against Global Payments v2.4.7 OpenAPI 3.0.1 spec on 2026-05-08 — AchUSDebitTransfer example.
| Attribute | Value |
|---|---|
paymentType | "ACH" |
transferType | "DEBIT" (the only routing difference vs. credit; Party blocks for debtor and creditor are also swapped — see example below) |
paymentTypeInformation.serviceLevelCode | "NURG" (OAS debit example uses this; same enum as credit) |
paymentTypeInformation.localInstrumentCode.code | Full enum same as §7.3 credit: SDCL, IN, CCD, IAT, PPD, CTX, CIE, ARC, POP, RCK, BOC, POS, WEB, TEL. Per NACHA rules, the SEC code selected dictates which authorization rules apply (e.g., PPD for consumer authorizations, CCD for corporate, WEB/TEL for internet/telephone authorizations). OAS debit example uses PPD |
endToEndId | Same as §7.3: OAS base schema max 128; rail-specific max [CONFIRM with JPM]. Reuse window 60 days (per dev-portal docs) |
value.amount | STRING with decimal, e.g., "3.00" (verified against AchUSDebitTransfer example) |
| Amount limits | USD 1,000,000 same-day; USD 99,999,999.99 next/2nd-day |
| Authorization (mandate) storage | UTA's responsibility — GP2 does not store mandates. UTA must retain the signed authorization per NACHA rules |
Important on debit semantics — debtor is the funding party, NOT UTA. For a debit pull, debtor is the third party whose account UTA is pulling from (the funding source), and creditor is UTA (the destination of the funds). This is the inverse of the credit case where debtor is UTA.
OAS example — US ACH Debit Pull (verbatim from AchUSDebitTransfer):
{
"requestedExecutionDate": "2025-07-10",
"paymentIdentifiers": { "endToEndId": "USACHDBTEST" },
"value": { "currency": "USD", "amount": "3.00" },
"transferType": "DEBIT",
"paymentType": "ACH",
"paymentTypeInformation": {
"serviceLevelCode": "NURG",
"localInstrumentCode": { "code": "PPD" }
},
"creditor": {
"account": { "accountNumber": "0616759257", "companyId": "1590925701" },
"name": "John Doe",
"postalAddress": { /* ... */ }
},
"creditorAgent": {
"name": "JP Morgan Chase",
"financialInstitutionIds": [{ "id": "021000021", "idType": "USABA" }],
"postalAddress": { "country": "US" }
},
"debtor": {
"name": "Jane Doe",
"account": { "accountNumber": "9876543210", "accountCurrency": "USD" },
"postalAddress": { /* ... */ }
},
"debtorAgent": {
"name": "JP morgan Chase",
"financialInstitutionIds": [{ "id": "021000021", "idType": "USABA" }],
"postalAddress": { "country": "US" }
},
"remittanceInformation": {
"unstructuredInformation": [{ "text": "Music services INV#09900" }]
},
"paymentPurpose": { "categoryPurpose": { "proprietary": "ACCTVERIFY" } },
"taxInformation": { "type": "TAX_PAYMENT" }
}All other fields and lifecycle behavior match §7.3.
Source basis: GP2 OpenAPI Specification v2.4.7 — AchUSDebitTransfer example, TransferType, LocalInstrument schemas · ACH payment parameters (debit) · ACH overview · Cliff direction post-2026-03 to expand ACH scope to debits.
7.5 Wire — Same-Currency (Domestic + Cross-Border Same-Currency)
Status: Cleared — sample request body confirmed by Jessica Jin 2026-05-12 | Channel: REST POST + Webhook callback | Sequence: Wave 2
Purpose: High-value same-currency wire credit transfers via Fedwire / CHIPS / SWIFT MT103 — for corporate customers like UTA, originated from UTA's Klutch operating account.
Product distinction — Wire Payments 2 API is NOT UTA's path. JPM publishes a separate product called "Wire Payments" / "Wire Payments 2 API" v2.0.5 (OAS at Playbook/Wire Payments 2 API 2.0.5.yaml). That product is for Financial Institutions (FI-to-FI wires, correspondent banking, cover payments via SWIFT MT103) — its OAS explicitly requires initiatingParty.id.organizationId.other.id: "BANK" and all examples are "US FI to FI." UTA is a corporate, not an FI; UTA's wires go through GP2 (POST /payment/v2/payments with paymentType: "WIRE"), not through Wire Payments 2 API.
US Wire request body — sample confirmed by Jessica Jin 2026-05-12. GP2 v2.4.7 OAS lists WIRE in the paymentType enum and exposes paymentTypeInformation.paymentContext (FI | CUSTOMER) for wire flows but contains no verbatim US Wire request example (RTP and ACH samples only). Jessica's 2026-05-12 reply provided the canonical body below — closes §12 #23.
Endpoint + headers:
POST https://api-mock.payments.jpmorgan.com/payment/v2/payments
Accept: application/json
Content-Type: application/json
Idempotency-Key: <UUID>
Request-Id: <UUID>Verbatim sample request body (US same-currency Fedwire, USD 1.00 — Jessica Jin 2026-05-12):
{
"requestedExecutionDate": "2026-01-14",
"paymentIdentifiers": { "endToEndId": "US_WIRETEST_123" },
"value": { "currency": "USD", "amount": "1" },
"transferType": "CREDIT",
"paymentType": "WIRE",
"debtor": {
"account": { "accountNumber": "12311871", "accountCurrency": "USD" }
},
"debtorAgent": {
"financialInstitutionIds": [
{ "id": "021000021", "idType": "USABA" },
{ "id": "CHASUS33", "idType": "BIC" }
],
"postalAddress": { "country": "US" }
},
"creditor": {
"name": "JPMCHASE",
"account": { "accountNumber": "123456789", "accountCurrency": "USD" },
"postalAddress": { "country": "US" }
},
"creditorAgent": {
"financialInstitutionIds": [
{ "id": "021000021", "idType": "USABA" }
]
},
"paymentPurpose": { "purpose": { "code": "GDDS" } },
"paymentTypeInformation": { "paymentContext": "CUSTOMER" },
"remittanceInformation": {
"unstructuredInformation": [
{ "text": "Payment for Macbook batteries Receipt #AXF23-LGG" }
]
}
}Key shape notes from Jessica's sample:
debtorAgent.financialInstitutionIds[]accepts multiple entries — Jessica's sample populates both USABA (021000021) and BIC (CHASUS33) for the debtor agent. UTA should provide both routing forms when known.creditor.nameis populated even for intra-JPMC routing ("JPMCHASE"in the example).paymentTypeInformation.paymentContext: "CUSTOMER"is the value for corporate-originated wires (UTA's case);"FI"is for FI-to-FI (not UTA).paymentPurpose.purpose.codeuses ISO 20022 codes — Jessica's example usesGDDS(Goods); other ISO codes apply per UTA's payment purpose.remittanceInformation.unstructuredInformationoutbound shape is[{text: "..."}](array of objects withtextfield). This is distinct from §6.5 Payment Receipts inbound which deliversunstructuredInformationasarray of strings. UTA's serializer + parser must handle both shapes by direction.
| Attribute | Value |
|---|---|
| Endpoint | POST /payment/v2/payments |
paymentType | "WIRE" |
transferType | "CREDIT" |
paymentTypeInformation.paymentContext | "CUSTOMER" (UTA-originated) or "FI" (financial-institution-initiated; not UTA's case) |
endToEndId | OAS base schema max 128 chars; [CONFIRM with JPM] the rail-specific Fedwire/CHIPS validator length (industry practice is 16 chars in the IMAD/OMAD format). Reuse window 60 days per dev-portal docs |
value.amount | STRING with decimal, e.g., "50000.00" — same format as ACH/RTP per OAS AmountValue schema |
paymentIdentifiers.otherPaymentReferences.uetr | Optional but recommended for wires — 36-char SWIFT GPI tracking reference (per OAS OtherPaymentReferences.uetr). Lets UTA join GP2 status events to SWIFT GPI tracker entries |
paymentIdentifiers.otherPaymentReferences.relatedReferenceId | Optional; per OAS "applicable for ACH and WIRES only" |
| Limits | Fed/CHIPS: USD 9.9 billion max per wire. Book transfer (intra-JPMC): USD 25 billion max (per dev-portal docs) |
| Cutoffs | Fedwire: 15:00–18:15 ET (varies by transaction type). CHIPS: 17:30 ET straight-through; 17:00 ET operator repair. SWIFT: 16:30 ET across USD channels (per dev-portal docs) |
| Returns / cancellations | Wires are irrevocable. No /returns endpoint. Recall must be bilateral with JPMC ops |
Required fields: paymentType = "WIRE", transferType = "CREDIT", paymentTypeInformation.paymentContext = "CUSTOMER", requestedExecutionDate, paymentIdentifiers.endToEndId, value.currency, value.amount, debtorAgent.financialInstitutionIds[].id (BIC or USABA), idType ("BIC" or "USABA"), creditorAgent.financialInstitutionIds[].id and idType.
Sub-ledger / reconciliation fields referenced in sample bodies but not enumerated in the parameters page: instructionForDebtorAgent, instructionForCreditorAgent, remittanceInformation (structured + unstructured), ultimateDebtor, ultimateCreditor, intermediaryAgent, chargeBearer, paymentPurpose. Action: pull the full GP2 OAS for the wire schema before implementation — the markdown parameters page is incomplete.
Status lifecycle: paymentStatus: ACCEPTED (sub: ACCEPTED), COMPLETED (sub: COMPLETED_BY_JPM), REJECTED (sub: REJECTED), RETURNED (sub: RETURNED). Terminal: COMPLETED, REJECTED, RETURNED.
Source basis: Same-Currency Wire overview · Wire payment parameters · Wire resources (limits, cutoffs) · Initiate a wire payment how-to · Get wire status how-to · GP2 OpenAPI Spec.
7.5.1 Intra-JPMC Book Transfer
For DDA-to-DDA transfers between two JPM accounts (e.g., funding a Klutch sub-account, treasury sweeps within JPM, prefunding a check-printing fund), use the same POST /payment/v2/payments endpoint with paymentType: WIRE. JPM auto-detects intra-bank routing when both debtorAgent.financialInstitutionIds[].id and creditorAgent.financialInstitutionIds[].id resolve to a JPM BIC (e.g., CHASUS33); no separate paymentType value exists for book transfer (the GP2 OAS paymentType enum is RTP | WIRE | ACH | CARD | VENMO | PAYPAL | BLOCKCHAIN | INTERAC | ZELLE | DEFAULT — no BOOK_TRANSFER).
| Attribute | Value |
|---|---|
| Endpoint | POST /payment/v2/payments (same as §7.5) |
paymentType | "WIRE" |
| Detection rule | JPM auto-routes as a Book Wire when both debtor and creditor agents resolve to a JPM BIC. No client-side flag per dev-portal narrative — [CONFIRM in CAT] if JPM's validator expects an explicit indicator |
| Settlement | Same-day, intra-bank — does not transit Fedwire or CHIPS |
| Limit | USD 25 billion per transfer (vs. USD 9.9 billion for Fed/CHIPS-routed wires) |
| Fee | Significantly lower than Fedwire/CHIPS (Book Wire rate per dev-portal docs); exact fee per UTA's JPM treasury services pricing |
| GL posting | Two offsetting Journal Entries — debit source account, credit destination account, using JPM's response paymentId as the memo. Never post as a single net entry (mirrors CNB DEC-010 for cross-bank consistency) |
| Status / callbacks | Same as §7.5 wire — GP2 Callbacks (§6.6) for status; polling fallback via GET /payment/v2/payments/{paymentId} |
| Use cases for UTA | (a) Funding a sub-account for check-printing, (b) treasury moves between Klutch sub-accounts, (c) FX wire prefunding, (d) any internal allocation that doesn't need to leave JPM |
Sample request — USD 10,000 book transfer (Klutch operating → check-printing fund):
{
"paymentType": "WIRE",
"transferType": "CREDIT",
"paymentTypeInformation": { "paymentContext": "CUSTOMER" },
"requestedExecutionDate": "2026-10-15",
"paymentIdentifiers": { "endToEndId": "UTA-BT-2026-10-15-001" },
"value": { "currency": "USD", "amount": "10000.00" },
"debtor": { /* UTA Klutch operating account */ },
"debtorAgent": { "financialInstitutionIds": [{ "id": "CHASUS33", "idType": "BIC" }] },
"creditor": { /* UTA Klutch check-printing fund */ },
"creditorAgent": { "financialInstitutionIds": [{ "id": "CHASUS33", "idType": "BIC" }] }
}Source basis: Wire resources (limits, cutoffs) (Book Wire limit + intra-JPMC fee guidance) · GP2 OAS v2.4.7 (paymentType enum — confirms no separate BOOK_TRANSFER value).
7.6 Wire — Cross-Currency / FX
Status: Cleared — end-to-end flow documented | Channel: REST POST (RFQ Quote → RFQ Trade → GP2 Wire) | Sequence: Wave 3
Purpose: International wire with FX-locked GL posting amount, so the USD debit amount is fixed on UTA's books before the wire executes.
7.6.1 The end-to-end flow
┌───────────────────────────────────────────────────────────────────┐
│ STEP 1 — RFQ Quote (real-time pricing) │
│ POST /tsapi/v1/quotes → returns jpmQuoteId (R… 30-char) │
└───────────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────────┐
│ STEP 2 — RFQ Trade (lock the rate) │
│ POST /tsapi/v1/trades → returns jpmContractId (T… 30-char) │
│ Locked rate; UTA's GL amount is now committed │
└───────────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────────┐
│ STEP 3 — GP2 Wire Payment │
│ POST /payment/v2/payments with: │
│ { │
│ "paymentType": "WIRE", │
│ "transferType": "CREDIT", │
│ "value": { "currency": <foreign>, "amount": <foreign-amt> }, │
│ "debtor": { ... UTA USD account ... }, │
│ "creditor": { ... beneficiary ... }, │
│ "instructionForDebtorAgent": "/FXA/<jpmContractId>" │
│ } │
└───────────────────────────────────────────────────────────────────┘
│
▼
Wire executes at the locked rate.
GL variance: zero.Optional Step 0: UTA can pre-fetch published rates via the FX Rate Sheet API (§7.6.3 below) for non-real-time pricing scenarios. Returns Rate IDs (R…) that can be used in §7.6.4 in place of running a fresh RFQ Quote, subject to the sheet's transaction-size bounds and expiry.
Optional Step 4: Cancel a booked trade if no wire is initiated yet — POST /tsapi/v1/trades/cancel with clientTradeId or jpmContractId.
7.6.2 RFQ Quote — Step 1 (real-time pricing)
Authoritative spec:
Playbook/Request for Quote API 1.0.1.yaml
| Attribute | Value |
|---|---|
| Endpoint | POST /tsapi/v1/quotes (operationId request-quote) |
| Base URLs | Production mTLS: https://apigateway.jpmorgan.com/tsapi/v1 · CAT mTLS: https://apigatewayqaf.jpmorgan.com/tsapi/v1 |
| Auth model | mTLS only (no OAuth servers declared in the RFQ OAS) · Digital Signature Required on all 3 RFQ operations (per OAS endpoint descriptions) |
| Batching | Up to 50 quote requests in a single API call (ERR_1324 if exceeded) |
Request body shape:
{
"data": {
"accountId": "796706786", // UTA's debit account (must match clientSellCcy)
"clientSellCcy": "USD", // ISO 4217, 3 chars; must be account currency
"quoteType": "EXECUTABLE", // or "INDICATIVE"
"quote": [
{
"clientRequestId": "CBQID20200618120921052", // UTA-supplied, max 26 chars, unique
"clientBuyCcy": "CAD", // ISO 4217 target currency
"buyCcyAmt": 0.24, // OR sellCcyAmt — exactly one of the two
"paymentDetail": {
"paymentMethod": "WIRE" // or DRAFT or ACH
}
}
]
}
}Required for ACH paymentMethod (not for WIRE): beneficiaryType, senderType, beneBankCountryCode, recipientAccountUri, senderAccountUri, bankCode (per OAS).
Response shape (key fields):
{
"_metadata": {
"msgType": "quoteResponse",
"sendingTimeUTC": "20200618-12:09:21Z"
},
"data": {
"accountId": "796706786",
"clientSellCcy": "USD",
"quoteType": "EXECUTABLE",
"quote": [{
"clientRequestId": "CBQID20200618120921052",
"status": "ACCEPTED", // or REJECTED
"jpmQuoteId": "R3CC77CEAE64623BE9706A5A807207", // ← THE RATE ID
"clientBuyCcy": "CAD",
"buyCcyAmt": 0.24,
"sellCcyAmt": 0.31, // implied USD debit
"fxValueDate": "20200618",
"expirationTimeUTC": "20200618-12:09:41Z", // ← Quote expiry
"clientRate": 1.3134, // ← Quote rate
"baseCcy": "USD",
"fromBuyCcyToSellCcy": "Divide"
}]
}
}jpmQuoteId format: Always 30 chars, pattern R[A-Za-z0-9]{29} per OAS rateReferenceId schema.
Error catalog (selected; full list in OAS): GCA-021 accountId required · GCA-119 clientSellCcy required · ERR_1304 invalid clientSellCcy · ERR_1303 invalid clientBuyCcy · ERR_1305 two identical currencies · ERR_1308 invalid clientRequestId · ERR_1311 invalid paymentMethod · ERR_1318 missing amount · ERR_1319 two amounts provided · ERR_1324 exceeded 50 quote requests · ERR_1325 restricted currency · ERR_1326 ERISA account · ERR_1329 outside branch trading hours · ERR_1330 outside currency trading hours · ERR_1335 amount too large · ERR_1369 outside onshore CNY trading hours.
7.6.3 RFQ Trade — Step 2 (lock the rate)
| Attribute | Value |
|---|---|
| Endpoint | POST /tsapi/v1/trades (operationId book-trades) |
| Auth + base URLs | Same as Quote (mTLS only, Digital Signature Required) |
| Batching | Up to 50 trade requests per call (ERR_2529) |
Request body shape:
{
"data": {
"accountId": "719532764",
"clientSellCcy": "USD",
"trade": [{
"clientTradeId": "CBTID20200618120925899", // UTA-supplied, max 26 chars
"jpmQuoteId": "R3CC77CEAE64623BE9706A5A807207", // ← from Step 1 Quote
"clientBuyCcy": "CAD",
"clientRate": 1.3134, // ← must match quote response
"fxValueDate": "20200618", // ← must match quote response
"buyCcyAmt": 0.1, // OR sellCcyAmt
"paymentDetail": {
"paymentMethod": "WIRE" // ← must match quote
}
}]
}
}Critical: every field on the trade request must match what JPM returned on the quote (currency, rate, value date, payment method, etc.). Mismatch errors are numerous: ERR_2553-ERR_2562 catch the various dimensions.
Response shape:
{
"_metadata": { "msgType": "tradeResponse", "sendingTimeUTC": "..." },
"data": {
"accountId": "719532764",
"clientSellCcy": "USD",
"trade": [{
"clientTradeId": "CBTID20200618120925899",
"status": "ACCEPTED", // or REJECTED
"jpmContractId": "T178C681EB1A458B802AE896671925", // ← THE CONTRACT ID (locked rate)
"jpmQuoteId": "R3CC77CEAE64623BE9706A5A807207",
...
}]
}
}jpmContractId format: Always 30 chars, pattern T[A-Za-z0-9]{29} per OAS.
Critical error to avoid: ERR_2551 — "Trade request received on an indicative quote." Only EXECUTABLE quotes can be traded; INDICATIVE quotes are informational only. UTA must always request quoteType: "EXECUTABLE" at the Quote step for production wires.
7.6.4 GP2 Wire Payment with locked Contract ID — Step 3
| Identifier type | Prefix | Source | Usage |
|---|---|---|---|
| Rate ID | R (30 chars) | RFQ Quote response (jpmQuoteId) or FX Rate Sheet response (rateId) | Acceptable but not recommended for production wires — represents an unbooked quote |
| Contract ID | T (30 chars) | RFQ Trade response (jpmContractId) | Recommended for UTA — locked rate; GL variance zero |
JSON example for the wire Payment body (verbatim per Jessica):
"instructionForDebtorAgent": "/FXA/T178C681EB1A458B802AE896671925"UTA standard: Always use the Contract ID (T… prefix) in instructionForDebtorAgent, sourced from a completed Step 2 RFQ Trade. Never use a Rate ID directly in production wires.
Note on GP2 OAS fxInformation field — alternative path, NOT canonical: The GP2 OAS v2.4.7 includes a Payment.fxInformation object with rateId / contractId fields. An earlier (2026-05-08) draft of this spec elevated fxInformation.contractId to canonical based on OAS schema inspection. Jessica Jin's authoritative March 3 response establishes that the production-canonical pattern is instructionForDebtorAgent: "/FXA/<id>", not fxInformation.contractId. The OAS fxInformation field may document an alternative or future path; treat it as informational. (Lesson: customer-specific Implementation Manager guidance trumps public OAS schema interpretation — see Bank/lessons-learned.md.)
7.6.5 RFQ Trade Cancellation — Step 4 (optional)
| Attribute | Value |
|---|---|
| Endpoint | POST /tsapi/v1/trades/cancel (operationId cancel-trade) |
| Use case | UTA booked a trade but the downstream wire is no longer happening (e.g., payee bounced pre-flight validation) |
| Request body | `{ data: { accountId, trade: [{ clientTradeId |
| Key error | ERR_3129 — "Cancellation request received for a trade where the payment has already been submitted." Cancellation is only valid before the GP2 wire is initiated |
7.6.6 FX Rate Sheet API — alternative rate source (CNB §5.6 indicative rate file replacement)
Authoritative spec:
Playbook/FX Rate Sheet API 1.0.2.yaml
Purpose: Pull published indicative + executable FX rates for UTA's account on a periodic schedule, without running a per-transaction RFQ Quote. This is the JPM equivalent of CNB §5.6's Exchange Rate File — direct functional replacement.
| Attribute | Value |
|---|---|
| Endpoint | GET /tsapi/v1/accounts/{accountId}/ratesheets/current (operationId getCurrentRatesheet) |
| Base URLs | Production OAuth: https://openbanking.jpmorgan.com/tsapi/v1 · Production mTLS: https://apigateway.jpmorgan.com/tsapi/v1 · CAT OAuth: https://openbankinguat.jpmorgan.com/tsapi/v1 |
| Auth model | mTLS or OAuth (both declared in OAS — unlike RFQ which is mTLS-only) |
| Path params | accountId (UTA's account; same value as RFQ accountId field) |
| Query params | customerDepartment[] — optional array of LOB names (e.g., ["E-commerce Dept", "Payments Dept"]); max 100 items, each 1-50 chars. Used when JPM has set up department-specific rate tiers for UTA (requires upfront TSFX Product configuration per OAS) |
Response shape (key fields):
{
"_metadata": {
"sendingTime": "20180903-15:01:02Z",
"clientRequestId": "51a190dc-940d-43d1-a0b9-5fabd5f2e640",
"disclaimer": "..." // Treasury Services FX disclaimer
},
"data": {
"accountId": "123456789",
"ratesheetId": "d51176f6-...",
"publicationId": "e51176f6-...",
"publicationTime": "2018-09-03T15:01:02Z",
"expiry": "2018-09-03T15:01:02Z", // ← rates expire after this
"thresholdAmount": 1000000, // ← rates valid up to this amount
"thresholdCcy": "USD",
"customerDepartment": [{
"name": "Example E-commerce Dept",
"currencyPairs": [{
"clientBuyCcy": "BRL",
"clientSellCcy": "USD",
"onshoreOffshore": "Onshore", // or Offshore
"baseCcy": "USD",
"fromBuyCcyToSellCcy": "Divide", // or Multiply
"rates": [{
"rateId": "R1234567-8901-2345-6789-012345678901", // ← R-prefix, same format as RFQ
"clientRate": 3.31645,
"rateType": "EXECUTABLE", // or INDICATIVE
"paymentMethod": "ACH", // WIRE_DRAFT_BOOK | ACH | WALLET | CARD
"beneficiaryType": "BUSINESS",
"minTransactionSize": 100,
"maxTransactionSize": 10000,
"minMaxTransactionSizeCcy": "USD"
}]
}]
}]
}
}Key concepts:
rateType: EXECUTABLE— UTA can use thisrateIddirectly in a wire body (/FXA/<rateId>) without running RFQ Trade, provided the transaction amount falls withinminTransactionSize/maxTransactionSizeand the wire executes beforeexpiry. Risk: less price-locked than a Contract ID since it's based on a pre-published rate, not a real-time confirmationrateType: INDICATIVE— Informational only; cannot be used to execute a wire. Useful for UI display ("show payer estimated FX rate before they commit")thresholdAmount— Hard cap above which the rate sheet's rates don't apply at all (UTA would need RFQ instead)
UTA design choice between RFQ and Rate Sheet:
| Use case | Recommended path |
|---|---|
| Production cross-currency wires with GL assurance | RFQ Quote → RFQ Trade → use Contract ID (§7.6.2 → §7.6.3 → §7.6.4) |
| UI display of estimated rates pre-commitment | Rate Sheet, rateType: INDICATIVE |
| Repetitive small-value FX flows within rate sheet bounds | Rate Sheet, rateType: EXECUTABLE — acceptable if UTA accepts the rate-sheet-bounded GL risk |
| Bulk pricing context for FX dashboard | Rate Sheet (pulled periodically; covers all currency pairs UTA has set up) |
For UTA's Klutch use case (inbound AR cash-application + outbound settlement wires to athletes/loanouts): the RFQ flow (§7.6.2 + §7.6.3) is the right path for FX wires. The Rate Sheet API is documented here for completeness and future use.
Error codes (FX Rate Sheet, verbatim from OAS):
| Code | Meaning |
|---|---|
GCA-001/GCA-003 | Unauthorized Access |
GCA-010 | Account not found |
GCA-099 | System unavailable |
ERR_1201 | Invalid Rate Sheet Request, invalid accountId |
ERR_1203 | All rates expired, unable to find valid rates for request |
ERR_1204 | Internal error, resend new Rate Sheet Request |
7.6.7 Out-of-scope: Xpedite Remit FX Rate Sheet
JPM also publishes an Xpedite Remit FX Rate Sheet API v1.0.1 (Playbook/Xpedite Remit FX Rate Sheet API 1.0.1.yaml) — POST /tsapi/v1/xR/fxrates. This is a separate Xpedite Remit product (consumer cross-border remittance), not the corporate treasury FX flow UTA uses. NOT IN SCOPE for UTA's Klutch corporate wires. Retain the OAS for awareness; no spec coverage needed.
7.6.8 Updated open items for §7.6
| Item | Status |
|---|---|
| RFQ Quote / Trade endpoint URLs | Closed — see §7.6.2, §7.6.3 (RFQ API v1.0.1 OAS) |
Wire body field name (/FXA/) | Closed — Jessica Jin 2026-03-03; see §7.6.4 |
| Indicative-rate file equivalent | Closed — FX Rate Sheet API v1.0.2 (see §7.6.6); replaces CNB §5.6 |
Sample US Wire FX Payment body | Still Confirm-Blocked. The wire-body field is documented; the complete US wire request body (with full debtor/creditor shapes for a USD-denominated Fedwire) is not in any OAS we have. [ACTION — JPM Integration Manager / Jessica Jin] provide a verified US wire FX sample, or this resolves naturally in CAT |
jpmContractId lifecycle / expiry | OAS implies no expiry on a booked trade, but the documented expirationTimeUTC is on the Quote (not the Trade). [CONFIRM with JPM] whether a booked Contract ID has its own expiration window separate from the wire's requestedExecutionDate |
| Trading hours / currency cutoffs | OAS error codes (ERR_1329, ERR_1330, ERR_1369) reference branch and currency trading hours but don't enumerate them. [CONFIRM with JPM] — likely a JPM Markets reference document |
Status update (rolled forward):
- v3.0 initial draft (2026-05-08):
Confirm-Blocked — entire flow. Speculative path via JPM Wallet FX-Wire. - 2026-05-08 OAS-based correction: incorrectly elevated
fxInformation.contractIdas canonical. - 2026-05-11 first revert: restored Jessica's
/FXA/pattern as canonical (wire body); RFQ upstream still pending. - 2026-05-11 second update (this revision): RFQ API v1.0.1 OAS + FX Rate Sheet API v1.0.2 OAS downloaded. End-to-end flow now Cleared. All major architectural pieces in place. Remaining open items are implementation-level (US wire sample body, Contract ID lifecycle, trading hours catalog) — answerable in CAT.
Source basis: Request for Quote API v1.0.1 OAS — authoritative for upstream RFQ · FX Rate Sheet API v1.0.2 OAS — authoritative for published rates · [Jessica Jin, JPM Implementation Manager, 2026-03-03 response] — authoritative for wire-body /FXA/ pattern · GP2 OAS fxInformation documented as alternative/future path (see Playbook/Global Payments 2.4.7.yaml).
7.7 Check Issuance & Print
Status: Cleared (full OAS verified) | Channel: REST POST (sync
/checks/issuances; async/checks/printswithGET /checks/prints/{id}poll) | Sequence: Wave 2
Purpose: Two flows — (a) Issuance registers a check that UTA prints in-house in the JPM Issuance/Positive Pay register; (b) Print submits a request to JPM to print and mail the check on UTA's behalf.
OAS verified against Checks API v2.1.1 OpenAPI 3.1.0 spec on 2026-05-12 — see Playbook/Checks API 2.1.1.yaml.
Base URLs (shared with §6.4 and §7.8):
- Production:
https://api.payments.jpmorgan.com/payable/v2 - Mock:
https://api-mock.payments.jpmorgan.com/payable/v2
7.7.1 Check Issuance — POST /checks/issuances
| Attribute | Value |
|---|---|
| Endpoint | POST /checks/issuances (single check) |
| Required fields | debtor (with accountNumber 2–17 digits + financialInstitutionId.{id, idType}), checkAmount.{amount, currency}, checkNumber (1–10 digits), issueDate (ISO 8601) |
| Optional fields | checkType enum, payees[] (1–3 items, each name 1–50 chars + priority 1–3), address (structured), additionalInformation[] (up to 10 items) |
checkType enum | CUSTOMER_CHECK (default for US/CA) | CERTIFIED_CUSTOMER_CHECK | BANK_CHECK | DRAFT | ELECTRONIC_DRAFT (NOT supported for Issuance or Cancellation) |
additionalInformation valueType enum | ESCHEATMENT_PRODUCT_CODE (max 6 chars, Issuance only) | ADDITIONAL_DATA (max 35 chars, Issuance only) |
clientReference | NOT supported on Issuance (per OAS note). UTA's internal reference must be tracked outside this API |
financialInstitution.idType enum | USABA | BIC | SORT_CODE | CLEARING_SYSTEM_ID |
| Multi-payee | Up to 3 payees with priority 1–3. Distinct from Print, which allows 2 payees max at 40-char names |
| Response (201) | id (UUID), issueDate, requestInvocationId |
Common errors (HTTP 400 with code 10001/10199) | "checkAmount/issueDate is mandatory", "Issue already exists for check", "Stop on file for check", "Cancel exists for check" |
Sample Issuance request — US, with escheatment data (verbatim shape from OAS):
{
"debtor": {
"accountNumber": "1234567890",
"financialInstitutionId": { "id": "123456789", "idType": "USABA" }
},
"checkNumber": "123456790",
"issueDate": "2026-10-01",
"checkAmount": { "currency": "USD", "amount": "500.00" },
"payees": [
{ "name": "John Doe", "priority": 1 },
{ "name": "ELITE CORP", "priority": 2 }
],
"address": {
"addressLines": ["123 Main St", "Suite 100"],
"city": "Tampa", "postalCode": "33607",
"countrySubDivision": "FL", "country": "US"
},
"additionalInformation": [
{ "valueType": "ESCHEATMENT_PRODUCT_CODE", "text": "123456" }
]
}7.7.2 Check Print — POST /checks/prints (async)
JPM prints and mails the check on UTA's behalf. Two templates available via printType:
| Template | printType value | Use case |
|---|---|---|
| US Cashier's Check / Draft | CASHIERS | High-trust draft drawn on bank funds. US-only. No bank holidays / weekends (EST). Bank assigns the checkNumber. clientReference is required and must be unique (1–10 chars) |
| US/CA Accounts Payable (6 column) (JPM template name; see note below) | ACCOUNTS_PAYABLE_6_COLUMN | Standard structured-remittance check template. issueDate ≤ 180 days future, no past dates. Defaults to current date if omitted |
About the
ACCOUNTS_PAYABLE_6_COLUMNtemplate name:ACCOUNTS_PAYABLE_6_COLUMNis JPM's literalprintTypeenum value — the name reflects the layout (6-column structured remittance withNET / DISCOUNT / GROSStriplets) that JPM originally built for AP use cases. UTA does not have a traditional Accounts-Payable function on the Klutch JPM accounts. UTA uses this template for athlete/loanout settlement-payout checks because the structured remittance layout fits Klutch's per-payment breakdown (e.g., gross deal amount, agency fee, net to athlete). The enum value must be sent verbatim to JPM regardless of UTA's internal label for the use case.
Shared required fields: debtor, checkAmount, payees (1–2 items, each name 1–40 chars + priority 1–2), address (structured), delivery.courier
Print-only delivery block:
| Field | Notes |
|---|---|
courier | e.g., USPS, FEDEX, UPS (1–5 chars per OAS) |
courierBillingAccountNumber | Read-only; assigned by JPM |
contactPhone | Required for non-USPS couriers |
specialHandling.deliveryAddress | Third-party delivery target (e.g., mailing service) |
specialHandling.companyName | Required if specialHandling present |
specialHandling.attention | "ATTN" line — person/department |
Cashier-specific required: clientReference (unique), remittance.{documents[], remitter}. Cashier amounts are constrained to type: NET_AMOUNT only.
ACCOUNTS_PAYABLE_6_COLUMN-specific required (JPM template name; UTA uses this template for settlement-payout checks, not AP): checkNumber, formCode (UTA-defined template code, 1–8 chars), remittance.documents[] structured with the NET_AMOUNT / DISCOUNT_AMOUNT / GROSS_AMOUNT triplet (all 3 required per document; NET = GROSS − DISCOUNT; up to 1000 documents per request). Optional memoLines[] (1 line max, 50 chars).
Response (202 async): id (print job UUID), issueDate, requestInvocationId. The export process is asynchronous — UTA must poll GET /checks/prints/{id} for status.
Polling — GET /checks/prints/{id} (results cached 5 min):
Response is CheckPrintDetailsResponse containing:
checkApprovalStatusenum:SUCCESS|REJECTED|ERROR|PENDING_CONFIRMATION|PENDING_APPROVALcheckPrintValidationStatusenum:SUCCESS|ERROR|PENDING_INVESTIGATION|PENDING_FUNDINGcheckPrintValidationErrors[](whenvalidationStatus = ERROR)exportStatus(boolean) —trueonce printed and exported
Sub-ledger gate: UTA's GL post-action on a Print request is gated on exportStatus: true AND checkApprovalStatus: SUCCESS AND checkPrintValidationStatus: SUCCESS. Any other combination is held for ops review.
Sample Print request — Cashier's with FedEx delivery:
{
"printType": "CASHIERS",
"clientReference": "UTA-CC-001",
"debtor": { "accountNumber": "987654321" },
"checkAmount": { "amount": "500.00", "currency": "USD" },
"payees": [{ "name": "John Doe", "priority": 1 }],
"address": {
"addressLines": ["456 Corporate Ave", "Floor 10"],
"city": "Chicago", "postalCode": "60642",
"countrySubDivision": "IL", "country": "US"
},
"delivery": { "courier": "FEDEX", "contactPhone": "312-555-6789" },
"remittance": {
"documents": [{
"description": ["Reimbursement"],
"documentDate": "2026-04-01",
"amounts": [{ "value": { "amount": "500.00", "currency": "USD" }, "type": "NET_AMOUNT" }]
}],
"remitter": "UTA Klutch"
}
}Source basis: Checks API v2.1.1 OAS — authoritative · Checks API overview · Checks Getting Started · Check Issuance & Cancellation overview · Issuance parameters · Issuance how-to · Check Print overview · Check Print parameters · Manage Check Print how-to · Checks API error codes.
Ops: JPM exposes GET /checks/health (unauthenticated, 30-sec server-side cached, returns {status: UP|DOWN, isReady, version, applicationName, statusUpdatedAt}) — useful for CAT smoke tests, pre-batch readiness checks, and ops monitoring (Datadog-style probes). Not part of UTA's per-transaction request flow.
7.8 Cancellation, Stop Payment & Revoke
Status: Cleared (full OAS verified) — all three verbs OAS-confirmed | Channel: REST POST | Sequence: Wave 2
Purpose: Three distinct lifecycle interventions on issued checks, each addressing a different stage:
| Verb | Endpoint | When | Effect |
|---|---|---|---|
| Cancellation | POST /checks/cancellations | Pre-clearance void — before the check has been presented/cleared | Removes the check from the issuance/Positive Pay register; reconciles outstanding record |
| Stop | POST /checks/stops | Post-issuance halt — after the check is in circulation but before it clears | Places a hold; if presented, JPM returns it. Time-bound — see expiration fields below |
| Revoke | POST /checks/stops/revoke | Lifts a prior Stop | Removes the stop; the check can be processed normally again |
OAS verified against Checks API v2.1.1 OpenAPI 3.1.0 spec on 2026-05-12 — closes §12 #6 with OAS-anchored paths and schemas.
7.8.1 Check Cancellation — POST /checks/cancellations
| Attribute | Value |
|---|---|
| Required fields | debtor, checkAmount, checkNumber, issueDate (same shape as Issuance) |
| Optional fields | checkType, payees[] (1–2 items only — third priority not used for Cancel), additionalInformation (without ESCHEATMENT_PRODUCT_CODE — Issuance-only) |
clientReference | NOT supported (same as Issuance) |
| Response (200) | id, issueDate, requestInvocationId |
Common error scenarios (HTTP 400 with code 10199) | "Cancel already exists", "Stop exists for check", "Check Has Already Cleared", "Cancel amount mismatch" |
Sample Cancellation request:
{
"debtor": {
"accountNumber": "1234567",
"financialInstitutionId": { "id": "123456789", "idType": "USABA" }
},
"checkNumber": "123456790",
"issueDate": "2026-10-01",
"checkAmount": { "currency": "USD", "amount": "500.00" },
"payees": [{ "name": "John Doe", "priority": 1 }]
}Operational rule: UTA's UI must call Cancel synchronously when a check is voided in the sub-ledger before mailing — the void action gates on a successful Cancel response. Once a check has been mailed, the equivalent action is Stop (§7.8.2), not Cancel.
7.8.2 Stop Payment — POST /checks/stops
| Attribute | Value |
|---|---|
| Required fields | debtor, type (SINGLE | RANGE), check (with checkNumber for SINGLE, or checkRange.{start, end} for RANGE), stopReason enum |
| Optional fields | checkAmount, payees[] (1–3 items). Not applicable to RANGE stops — checkAmount + payees are SINGLE-only |
| Range limit | Up to 1000 checks per range |
stopReason enum (15 values) | US: CHECKS_LOST, CHECKS_DAMAGED, WRONG_AMOUNT, WRONG_PAYEE, CHECKS_POST_DATED, CHECKS_ALTERED, CHECKS_FORGED, SIGNER_OR_MAKER, CHECKS_STOLEN, OTHER. CA: CLIENT_INSTRUCTION, CHEQUE_LOST, CHEQUE_EXPIRED, CHEQUE_DESTROYED, CHEQUE_STOLEN |
| Response (202) | id (StopPaymentId UUID), createdAt, requestInvocationId |
| Stop expiration semantics | A Stop is time-bound. Inquiry-returned additionalStopInfo: remainingTime (days remaining as ISO 8601 duration, decrements daily), originalTime (initial duration), expirationTime (years until full expiry), isRenewed (boolean — auto-renews on remainingTime: P0D reset). When both remainingTime and expirationTime reach 0, the Stop is no longer in effect |
Sample Stop — Single check, US:
{
"debtor": {
"accountNumber": "1234567890",
"financialInstitutionId": { "id": "123456789", "idType": "USABA" }
},
"type": "SINGLE",
"check": { "checkNumber": "123456666" },
"stopReason": "CHECKS_LOST"
}Sample Stop — Range, US:
{
"debtor": { "accountNumber": "1234567890", "financialInstitutionId": { "id": "123456789", "idType": "USABA" } },
"type": "RANGE",
"check": { "checkRange": { "start": "10020", "end": "10030" } },
"stopReason": "CHECKS_LOST"
}7.8.3 Revoke a Stop — POST /checks/stops/revoke
Two operation modes via the operationType discriminator:
operationType | Required fields | Use when |
|---|---|---|
ID | stopId (from the prior Stop response) | You have the stop's identifier — preferred path |
DETAIL | debtor, type, check — plus optional checkAmount, payees | The original stopId is unavailable (e.g., re-keyed from a paper record) |
Response (202): id, createdAt, requestInvocationId.
Sample Revoke by ID:
{ "operationType": "ID", "stopId": "n8a40v3r-3769-4o79-9z0l-ale1edc90389" }Sample Revoke by detail:
{
"operationType": "DETAIL",
"debtor": { "accountNumber": "1234567890", "financialInstitutionId": { "id": "123456789", "idType": "USABA" } },
"type": "SINGLE",
"check": { "checkNumber": "123456666" }
}7.8.4 Cross-cutting Checks API error codes (HTTP 400 schema, shared with §6.4 and §7.7)
| Code | Usage |
|---|---|
10001 | Mandatory field missing |
10002 / 10003 | Min/max length violation |
10100 / 10101 / 10102 | Min/max/range value violation |
10103 / 10104 / 10105 / 10199 | Bad format / bad value / unexpected field / other |
12000 | System error |
13000 | Uncategorized error |
14000 | Security failure (also drives HTTP 401) |
HTTP 503 returns ServiceUnavailable with same Error schema. HTTP 404 on revoke = stop-id not found. Health check available at GET /checks/health for connectivity testing (results cached 30 seconds).
Source basis: Checks API v2.1.1 OAS — authoritative · Stop & Revoke overview · Stop & Revoke parameters · Manage Check Stop how-to · Manage Check Revoke how-to · Checks API error codes.
7.9 Positive Pay Decisioning (Deferred — programmatic surface only)
Status: Phase 1 protection ACTIVE via §7.7 Issuance | Programmatic decisioning Deferred — JPM REST API not yet GA | Channel: TBD | Sequence: Phase 2
Critical framing — what is and isn't deferred: Positive Pay has two halves. UTA gets the protective half from day 1 — only the automation of decisioning is deferred.
| Half | Mechanism | Phase 1 status |
|---|---|---|
| Protection (Issuance register) | UTA registers every check via POST /checks/issuances (§7.7). JPM validates inbound presentments against this register. Any presentment that doesn't match an Issuance record is flagged as an exception. | ACTIVE in Phase 1. Wired up via §7.7. UTA gets fraud-protection benefit from the moment §7.7 goes live, regardless of how exceptions are decisioned. |
| Exception decisioning | When JPM flags an exception, UTA decides PAY or RETURN. | Manual in Phase 1; programmatic deferred to Phase 2 pending JPM REST API GA. |
Purpose of §7.9 specifically: documents the programmatic exception decisioning surface that lets UTA's system pull the exception queue from JPM and post Pay/Return decisions automatically — the automation layer on top of the Phase-1-functional manual flow.
State (2026-05-08): No REST decisioning endpoint or Positive Pay reference appears anywhere in the JPM developer portal Checks markdown. Jessica Jin reconfirmed 2026-03-03: "Check Exception Management will be launching tentatively in Q2. Can incrementally add this capability when this is live via the API." See §12 #7.
Phase 1 decisioning paths (until JPM REST GA):
| Path | Mechanism | UTA operational cost | Tradeoff |
|---|---|---|---|
| Manual JPM Access UI | Designated UTA operator(s) log into JPM Access during a daily cutoff window, review exception queue, click PAY or RETURN per item | Daily login + per-item review during JPM's cutoff window (typically morning to early afternoon ET) | Operational overhead; matches existing CNB pattern; preserves full decision flexibility |
| Default decisioning rules (configured at JPM onboarding, not programmatic) | UTA tells JPM at onboarding: "auto-return all exceptions" (safest), or "auto-pay below $X / auto-return above," or similar | Zero ongoing operational cost | Rigid policy; legitimate-but-mismatched checks may bounce; safest variant (auto-return-all) may cause friction for legitimate payees |
UTA decision needed at JPM onboarding (see §5 kickoff agenda item #6): which Phase 1 path, who owns the operational workflow if Manual UI, and what the default-rule policy is if Default Rules.
Architectural impact when REST GA lands: the §7.7 Issuance flow does not change. UTA wires in a pull-exception + post-decision flow as an additive Wave 3 capability without disrupting Phase 1 plumbing.
7.10 Out-of-Scope GP2 Rails
The following GP2 rails are reachable via the same POST /payment/v2/payments endpoint by setting paymentType accordingly. None are in scope for UTA Phase 1 but they are documented here so the dev team knows not to wire them in:
paymentType | Rail | Notes |
|---|---|---|
PUSH_TO_CARD (or per-OAS value) | Push to Card — disburses to debit/prepaid cards | Out — UTA does not disburse to cards |
PUSH_TO_WALLET | Push to PayPal / Venmo | Out — not a UTA payee channel |
ZELLE | Zelle Disbursements | Out — UTA uses Zelle through retail rails, not corporate disbursement |
JPM_COIN (Kinexys) | Cross-border via JPM Blockchain Deposit Account | Out — no BDA at UTA |
INTERAC | Canadian RTP scheme | Out of geography (CAD 25,000 limit; UTA's Canadian volume is too low to justify) |
7.11 Inbound Credit Refunds & Reversals
Status: Per-rail (see table) | Use case: Refunding a credit UTA received (overpayment, duplicate payment, wrong-account, client request, fraud reversal)
Distinction: This subsection covers refunding an inbound credit UTA already received — not returning an outbound payment UTA sent (which is §7.2 Return endpoint for RTP and paymentStatus = RETURNED callbacks for ACH per §7.3). The operational ask is: "client deposited $X to UTA in error / overpayment / wants it back — how do we send it back via JPM?"
Per-rail refund mechanisms:
| Inbound rail | Programmatic refund surface? | Refund mechanism | UTA requirement |
|---|---|---|---|
| RTP (TCH RTP / FedNow) | Partial — needs JPM confirmation. GP2 POST /payment/v2/payments/returns with paymentType: RTP accepts a return citing the bankReferenceNumber received via the original §6.5 Payment Receipts notification. OAS confirms the endpoint and schema, but only ships a Brazil PIX (RealTimeBRPIXPaymentReturn) example — no US TCH/FedNow example. UTA must [CONFIRM with JPM] whether the same shape applies to US RTP (§12 #43). | If confirmed for US: capture bankReferenceNumber from every Payment Receipts webhook, store in Client Processing; refund flow POSTs to /payments/returns with the captured ref + endToEndId for the return. If unconfirmed at Phase 1 cutoff: fall back to "new outbound payment" pattern below. | |
| ACH credit | No. No client-initiated refund/return endpoint exists for inbound ACH credits in GP2 OAS. (NACHA R-code returns are RDFI-side automated rejections for system reasons like NSF / no-account — not voluntary refunds.) | UTA initiates a new outbound ACH credit (§7.3) back to the originator's account. Use originator's bank info captured in §6.1 Transaction Details (achBatchItems[].items[].dfiAccountId / dfiBankId) + originator name from the same record. Reference the original payment in remittanceInformation for audit. | |
| Wire (inbound) | No. Wires are technically irrevocable once received. "Wire recall" exists as a bilateral bank-to-bank SOP but is not a programmatic API — JPM ops engages on behalf of UTA via a manual process if the case justifies (e.g., demonstrable fraud, large-dollar error). | UTA initiates a new outbound wire (§7.5) back to the originator. Use originator details captured in §6.1 Transaction Details (originatingBank.name, originatingCust.name, originatingCust.partyIds, etc.). Reference the original UETR / bankReferenceSearchable.standardValue in the outbound wire's remittanceInformation.unstructuredInformation[].text for audit. | |
| Check deposit | No. Check refunds are not a programmatic surface — once a deposited check has cleared, the funds are settled. (Pre-clearance reject is the drawee bank's mechanism, not UTA's.) | UTA initiates a new outbound payment back to the depositor — typically ACH (§7.3) if UTA has the depositor's ABA/account, or check (§7.7 Print) otherwise. Reference the original deposit's checkNumber + customerReferenceSearchable.standardValue in the outbound payment's remittance. |
Requirements UTA owns (per the §16 scope split — engineering design implements):
- What triggers a refund — defined upstream of this spec in Client Processing business rules. Likely: AR-team flag + manager approval; client-service ticket on overpayment; fraud-ops disposition.
- Originator-data persistence — Client Processing must retain enough of the inbound credit's data (from §6.1 Transaction Details + §6.5 Payment Receipts) to populate a return request. Minimum: original
endToEndId,bankReferenceNumber/clearingSystemReference, originator name + account + bank, original amount + value date. These need to be queryable months after the original receipt (statutory dispute windows). - Refund-as-new-outbound-payment dedup — when refund is implemented by initiating a new outbound payment (ACH / Wire / Check), UTA's idempotency key must NOT be the same as any prior outbound payment to that same beneficiary. Use a refund-specific key prefix (e.g.,
RFND-<original-bankRef>). - Audit linkage — every refund (whether RTP-return-endpoint or new-outbound-payment) must carry a reference to the original inbound credit in remittance fields so JPM-side reconciliation (and UTA's audit) can pair them.
- Rail-selection policy for the "new outbound payment" fallback — when refunding an ACH credit or wire credit via a new outbound, does UTA refund on the same rail received? On the fastest available rail? Cheapest? Caller's preference? This is a Cliff decision before engineering hand-off.
Status: Phase 1 covers refund-via-new-outbound-payment for ACH, Wire, and Checks (uses already-in-scope §7.3 / §7.5 / §7.7 rails). RTP programmatic return is conditionally Phase 1 pending §12 #43 confirmation; if not confirmed before CAT-ready, RTP refunds also fall back to new-outbound-payment until JPM confirms US shape support.
8. Status Inquiry Strategy
JPM is a mixed push/poll model. The default path for every outbound payment is the GP2 Callback (§6.1). Polling GET /payment/v2/payments/{paymentId} is a fallback used only when a callback has not arrived within rail SLA, or when UTA needs a confirmation snapshot before a GL post.
8.1 Per-rail polling cadence (fallback, only when callback hasn't arrived)
| Rail | Callback SLA | Fallback poll cadence (after SLA breach) | Final-status criteria |
|---|---|---|---|
| RTP | "typically within 30 seconds" of network response | Every 30 sec for 5 min, then every 5 min for 30 min, then alert | paymentStatus ∈ {COMPLETED, REJECTED, RETURNED, CANCELED} |
| ACH | Within minutes for ACCEPTED/PROCESSING; T+2 for terminal COMPLETED/RETURNED | Every 5 min until ACCEPTED, then every hour during business hours until terminal | paymentStatus ∈ {COMPLETED, REJECTED, RETURNED} |
| Wire (same-currency) | Within minutes for ACCEPTED; same-day for terminal | Every 5 min until terminal | paymentStatus ∈ {COMPLETED, REJECTED, RETURNED} |
Stop polling on terminal. UTA's polling loop must respect terminal status — never re-poll a payment that has reached COMPLETED, REJECTED, RETURNED, or CANCELED. This is the same discipline as CNB v5 §7 (where 0 and 10 were the terminal IFX status codes).
8.2 Status visibility scope
Status inquiry works only for transactions UTA submitted through GP2. Payments initiated via J.P. Morgan Access UI, Wire Center, or other channels are not queryable by paymentId from the GP2 endpoint.
8.3 Idempotency on retries
When a poll or a re-submission is needed:
Idempotency-Keyheader reused with same payload → returns the prior response (safe)Idempotency-Keyreused with different payload → error10106(HTTP 422) — generate a new key- Concurrent same key → error
10107(HTTP 409) — wait + poll, do not retry immediately
9. Reconciliation Logic — The Three-Way Match
For JPM, the Three-Way Match assurance strategy uses GP2's webhook architecture as the engine and the Account Balances API + Transaction Details API as the brake.
Three sources:
- Bank Source ("The Brakes"): Account Balances API (§6.2) for balance snapshot + Transaction Details API (§6.1) for activity, queried at ~10:00 PM local for EOD close.
- Sub-ledger Source ("The Engine"): UTA's cumulative record of GP2 callback events (§6.6), Payment Receipts events (§6.5), and successful
201responses fromPOST /payment/v2/payments(§7.2–§7.5). - ERP Source (NetSuite): Total Journal Entries posted in the matching period, retrieved via the NetSuite REST API.
Assurance rule: any discrepancy between the bank's settled balance (Brakes) and the sub-ledger's recorded activity (Engine) must be flagged as a variance and routed to the GL manager for audit before next business day open.
Reconciliation timing:
| Step | Time | Action |
|---|---|---|
| Intraday | Continuous | GP2 Callbacks + Payment Receipts update sub-ledger in real time |
| EOD Balance Lock | ~10:00 PM local | Pull Account Balances API (§6.2) balances; freeze sub-ledger totals |
| EOD Match | ~10:05 PM local | Compare Engine totals against Brakes; flag variances |
| Prior-Day Confirm | ~7:30 AM local | Pull Transaction Details API (§6.1) ?relativeDateType=PRIOR_DAY for prior day; reconcile any missing events |
10. PACMan — Platform Availability Communication Management
Status: Deferred — Phase 2 reliability uplift (not required for Phase 1) | Channel: N/A in Phase 1 | Sequence: Phase 2
Purpose: Optional pre-flight participant availability check for US RTP — confirms the receiving bank is currently online before UTA submits an RTP credit, avoiding 11026/11027/11703/11704 agent-suspended errors and burned endToEndIds. Phase 1 does not integrate PACMan. JPM's RTP endpoint returns agent-suspended errors directly, and §7.2's error path handles them. Reconsider for Phase 2 if RTP volume or operational posture changes the value calculus.
OAS: Playbook/Platform Availability API 1.1.0.yaml. Two REST endpoints (GET /participants, GET /participants/{id}) plus a declared webhook callback (POST /client-domain) — full deep-scan deferred to Phase 2.
Source basis: PACMan overview · Platform Availability API v1.1.0 OAS.
11. Rollout Sequencing
Three waves, ordered by dependency on JPM-side onboarding (Pre-Flight gates everything; webhooks gate Wave 1; FX gates Wave 3 pending JPM clarification).
Wave 1 — Inbound + base outbound (target: Test 2026-07, Prod 2026-09)
- §4 Authentication (all 5 cert types)
- §6.1 Transaction Details API — Intraday + Prior-Day Activity
- §6.2 Account Balances API — EOD Balance Anchor
- §6.5 Payment Receipts receiver (UTA-side endpoint stood up; RTP coverage)
- §6.6 GP2 Callbacks receiver (UTA-side endpoint stood up)
- §7.1 Validation Services (Pre-Flight)
- §7.2 RTP — Real-Time Payments (with optional §10 PACMan check)
- §7.3 ACH — Credit Disbursements
- §8 Status inquiry strategy
- §9 Reconciliation logic
Wave 2 — Wire + Checks + ACH Debit (target: Test 2026-08, Prod 2026-10)
- §6.4 Check Image retrieval
- §7.4 ACH — Authorized Debit Pulls
- §7.5 Wire — Same-Currency
- §7.7 Check Issuance & Print
- §7.8 Cancellation, Stop Payment & Revoke
Wave 3 — FX + Positive Pay (target: dependent on JPM)
- §7.6 Cross-Currency Wire / FX (blocked on JPM Integration Manager)
- §7.9 Positive Pay Decisioning (blocked on JPM GA)
12. Open Items
Item numbers are stable across versions — never renumber. Closed items remain numbered with a (closed) suffix.
GP2 pilot enrollment confirmation — (path forward documented 2026-05-12). Jessica Jin 2026-05-12 provided the onboarding sequence: UTA submits formal implementation request to Sam Bomes + Joey at JPM, which triggers implementation-team assignment and UAT environment setup. UTA prerequisites (accounts in scope, payment types in scope, certificates, POC list registered in PDP) are now documented in §5. Reconfirmed Jessica's 2026-03-03 framing: "Our team is actively seeking clients to be in the pilot phase and believe the team would be a great candidate to be in GPV2."
[ACTION — UTA: confirm §5 prerequisites, then send formal implementation request to Sam Bomes + Joey]Inbound webhook signature scheme (GP2 Callbacks + Payment Receipts) — JPM Integration Manager owes the canonical authentication contract on inbound webhooks. Public OAS shows
x-jpmc-security: {}(empty placeholder).[CONFIRM with JPM]Complete CloudEvent
typeenum per rail — public portal documents onlyPayment.CompletedandPayment.Rejected; OAS implies many more. JPM Integration Manager owes the full list.[CONFIRM with JPM]Cross-currency wire / FX flow product mapping — (closed — end-to-end flow documented 2026-05-11). Wire-body field:
instructionForDebtorAgent: "/FXA/<id>"per Jessica Jin (2026-03-03). Upstream RFQ flow:Request for Quote API v1.0.1OAS downloaded (Playbook/Request for Quote API 1.0.1.yaml) — endpointsPOST /tsapi/v1/quotes,/trades,/trades/cancel. Returns Rate ID (R…30 chars) at Quote step, Contract ID (T…30 chars) at Trade step. UTA standard: use Contract ID (T…) for production wires (locked rate). Full end-to-end flow now documented in §7.6.1-§7.6.5. Remaining sub-items (US Wire FX sample body, Contract ID lifecycle, currency trading hours) split into new items #33-#35.Checks API canonical base URL — (closed) — Confirmed 2026-03-03 by Jessica Jin and re-verified by Checks API v2.1.1 OAS on 2026-05-12. Base URL is
https://api-mock.payments.jpmorgan.com/payable/v2(mock); production analoghttps://api.payments.jpmorgan.com/payable/v2. PDP reference forcheckCancellation: https://developer.payments.jpmorgan.com/api/treasury/checks/checks#/operations/checkCancellation . HTTP conventions: https://developer.payments.jpmorgan.com/api/response-codes . v2.2 spec was correct on the/payable/v2base Q5.Check Cancel verb/path — (closed 2026-05-11; full §6.4 / §7.7 / §7.8 deep-scan completed 2026-05-12). All three verbs OAS-confirmed at OAS-canonical paths: Cancellation
POST /checks/cancellations, StopPOST /checks/stops, RevokePOST /checks/stops/revoke. Full schemas, error codes, multi-payee limits, escheatment fields, stop-expiration semantics, and async polling for Print (GET /checks/prints/{id}) now documented in §7.7 and §7.8. SeePlaybook/Checks API 2.1.1.yaml.Positive Pay decisioning REST API GA timing — Reconfirmed 2026-03-03 by Jessica Jin: "Check Exception Management will be launching tentatively in Q2. Can incrementally add this capability when this is live via the API." UTA's spec treats this as Phase 2 deferred. Watch for Q2 2026 launch announcement.
Payment Receipts webhook payload schema — (closed — schema self-answered via OAS 2026-05-11). Payment Receipts API v1.2.0 OAS downloaded to
Playbook/Payment Receipts 1.2.0.yaml. The full webhook envelope (creditConfirmationwithtransactionDetails,relatedParties.debtor/creditorwith full postal addresses,relatedAgents, structured + unstructuredremittanceInformation, andtaxInformation.debtorTaxInformationfor Mexico) is now documented in §6.5. Webhook path/webhook/credit-confirmation; receiver{YOUR-SERVER-DOMAIN}/creditConfirmation. OAS examples cover Singapore IRCT and UK FPS Agency Banking (no US RTP example, but schema is rail-agnostic). Remaining sub-item: rail-coverage roadmap — public docs originally implied RTP-only, but the OAS schema is rail-agnostic; whether JPM firescreditConfirmationevents for inbound US Wire and inbound ACH credits is still unconfirmed. Polling fallback via Transaction Details API (§6.1) and Account Balances API EOD (§6.2) covers any gap. Sub-item split to new #36.Business Direct Connect — BAI code field name — (closed — BDC out of scope for UTA per Jessica Jin 2026-05-12). UTA is corporate-segment on JPM's Access platform; BDC is the commercial-segment product. Original BDC OAS analysis (field
commercialCode, shape{type: BAI \| BTRS \| ISO \| SWIFT, code: <string>}) is retained for historical context only. UTA's path is the Transaction Details API permanently (baiType.typeCode+baiType.description+baiType.btrsTypeCode). Not a future-state migration target.Business Direct Connect — date format and required-ness — (closed — BDC out of scope for UTA per Jessica Jin 2026-05-12). Same as #9: BDC is commercial-segment-only; UTA is corporate-segment and permanently on Transaction Details API (which uses
startDate/endDateorrelativeDateType=CURRENT_DAY|PRIOR_DAY, YYYY-MM-DD).Business Direct Connect — rate limits — (closed — BDC out of scope for UTA per Jessica Jin 2026-05-12). Not applicable; UTA is corporate-segment and cannot migrate to BDC (commercial-segment-only product).
Validation Services mock base URL + complete verification-vs-authentication code tables. (closed — full §7.1 OAS deep-scan completed 2026-05-12). Validation Services API v2.2.3 OAS deep-scanned and §7.1 rewritten with full OAS-anchored schema (
Playbook/Validation Services API 2.2.3.yaml). Servers confirmed: productionapigateway.jpmorgan.com/tsapi/v2, CATapigatewaycat.jpmorgan.com/tsapi/v2, mockapi-mock.payments.jpmorgan.com/tsapi/v2. Two endpoints:POST /validations/entitiesandPOST /validations/accounts. Required headers:x-client-idandx-program-id. Samplex-program-idvalues per profile (VERIAUTH,VERIAUTHMULTI,VERIAUTHNONUS,VERIAUTHUS,SUREPAYVOP) and async callback support ({client-url}/status) now documented in §7.1. Result-code first-digit dictionary and provider taxonomy fully captured. Auth confirmed as mTLS-only (no Digital Signature requirement). Per-customer onboarding values carry over to #38.GP2 Payment Cancellation endpoint exact path — referenced verbally but not surfaced.
[CONFIRM with JPM]Cert-installation calendar — significance of double-asterisked dates (2026-07-16, 2026-07-30, 2026-11-19, 2026-12-17).
[CONFIRM with JPM]apigateway.jpmorgan.commTLS expiry 2026-05-28 / 2026-10-22 — UTA must re-pin before expiry.[ACTION — UTA]UTA decision: same-day wire credit treatment for AR auto-match. (closed) — Conservative (Pending) selected 2026-05-08. See §6.1. Current-day wire credits are treated as unposted until the ~7:30 AM prior-day confirm.
UTA callback receiver standup — UTA hosts an HTTPS endpoint that JPM pushes to (GP2 Callbacks + Payment Receipts). Architecture TBD pending Amir's review — candidate approach floated in early discussions: AWS API Gateway + Lambda fronted by mTLS-terminating ALB. Implementation not started.
[ACTION — Amir, UTA Engineering: confirm or propose alternative architecture, then scope the build]UTA account list for CAT entitlement — (closed 2026-05-12). Two Klutch accounts confirmed by Cliff in 2026-05-12 followup to Jessica Jin: 900867182 (KSG Operating USD) and 900867232 (KSG Client Trust USD). JPM serves Klutch only; touring, endorsements, and voiceovers are at CNB and out of scope. These accounts go in the formal implementation request to Sam Bomes + Joey.
PoC against JPM — none executed yet.
[ACTION — UTA Engineering]JPM Wallet onboarding decision — (closed 2026-05-12). §7.6 FX wire flow resolved via RFQ + GP2 Wire with
/FXA/<contractId>(§12 #4 closed 2026-05-11). JPM Wallet is not required for UTA's FX wire path. Decision: do not onboard JPM Wallet.PACMan schema and endpoint paths — (closed 2026-05-11; PACMan deferred to Phase 2 on 2026-05-12). Platform Availability API v1.1.0 OAS downloaded (
Playbook/Platform Availability API 1.1.0.yaml). Three endpoints surfaced:GET /participants(optionalstatus=ONLINE\|OFFLINEfilter),GET /participants/{id}, andPOST /client-domain(webhook callback — corrected from prior framing of "polling-only"). Production hosts:openbanking.jpmorgan.com/tsapi/v1(OAuth) andapigateway.jpmorgan.com/tsapi/v1(mTLS); CAT analogsopenbankinguat,apigatewayqaf. Scope decision 2026-05-12: PACMan is an optional reliability uplift for RTP, not a Phase 1 necessity — JPM's RTP endpoint returns agent-suspended errors that §7.2 already handles. Full integration deferred to Phase 2 if RTP volume or operational posture changes the value calculus. See §10.Indicative FX rate file — (closed 2026-05-11). Resolved by the FX Rate Sheet API v1.0.2 (
Playbook/FX Rate Sheet API 1.0.2.yaml). EndpointGET /tsapi/v1/accounts/{accountId}/ratesheets/currentreturns both EXECUTABLE and INDICATIVE rate types per currency pair, per customer department. Direct functional replacement for CNB §5.6 Exchange Rate File. Documented in §7.6.6.US Wire — sample request body — (closed 2026-05-12). Jessica Jin provided verbatim curl + JSON sample (same-currency USD Fedwire). Documented in §7.5. Key shape confirmations:
debtorAgent.financialInstitutionIds[]accepts multiple entries (USABA + BIC);paymentTypeInformation.paymentContext: "CUSTOMER";paymentPurpose.purpose.codeuses ISO 20022 codes; outboundremittanceInformation.unstructuredInformationis[{text: "..."}](array of objects — distinct from §6.5 inboundarray of strings).Per-rail
endToEndIdlength — GP2 OAS v2.4.7 base schema is max 128 chars globally; my earlier per-rail limits (RTP 1-35, ACH 1-15, Wire 35) were from developer-portal narrative pages, not the OAS. Rail-specific validators may enforce stricter limits in CAT/Production.[CONFIRM with JPM]the per-rail validator length for RTP, ACH, and Wire before locking UTA'sendToEndIdgenerator format. See §7.2, §7.3, §7.4, §7.5.GP2 CloudEvent
typeenum — confirmed via OAS deep-scan (2026-05-08) that the spec lists 6 named callback examples (Push To Card Status,Push To Card - TP3 Status,Push To Card - TP3 Rejected Status,Kinexys DDA-to-BDA Completed Status,ACH Batch,RTP - BR PIX Payment Return) but does NOT enumerate the exacttypestrings.[CONFIRM with JPM]the completeEvent.typeenum so UTA's callback dispatcher can route on it. Same root issue as item #3.BDC product fit — clarification of right inbound product — (closed; reaffirmed 2026-05-12 by Jessica Jin) Transaction Details API + Account Balances API is UTA's permanent path. Jessica's 2026-05-12 reply made the segment-eligibility framing explicit: "Business Direct Connect platform is for our commercial clients – UTA is considered a corporate client on our Access platform and will not be able to utilize FDX." BDC is not a future-state migration target — it is a different product line UTA cannot access. v3.0 spec §6.1 is the permanent path. Methodology lesson logged at
Bank/lessons-learned.md.Transaction Details API — Mock server availability — OAS v3.1.8 declares Production + multiple CAT/UAT servers but NO dedicated mock.
[CONFIRM with JPM Integration Manager]whether sandbox testing happens via CAT (with sandbox credentials) or via a separate mock URL not yet declared in the OAS. Blocks Postman validation of §6.1 until resolved.[ACTION — UTA Engineering]Transaction Details API —
tier: LEGACYEOL timeline — (closed / de-prioritized 2026-05-12). Per Jessica Jin: UTA is corporate-segment on the Access platform and cannot use BDC regardless of EOL timing. Whatever the EOL timeline for Transaction Details is, UTA's only path is to stay on it (or whatever Access-platform successor JPM ships for corporate clients). No BDC-migration parser-abstraction investment needed. Re-open only if Jessica or JPM announces an Access-platform replacement for corporate-segment clients.Account Balances API — OAS file — (closed) Resolved 2026-05-11. OAS downloaded to
Playbook/Account Balances API 1.0.5.yaml. §6.2 deep-scan proceeding.Transaction Details API —
lockbox informationparameter encoding — OAS literally names the parameterlockbox information(with a space). HTTP clients vary on whether they accept a literal space in query strings or require URL-encoding (%20).[CONFIRM in Postman/CAT]which form JPM's validator accepts. Affects UTA's parser library choice.Transaction Details API — BAI Type Code dictionary parity with CNB — UTA's existing CNB BAI2 parser handles a specific set of BAI Type Codes (115, 165, 195, 475, 935 RETURN WIRE, etc.). The Transaction Details API OAS doesn't enumerate which BAI codes JPM returns.
[CONFIRM with JPM]that JPM uses the standard BAI2 code dictionary so the existing parser logic can be reused. If JPM uses any non-standard codes, the parser needs an extension table.GP2 Payments Playbook — (closed) Resolved 2026-05-11. The GP2 Client Integration Guide v2 (
2026_GP2_Client_Integration_Guide_Version_2.pdf) IS the GP2 Payments companion to the Reporting Playbook — symmetric pairing: Reporting Playbook covers reporting APIs (Transaction Details, Account Balances); GP2 Integration Guide covers outbound payments (ACH, Wire, RTP). The GP2 guide is screenshot-heavy and PDF text extraction is lossy — for implementation specifics, the GP2 OAS v2.4.7 is the authoritative reference; the guide is supplementary.US Wire FX — sample request body with
instructionForDebtorAgentpopulated — (closed 2026-05-12). Jessica's 2026-05-12 base US Wire sample (see #23 and §7.5) provides the same-currency shape; the FX variant addsinstructionForDebtorAgent: "/FXA/<jpmContractId>"per §7.6.4 (Jessica 2026-03-03). UTA combines base-wire shape + the/FXA/field for FX wires — the two confirmations are composable; no additional Jessica sample needed.RFQ Contract ID lifecycle / expiry window — RFQ OAS v1.0.1 shows
expirationTimeUTCon the Quote response but does NOT document an explicit expiry on a booked Trade Contract ID.[CONFIRM with JPM]whether a bookedjpmContractIdhas its own expiration window separate from the wire'srequestedExecutionDate, and what happens if UTA's wire is submitted after that window. See §7.6.8.FX trading hours catalog — RFQ OAS v1.0.1 error codes reference branch and currency trading hour windows (
ERR_1329outside branch trading hours,ERR_1330outside currency trading hours,ERR_1369outside onshore CNY trading hours) but doesn't enumerate the windows.[CONFIRM with JPM]— likely a JPM Markets reference document; needed for UTA's submission timing logic to avoid wasted RFQ Quote calls.Payment Receipts — rail coverage for inbound US Wire and inbound ACH credits — split from item #8. The Payment Receipts v1.2.0 OAS schema is rail-agnostic (no rail enum constrains the
creditConfirmationevent), but the public dev-portal narrative originally framed Payment Receipts as RTP-only. UTA needs to know whether JPM actually firescreditConfirmationwebhooks for inbound US Wire credits and inbound ACH credits, or only for RTP. If wire/ACH are not covered, UTA falls back to Transaction Details polling (§6.1) — already adequate.[CONFIRM with JPM Integration Manager]the rail enum forcreditConfirmationevents as actually delivered in production.Wire Payments 2 API confirmed out-of-scope — (closed 2026-05-11). Wire Payments 2 API v2.0.5 OAS downloaded to
Playbook/Wire Payments 2 API 2.0.5.yaml. OAS confirms this is the FI-to-FI (correspondent banking) wire product:initiatingParty.id.organizationId.other.idis required to equal"BANK", and all 3 OAS examples are labeled "US FI to FI." UTA is a corporate (talent agency), not a financial institution, so UTA's wires belong in GP2 (§7.5), not Wire Payments 2. See §7.5 distinction paragraph andJPM_API_Catalog.md. This resolves the earlier-session uncertainty over whether a separate Wire OAS existed — one does exist, but it is for a different customer segment.Validation Services — customer-specific
x-client-id/x-program-idvalues issued to UTA at onboarding — split from item #12. Limited to the per-customer onboarding values; the first-digit message-class dictionary, the result-slot taxonomy (verification,authentication,individualID,businessID,individualScreening,businessScreening,accountScore, etc.), and the provider list are now documented in §7.1 from OAS v2.2.3. UTA still needs the actualx-client-idUTA is assigned plus thex-program-idvalues for each profile UTA enables (Standard, Multi, Non-US, ACS, Microdeposit, SurePay).[CONFIRM with JPM at onboarding]Platform Availability — outage push notification surface — (deferred to Phase 2 on 2026-05-12). Re-scan of PACMan OAS v1.1.0 identified a webhook endpoint
POST /client-domain("Participant Outage reporting Webhook") that the prior pass missed — push surface IS supported on this product (no separate Notifications product required for outage push). However, PACMan as a whole is deferred from Phase 1 — see §10 and #21. Two outstanding sub-items to revisit if Phase 2 elects to subscribe: (a) the subscription mechanism (how UTA registers its callback URL with JPM) is not in the OAS; (b) the webhook body schema in the OAS path is the simplepartnerBankshape, butcomponents.schemasalso defines a richeroutageEventDetailsshape (event typesoutage.created/outage.modified/outage.cancelledwithimpactedProducts[]) that is not linked to any path — confirm which is actually delivered.DigiCert certificate renewal-timeline changes (industry-wide) — Jessica Jin flagged 2026-05-12: "There are certificate management changes in the industry from DigiCert in regard to certificate renewal timelines." Affects how UTA's 5 cert types (§4.1) are generated and rotated, and how UTA coordinates with JPM's 2026 cert-installation calendar (#14).
[ACTION — Amir, UTA Engineering]research current DigiCert timelines before generating UTA's certs.Statement PDF retrieval — Access-platform alternative to BDC — Surfaced 2026-05-12 by the BDC ineligibility cascade. The BDC product (§14.3, marked OUT OF SCOPE) was the only documented JPM Statements PDF API. UTA still needs monthly PDF statement archival for compliance and retention. Phase 1 workaround documented in §6.3: manual download from JPM Access UI (same as today's pre-integration workflow).
[CONFIRM with JPM Integration Manager at kickoff]whether an Access-platform statement-retrieval API exists (analogous to BDC's/accounts/{accountId}/statements/{statementId}but on the corporate-segment side). If yes, scope into Phase 2; if no, manual JPM Access download remains UTA's only path indefinitely.Validation Services — Account Confidence Score (ACS) numeric-score field location — Surfaced 2026-05-13 during §7.1 sample-response audit. OAS-confirmed
AccountScoreschema is{code: integer, message: string}only (e.g.,1109"Information Found",1209"No Information Found"). JPM's dev-portal narrative documents a numeric 0–1000 RAG-banded score, but no numeric score field exists in the OASAccountScoreshape. Three possibilities to resolve: (a) the numeric score is returned inside thedetailsblock for VERIAUTHUS-profile responses but not schema-documented; (b) the dev-portal narrative is out of step with the current schema and the only consumable signal is theaccountScore.codevalue; (c) the numeric score is on a future-OAS roadmap and not yet surfaced.[CONFIRM with Jessica Jin]which slot/field carries the 0–1000 score, or that the codedaccountScore.codeis the only signal. Until resolved, UTA's Pre-Flight ACS logic keys offaccountScore.codefirst-digit (1Information Found /2No Information Found), not the un-located numeric score. See §7.1 ACS sample response and "OAS vs dev-portal mismatch" note.RTP client-initiated returns — US TCH / FedNow shape confirmation — Surfaced 2026-05-13 during §7.11 Inbound Credit Refunds audit. GP2 OAS exposes
POST /payment/v2/payments/returnswithpaymentType: RTPand thePaymentReturnschema is rail-agnostic on its face — but the only ships example is Brazil PIX (RealTimeBRPIXPaymentReturn). No US TCH/FedNow return example exists in the OAS.[CONFIRM with Jessica Jin]whether (a) the same/payments/returnsshape works for inbound US RTP credits citing thebankReferenceNumberUTA receives from §6.5 Payment Receipts, (b) US RTP returns require a different shape JPM has not yet published in the OAS, or (c) US RTP credits are simply not eligible for client-initiated programmatic return and UTA must refund via a new outbound payment. Drives §7.11 Phase 1 scope decision: if (a) confirmed, RTP refunds use the programmatic return endpoint; if (b) or (c), RTP refunds fall back to the new-outbound-payment pattern same as ACH/Wire/Check refunds.
13. Next Actions
- Jessica Jin reply received 2026-05-12 closing (a) BDC ineligibility for UTA — corporate-segment client cannot use commercial-segment BDC (closes §12 #9 / #10 / #11 / #26 / #28); (b) US Wire sample request body provided verbatim (closes §12 #23 / #33; §7.5 Status flipped to Cleared); (c) onboarding path: formal implementation request to Sam Bomes + Joey at JPM kicks off implementation-team assignment + UAT environment setup. Next: UTA-side, send the formal implementation request once §5 UTA prerequisites are confirmed (accounts in scope, payment types in scope, certificates obtained, POC list registered in PDP).
- Stand up UTA's callback receiver (§4.5 + §6.5 + §6.6) — Amir to confirm the receiver architecture (candidate: AWS API Gateway + Lambda + mTLS-terminating ALB; not yet locked) and then scope the build. This is on the critical path; cannot be parallelized with cert exchange.
- Cliff: deliver UTA's Klutch account number(s) for CAT entitlement (#18). JPM serves Klutch only — touring, endorsements, and voiceovers are at CNB.
- Generate UTA-side certificates — all 5 types per §4.1, in coordination with UTA security. Plan the 2026 cert-installation calendar windows backwards from the desired CAT-ready date.
- Engineering PoC against the GP2 sandbox —
POST /payment/v2/paymentswith a synthetic RTP body, validate the response shape, then validate that a sandbox Payment Receipts callback fires when a counterpart simulates an inbound credit. Goal: prove the end-to-end happy path before CAT. - Engineering design document — Amir's team owns drafting (separate from this spec; see §16 three-document set for context). Covers HOW the integration-boundary requirements in §6 / §7 / §8 / §9 plus the Client Processing behavior in document (B) are implemented: class decomposition, queue architecture, retry semantics, error-handling matrices for callbacks vs. polling, callback-receiver structure. Cliff's role here is requirements clarification when Amir's team flags an implementation question that exposes a gap at the integration boundary (when to call X, what to do with payload Y, how to handle exception Z) — those answers land in this spec. Gaps inside Client Processing (business rules, triggers, payload consumption) land in document (B). Engineering hand-off depends on BOTH (A) this spec AND (B) Client Processing behavior spec being ready — Amir's design needs both inputs. (A)-only hand-off would leave (C) without the business-rules layer it implements against.
- Schedule JPM Integration Manager call to walk through still-open JPM-side items in §12 — particularly #2 (webhook signature), #3/#25 (CloudEvents
typeenum), #13 (GP2 Payment Cancellation path), #23/#33 (US Wire sample), #28 (Transaction Details EOL), #36 (Payment Receipts rail coverage), #38 (Validation Services per-customer values), #39 (PACMan push surface), #42 (Validation Services ACS numeric-score field location), #43 (RTP client-initiated returns US shape confirmation). Many of these are unlikely to be resolved by email.
13.1 Requirements gaps to close before engineering hand-off
The following are Cliff-owned requirements decisions (per the §16 scope split) that Amir's engineering team will likely flag during the engineering-design phase. Flagged here so they don't surface as last-minute blockers. Each is a "what does UTA want to do" decision, not a "how does it work technically" question — answers land in this spec, not in the engineering design doc.
Webhook receiver behavior on retransmits (§6.5 Payment Receipts, §6.6 GP2 Callbacks). The receiver dedup-by-
endToEndIdrule is documented, but the response-to-JPM policy on partial failures is not. Decisions needed: (a) does UTA's receiver always return200 OKto JPM regardless of downstream handler outcome, deferring to a local retry queue? (b) or does the receiver propagate downstream failures back to JPM as5xxand let JPM retry? (c) what's the local retry policy if (a)? Tradeoff: option (a) puts retry burden on UTA; option (b) gives JPM control but couples receiver liveness to downstream system health.Per-error-code handling matrix for outbound payments (§7.2 – §7.5). GP2 returns granular error codes (e.g.,
9001Data Provider Error,9005Bad Request / Rate Limit, plus rail-specific rejection codes onpaymentStatus: REJECTEDcallbacks). UTA needs a per-code disposition matrix: which codes auto-retry, which queue for manual review, which auto-bounce back to AR with notification, which page on-call. Currently the spec covers terminal-state criteria but not the per-code branching policy.Microdeposit Challenge operational workflow (§7.1 Validation Services). When Pre-Flight returns
MICRODEPOSIT REQUIRED, JPM sends two small deposits to the candidate account, then asks the customer to confirm the amounts. Decisions needed: who at UTA handles the customer-confirmation step? Is there a Client Processing UI for it, or is this a manual operator workflow? What's the timeout / escalation policy if the customer doesn't confirm within JPM's window?Three-Way Match failure handling (§9 Brakes). When the EOD Three-Way Match fails (bank vs sub-ledger vs GL), what's the operational workflow? Manual review queue assigned to which team? Auto-retry the match after a settle period? Page on-call after how many consecutive failures? What's the escalation tree?
Inbound credit refund — rail-selection policy (§7.11). When refunding an inbound credit via the new-outbound-payment pattern (ACH, Wire, Check), what rail does UTA choose? Same rail as received? Fastest available (RTP if eligible)? Cheapest (ACH)? Caller's preference? Different policies per refund-reason category (overpayment vs fraud vs client request)?
Refund authorization workflow (§7.11, upstream from this spec). Who authorizes a refund inside UTA — AR-team flag + manager approval; client-service ticket; fraud-ops disposition? This is upstream of the integration but shapes what Client Processing must capture and what state-transitions Amir's team designs around.
Resolution path: Cliff drafts answers (or asks Andrew / cash-mgmt / client-accounting for input where the policy is operationally owned elsewhere). Answers land in the relevant §6 / §7 / §9 section as new requirements rows. Once landed, items in this subsection get a (closed) suffix the same way §12 items do. Do not delete closed items — the historical record matters for engineering-design traceability.
14. References
Every endpoint, field, schema, and behavior cited in this document traces back to one of the sources below. Pages on the developer portal are stable HTTPS URLs and load without authentication; pages requiring sign-in (the Developer Portal Security tab where certificates are uploaded) are flagged inline. The GP2 Integration Guide PDF lives in UTA's JPM/ folder and is referenced by page number where applicable.
14.1 J.P. Morgan Payments Developer Portal — Reference Pages (cross-cutting)
| Topic | URL |
|---|---|
| API reference root | https://developer.payments.jpmorgan.com/api/home |
| Authentication overview | https://developer.payments.jpmorgan.com/api/authentication |
| mTLS + Digital Signature mechanics | https://developer.payments.jpmorgan.com/api/mtls-with-digital-signature |
| OAuth flow (sandbox + signed JWT) | https://developer.payments.jpmorgan.com/api/oauth |
| J.P. Morgan public certificates (download + thumbprints) | https://developer.payments.jpmorgan.com/api/certificates |
| 2026 callback / encryption cert installation calendar | https://developer.payments.jpmorgan.com/api/environments |
| API versioning / deprecation policy | https://developer.payments.jpmorgan.com/api/versioning |
| Cross-API HTTP response code patterns | https://developer.payments.jpmorgan.com/api/response-codes |
14.2 Global Payments 2 (GP2) — Payment Initiation, Status, Returns
| Topic | URL |
|---|---|
| GP2 overview | https://developer.payments.jpmorgan.com/docs/treasury/global-payments/capabilities/global-payments-2/index |
| GP2 Callbacks (CloudEvents webhooks) | https://developer.payments.jpmorgan.com/docs/treasury/global-payments/capabilities/global-payments-2/callbacks |
| GP2 OpenAPI spec (OAS) | https://developer.payments.jpmorgan.com/api/treasury/global-payments/global-payments-2/global-payments-2-oas |
| GP2 status responses & error codes | https://developer.payments.jpmorgan.com/api/treasury/global-payments/global-payments-2/error-codes |
| GP2 changelog | https://developer.payments.jpmorgan.com/api/treasury/global-payments/global-payments-2/changelog |
| Treasury Global Payments getting started (CAT access gating) | https://developer.payments.jpmorgan.com/docs/treasury/global-payments/getting-started |
Real-Time Payments (RTP) — §7.2:
ACH (NACHA, both directions) — §7.3 & §7.4:
Wire (same-currency) — §7.5:
Cross-Currency / FX — §7.6 (Cleared via RFQ API — see §14.9 for authoritative OAS):
UTA's FX wire path is the Request for Quote API v1.0.1 (§14.9) combined with GP2 Wire carrying instructionForDebtorAgent: "/FXA/<contractId>" — see §7.6. JPM Wallet was evaluated and is not required for UTA (§12 #20 closed 2026-05-12). No standalone JPM developer-portal documentation page exists for this composite RFQ+GP2 flow — the OAS files and JPM's RFQ-flow guidance in the §7.6 sub-sections of this spec are authoritative. Previously-listed JPM Wallet FX-Wire/FX-ACH dev-portal URLs returned 404 and were removed 2026-05-13.
14.3 Business Direct Connect (FDX v6) — OUT OF SCOPE for UTA
BDC is JPM's commercial-segment product. UTA is corporate-segment on the Access platform and cannot use BDC (per Jessica Jin 2026-05-12; closes §12 #9 / #10 / #11 / #26 / #28). Retained here for historical reference only — none of these URLs are part of UTA's permanent integration path. UTA's inbound reporting product is the Transaction Details API + Account Balances API combination (see §6.1, §6.2). The original BDC v6.2.16 OAS file remains in JPM/Playbook/Future-State/ marked as a historical artifact.
14.4 Payment Receipts API (Inbound RTP credits)
| Topic | URL |
|---|---|
| Payment Receipts overview | https://developer.payments.jpmorgan.com/docs/treasury/payment-receipts/doc |
Payment Receipts OpenAPI spec (/webhook/credit-confirmation schema) | https://developer.payments.jpmorgan.com/api/treasury/payment-receipts/payment-receipts-oas |
14.5 Validation Services (Pre-Flight)
14.6 Checks API (Issuance, Print, Stop & Revoke, Image, Inquiry)
14.7 PACMan (Platform Availability Communication Management)
| Topic | URL |
|---|---|
| PACMan overview | https://developer.payments.jpmorgan.com/docs/treasury/pacman/doc |
14.8 Out-of-Scope GP2 Rails (referenced in §7.10 only)
14.9 Local Documents
JPM-issued playbooks (authoritative for product selection and onboarding sequence):
| Topic | Path |
|---|---|
| US JPM API Playbook — Reporting v1 (prescribes Transaction Details + Account Balances) | US J.P. Morgan API Playbook_Reporting_v1.pdf |
| GP2 Client Integration Guide v2 (outbound payments companion to Reporting Playbook) | 2026 GP2 Client Integration Guide v2.pdf |
OAS YAML files (authoritative for schemas, field names, error codes):
| API | Spec section(s) | Path |
|---|---|---|
| Transaction Details API v3.1.8 | §6.1 intraday + prior-day | Playbook/Transaction Details API 3.1.8.yaml |
| Account Balances API v1.0.5 | §6.2 EOD balance lock | Playbook/Account Balances API 1.0.5.yaml |
| Global Payments 2 v2.4.7 | §6.6 callbacks + §7.2 RTP + §7.3 ACH Credit + §7.4 ACH Debit + §7.5 Wire | Playbook/Global Payments 2.4.7.yaml |
| Request for Quote API v1.0.1 | §7.6.2 Quote + §7.6.3 Trade + §7.6.5 Cancel | Playbook/Request for Quote API 1.0.1.yaml |
| FX Rate Sheet API v1.0.2 | §7.6.6 (CNB §5.6 indicative-rate-file equivalent) | Playbook/FX Rate Sheet API 1.0.2.yaml |
| Payment Receipts v1.2.0 | §6.5 inbound creditConfirmation webhook | Playbook/Payment Receipts 1.2.0.yaml |
| Validation Services API v2.2.3 | §7.1 Pre-Flight (entity + account validation) | Playbook/Validation Services API 2.2.3.yaml |
| Checks API v2.1.1 | §6.4 + §7.7 + §7.8 (inquiry, image, issuance, cancellation, stop, revoke, print) | Playbook/Checks API 2.1.1.yaml |
| Platform Availability API v1.1.0 | §10 (PACMan — deferred to Phase 2; not in Phase 1 build) | Playbook/Platform Availability API 1.1.0.yaml |
| Onboarded Accounts API v1.0.1 | §5 (one-time post-CAT and Prod go-live entitlement verification) | Playbook/Onboarded Accounts 1.0.1.yaml |
| Wire Payments 2 API v2.0.5 (OUT OF SCOPE — FI-to-FI correspondent banking; UTA wires use GP2 per §7.5) | §7.5 distinction note only | Playbook/Wire Payments 2 API 2.0.5.yaml |
| Xpedite Remit FX Rate Sheet API v1.0.1 (OUT OF SCOPE — consumer remittance, not corporate treasury) | §7.6.7 (mentioned only) | Playbook/Xpedite Remit FX Rate Sheet API 1.0.1.yaml |
| Global Payments API v1.2.0 (DEPRECATED — superseded by GP2 v2.4.7; per Jessica Jin 2026-03-03: "GPV1 will be deprecated eventually, I would not recommend building to GPV1 as a fallback." Do not build against this) | (no scope section — deprecated) | Playbook/Global Payments API 1.2.0.yaml |
| BDC v6.2.16 (OUT OF SCOPE — UTA ineligible. BDC is JPM's commercial-segment product; UTA is corporate-segment on the Access platform per Jessica Jin 2026-05-12: "Business Direct Connect platform is for our commercial clients – UTA is considered a corporate client on our Access platform and will not be able to utilize FDX." Not a future-state target either) | (no migration path; UTA stays on Transaction Details + Account Balances permanently) | Playbook/Future-State/J.P. Morgan Business Direct Connect 6.2.16.yaml |
| JPM API Catalog (master checklist of all 46 JPM products + scoping decisions) | catalog-level reference | Playbook/JPM_API_Catalog.md |
Predecessor specs and other materials:
| Topic | Path |
|---|---|
| Predecessor spec (do not edit) | JPM/UTA JPM GP2 Integration Specification v2.2.md |
| Predecessor spec (do not edit) | JPM/UTA JPM GP2 Integration Specification v1.3.md |
| JPM Integration Manager response — 7 questions answered | JPM/correspondence/2026-03-03_jessica-jin-questions-response.md |
14.10 Conversations & Direction
| Source | When | What it covered |
|---|---|---|
| JPM Integration Manager response | 2026-03 | RFQ Quote → Trade → Contract ID flow shape; Account Balances API rate-limit guidance; ~10:00 PM EOD lock + ~7:30 AM prior-day lock; Payment Receipts PDP path; Transaction Details same-day wire credit availability; Checks API mock base; Positive Pay Q2 launch tentative |
| Cliff direction | post-2026-03 | Expand ACH scope to include authorized debit pulls (§7.4) |
| Amir architecture (candidate, not yet confirmed) | 2026-04+ | Candidate approach floated for UTA callback receiver: AWS API Gateway + Lambda fronted by mTLS-terminating ALB. Architecture not yet confirmed by UTA Engineering as of 2026-05-12 — awaiting Amir's formal review and decision (§12 #17). |
| Cliff/Andrew alignment | 2026-05 | October 2026 production target; 2–3 month test-readiness window |
End of Document — UTA ↔ JPM Global Payments 2 Integration Specification v3.0 (Draft)