Core concepts
The entities of the Payment API and how they relate.
Five entities carry the whole model: Company, Funding accounts (product accounts), Beneficiaries (with their payment methods), Quotes, and Payments.
Company (you)
├── Funding accounts what you pay FROM (productAccounts)
│ self-funded · credit-line · crypto-wallet · jeeves-pay-*
│
├── Beneficiaries who you pay
│ └── Payment methods HOW each one is paid (spei, wire, ach, swift, …)
│
├── Quotes a locked FX rate for one payment (single-use, expiring)
│
└── Payments money in motion: quote + account + beneficiary
└── status history pushed as payment.status.updated webhooksCompany
Your company at Jeeves. Credentials belong to a company; GET /v1/product-accounts returns an array of companies, one entry per company the credential covers — a single-company integration reads [0].productAccounts.
Funding account (product account)
The account a payment is funded from — productAccount in the API. You can hold several, across currencies and types (a USD fiat balance, a stablecoin wallet such as USDC, an MXN balance, credit in USD/MXN/BRL, …). Each has a type — self-funded (your pre-funded balance), credit-line (Jeeves credit; also what you send for a Bill Pay credit account, which GET /v1/product-accounts reports as jeeves-pay-credit), or crypto-wallet (stablecoin balance, currency reported as a ticker like USDC) — a currency, and a status. Only active accounts can fund a payment, and the account's currency must match the quote's sourceCurrency. Your FX rate and fees depend on the type, and the type shapes which purpose codes a corridor accepts.
Beneficiary
A person (individual) or business (business) you pay. Individuals carry firstName/lastName; businesses carry name. Each beneficiary has a bank country and currency, contact information, and zero or more attached payment methods (spei, wire, ach, swift, …). You reference both on a payment: beneficiaryId plus beneficiaryPaymentMethodId. Deleted beneficiaries and methods are never returned by the API. You can read one beneficiary with GET /v1/beneficiaries/{beneficiaryId} and create one with POST /v1/beneficiaries — see Beneficiaries.
Payment method
How one beneficiary is paid: a rail such as spei or wire, with the account details that rail needs. A beneficiary holds at most one payment method per rail. GET /v1/beneficiary-schemas tells you which methods a corridor offers and which bankingInformation and contactInformation fields each needs, and POST /v1/payment-methods attaches one. The paymentMethodId it returns is the beneficiaryPaymentMethodId you send on a payment.
Quote
A locked FX rate for one payment. Quotes are destination-amount based: you say what the beneficiary must receive, and the source amount is derived from the rate. A quote is single-use and expires — read expiresAt from the response (the TTL is configured per company; null means it doesn't expire). Reusing a consumed quote returns 422 quote_expired.
Corridor
The combination of source currency and account type on one side and destination currency/country on the other. A corridor can be domestic — same currency and country on both sides (e.g. MXN → MXN to a Mexican business via SPEI) — and the flow is identical. The corridor decides which purpose codes are valid and what beneficiary details are required. See the purpose-code table in Send a payment.
Purpose code
A regulatory declaration of why the payment is being made — always a string identifier like purchase_of_services, never a number. Mandatory on every payment, with no default. Each corridor accepts a fixed set of identifiers, listed in purposeCodes[] by GET /v1/beneficiary-schemas (see Send a payment); omitting it is a 400, and an identifier outside the corridor's set is 422 validation_failed.
Idempotency key
A customer-generated UUID sent as the Idempotency-Key header on POST /v1/payments, unique per payment attempt and never expiring. Same key + same body replays the original result byte for byte; same key + different body returns 409 idempotency_conflict. On timeout or 5xx, retry with the same key — a fresh key on retry is how duplicate payments happen.
Requote
What happens when onQuoteExpiry: requote rescues an expired quote: a new quote is priced at the current rate and used. The destination amount is unchanged; the source amount moves. The response then carries both quoteId (the quote that priced the payment) and originalQuoteId (the expired one you sent) — the one case where you pay a rate you were not previously shown.
Credential vs. scope
Your credential is the client ID + secret pair and the client certificate issued by Jeeves — it identifies your company. Scopes are the permissions you request on each token (payments:write, quotes:write, …); a token can never reach a capability outside its scopes. beneficiaries:write covers creating beneficiaries and attaching payment methods, and payments:write covers creating and cancelling payments. Some scopes (the *:multiple:* family, cards:multiple:write) are enabled on a credential only on request — ask Jeeves support.
Cancel
Stopping a payment you no longer want to send. You can cancel only while the status is in-review or scheduled; the payment becomes canceled, a canceled webhook is sent, and the quote stays spent. The call isn't idempotent. POST /v1/payments/{paymentId}/cancel — see Cancelling a payment.
Terminal status
A status a payment can never leave: completed, rejected, failed, canceled, refunded. Everything else (accepted, in-review, scheduled, in-progress) is in flight. failureReason is populated for rejected, failed, and canceled.