diff --git a/.claude/skills/grid-api/SKILL.md b/.claude/skills/grid-api/SKILL.md index 7036f5248..26d87d55e 100644 --- a/.claude/skills/grid-api/SKILL.md +++ b/.claude/skills/grid-api/SKILL.md @@ -420,29 +420,36 @@ values `SMS_OTP` (default) or `PASSKEY`. ### Same-Currency Transfers +Use `/quotes` with `"immediatelyExecute": true`. The `/transfer-in` and +`/transfer-out` endpoints are deprecated. + ```bash -# Transfer in (external → internal, same currency) +# External → internal, same currency (source must support pull, e.g. ACH pull) curl -s -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ -X POST -H "Content-Type: application/json" \ -d '{ - "source": {"accountId": ""}, - "destination": {"accountId": ""}, - "amount": 10000 + "source": {"sourceType": "ACCOUNT", "accountId": ""}, + "destination": {"destinationType": "ACCOUNT", "accountId": ""}, + "lockedCurrencySide": "SENDING", + "lockedCurrencyAmount": 10000, + "immediatelyExecute": true }' \ - "$GRID_BASE_URL/transfer-in" | jq . + "$GRID_BASE_URL/quotes" | jq . -# Transfer out (internal → external, same currency) +# Internal → external, same currency # Optional: top-level "remittanceInformation" (memo, max 80 chars) and a "paymentRail" # inside the destination to pick a specific supported rail. curl -s -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ -X POST -H "Content-Type: application/json" \ -d '{ - "source": {"accountId": ""}, - "destination": {"accountId": "", "paymentRail": ""}, - "amount": 10000, + "source": {"sourceType": "ACCOUNT", "accountId": ""}, + "destination": {"destinationType": "ACCOUNT", "accountId": "", "paymentRail": ""}, + "lockedCurrencySide": "SENDING", + "lockedCurrencyAmount": 10000, + "immediatelyExecute": true, "remittanceInformation": "Invoice 1234" }' \ - "$GRID_BASE_URL/transfer-out" | jq . + "$GRID_BASE_URL/quotes" | jq . ``` ### Transactions @@ -535,11 +542,12 @@ Use `sourceType: "REALTIME_FUNDING"` with customer ID and currency. Only works w ### 3. Same-Currency Transfers -Direct transfers between accounts without currency conversion. No quote needed. +Transfers between accounts without currency conversion. These go through `/quotes` +like any other transfer; set `immediatelyExecute` to create and execute in one call. ``` -External Account (USD) → Internal Account (USD) [transfer-in] -Internal Account (USD) → External Account (USD) [transfer-out] +External Account (USD) → Internal Account (USD) +Internal Account (USD) → External Account (USD) ``` ## Interactive Payment Workflows diff --git a/.claude/skills/grid-api/references/endpoints.md b/.claude/skills/grid-api/references/endpoints.md index e7550a096..977891c24 100644 --- a/.claude/skills/grid-api/references/endpoints.md +++ b/.claude/skills/grid-api/references/endpoints.md @@ -118,10 +118,12 @@ Internal accounts are auto-created when customers are created based on platform ## Same-Currency Transfers +Deprecated — use `POST /quotes` with `immediatelyExecute` instead. + | Method | Endpoint | Description | |--------|----------|-------------| -| POST | `/transfer-in` | Create a transfer-in request (external to internal) | -| POST | `/transfer-out` | Create a transfer-out request (internal to external) | +| POST | `/transfer-in` | **Deprecated.** Create a transfer-in request (external to internal) | +| POST | `/transfer-out` | **Deprecated.** Create a transfer-out request (internal to external) | ## Receiver Lookup @@ -281,8 +283,6 @@ The `/agents/me/*` endpoints are called by an agent using its own credentials (A | POST | `/agents/me/quotes/{quoteId}/execute` | Execute a quote | | GET | `/agents/me/actions` | List agent's own actions | | GET | `/agents/me/actions/{actionId}` | Get an agent action | -| POST | `/agents/me/transfer-in` | Create a transfer-in | -| POST | `/agents/me/transfer-out` | Create a transfer-out | | GET | `/agents/me/internal-accounts` | List agent's internal accounts | | GET | `/agents/me/external-accounts` | List agent external accounts | | POST | `/agents/me/external-accounts` | Add an external account | diff --git a/.stainless/stainless.yml b/.stainless/stainless.yml index a4e97538e..f9236c1d2 100644 --- a/.stainless/stainless.yml +++ b/.stainless/stainless.yml @@ -505,7 +505,6 @@ resources: pkr_beneficiary: "#/components/schemas/PkrBeneficiary" ethereum_wallet_external_account_info: "#/components/schemas/EthereumWalletExternalAccountInfo" verification_error: "#/components/schemas/VerificationError" - agent_transfer_details: "#/components/schemas/AgentTransferDetails" slv_external_account_create_info: "#/components/schemas/SlvExternalAccountCreateInfo" slv_beneficiary: "#/components/schemas/SlvBeneficiary" individual_customer: "#/components/schemas/IndividualCustomer" @@ -624,8 +623,6 @@ resources: me: methods: retrieve: get /agents/me - create_transfer_in: post /agents/me/transfer-in - create_transfer_out: post /agents/me/transfer-out list_internal_accounts: get /agents/me/internal-accounts subresources: transactions: diff --git a/components/grid-visualizer/CLAUDE.md b/components/grid-visualizer/CLAUDE.md index 51f3eafc8..3a48ae5ae 100644 --- a/components/grid-visualizer/CLAUDE.md +++ b/components/grid-visualizer/CLAUDE.md @@ -204,10 +204,10 @@ Stablecoins: `SOLANA_WALLET` (USDC), `POLYGON_WALLET` (USDC), `BASE_WALLET` (USD - `POST /customers/external-accounts` — Register external account - `GET /customers/internal-accounts` — List customer internal accounts - `GET /platform/internal-accounts` — List platform internal accounts -- `POST /quotes` — Create cross-currency transfer quote +- `POST /quotes` — Create a transfer quote (same-currency and cross-currency) - `POST /quotes/{quoteId}/execute` — Execute quote -- `POST /transfer-out` — Same-currency internal → external -- `POST /transfer-in` — Same-currency external → internal +- `POST /transfer-out` — **Deprecated.** Same-currency internal → external; use `/quotes` +- `POST /transfer-in` — **Deprecated.** Same-currency external → internal; use `/quotes` ### Quote Request Shape diff --git a/mintlify/api-reference/sandbox-testing.mdx b/mintlify/api-reference/sandbox-testing.mdx index 83965cbc5..0258df9ce 100644 --- a/mintlify/api-reference/sandbox-testing.mdx +++ b/mintlify/api-reference/sandbox-testing.mdx @@ -23,23 +23,20 @@ The Grid sandbox environment simulates real payment flows without moving real mo -### Beneficiary name verification - - - -## Transfer in - -In production, internal accounts are funded by sending a bank transfer to the account's payment instructions or by pulling from an external account. In sandbox, you have two options: + -### Transfer in from an external account +These outcomes apply whenever the account is used, as the source of a pull or the +destination of a payout. -Use the `/transfer-in` endpoint to pull funds from an external account into an internal account. The external account's number suffix determines the outcome: +### Beneficiary name verification - + -### Sandbox fund endpoint +## Funding an internal account -Instantly add funds to any internal account using `/sandbox/internal-accounts/{accountId}/fund`: +Internal accounts are funded from their payment instructions or by pulling from an external +account — see [Internal Accounts](/payouts-and-b2b/depositing-funds/internal-accounts) for +both. Sandbox adds a shortcut that skips the wait: ```bash curl -X POST https://api.lightspark.com/grid/2025-10-13/sandbox/internal-accounts/{accountId}/fund \ @@ -48,7 +45,10 @@ curl -X POST https://api.lightspark.com/grid/2025-10-13/sandbox/internal-account -d '{ "amount": 100000 }' ``` -## Creating quotes (cross-currency transfers) +To exercise the pull path instead, create a quote with an external account as the source and +`immediatelyExecute` set to `true`. The account's suffix decides the outcome. + +## Creating quotes @@ -56,7 +56,7 @@ curl -X POST https://api.lightspark.com/grid/2025-10-13/sandbox/internal-account After creating a quote, you need to fund it to trigger execution. There are two ways to do this in sandbox: -**Prefunded internal account** — If your quote's source is an internal account, fund the account using one of the methods described in [transfer in](#transfer-in), then call the quote execute endpoint to trigger the transaction: +**Prefunded internal account** — If your quote's source is an internal account, fund the account using one of the methods described in [funding an internal account](#funding-an-internal-account), then call the quote execute endpoint to trigger the transaction: ```bash curl -X POST https://api.lightspark.com/grid/2025-10-13/quotes/{quoteId}/execute \ @@ -75,10 +75,6 @@ curl -X POST https://api.lightspark.com/grid/2025-10-13/sandbox/send \ }' ``` -## Transferring out funds - -Use the `/transfer-out` endpoint to push funds from an internal account to an external account in the same currency. The external account's number suffix controls the outcome using the same patterns as [transfer in](#transfer-in-from-an-external-account). - ## Sending to a UMA address diff --git a/mintlify/changelog.mdx b/mintlify/changelog.mdx index ea908e117..e5678f5b9 100644 --- a/mintlify/changelog.mdx +++ b/mintlify/changelog.mdx @@ -11,6 +11,25 @@ changes and roadmap, [book a live demo](https://www.lightspark.com/contact) or +## `/transfer-in` and `/transfer-out` are deprecated + +Same-currency transfers now go through the quote endpoint, so one integration covers +same-currency and cross-currency alike. + +- Use `POST /quotes` with `immediatelyExecute: true` to create and execute a + same-currency transfer in a single request. +- `amount` becomes `lockedCurrencyAmount` with `lockedCurrencySide: "SENDING"`; source + and destination gain `sourceType: "ACCOUNT"` and `destinationType: "ACCOUNT"`. + `remittanceInformation`, `purposeOfPayment`, and the destination `paymentRail` carry + over unchanged. +- The response is a `Quote` rather than a `Transaction`—read `transactionId` from it to + track the resulting transaction. +- `POST /transfer-in` and `POST /transfer-out` continue to work with unchanged request + and response shapes. + +See [Send a payment](/payouts-and-b2b/payment-flow/send-payment#send-a-payment) +for the updated flow. + ## Assess your own fees on every transaction Charge your customers a platform fee and keep the margin—Grid collects it for you and diff --git a/mintlify/global-accounts/agents/approvals-and-audit.mdx b/mintlify/global-accounts/agents/approvals-and-audit.mdx index 34a5ce1d0..c178d608c 100644 --- a/mintlify/global-accounts/agents/approvals-and-audit.mdx +++ b/mintlify/global-accounts/agents/approvals-and-audit.mdx @@ -50,9 +50,8 @@ An approval is not always a guarantee that the action will execute. Your product - `agentId` — the agent that submitted the action - `customerId` / `platformCustomerId` — the customer on whose behalf the agent acted - `status` — `PENDING_APPROVAL` while awaiting a decision; transitions to `APPROVED`, `REJECTED`, or `FAILED` -- `type` — `EXECUTE_QUOTE`, `TRANSFER_OUT`, or `TRANSFER_IN` -- `quote` — for `EXECUTE_QUOTE` actions, the full quote object including amounts, currencies, exchange rate, and destination -- `transferDetails` — for `TRANSFER_OUT` / `TRANSFER_IN` actions, amount, currency, and source/destination account IDs +- `type` — `EXECUTE_QUOTE` +- `quote` — the full quote object including amounts, currencies, exchange rate, and destination - `transaction` — populated after the action is approved and execution begins; absent while pending or rejected - `rejectionReason` — optional reason string set when your platform rejects the action - `createdAt` / `updatedAt` — timestamps for the action lifecycle diff --git a/mintlify/global-accounts/agents/policies-and-permissions.mdx b/mintlify/global-accounts/agents/policies-and-permissions.mdx index 965a96736..f6cd747e6 100644 --- a/mintlify/global-accounts/agents/policies-and-permissions.mdx +++ b/mintlify/global-accounts/agents/policies-and-permissions.mdx @@ -37,9 +37,8 @@ Grid exposes explicit allowlists instead of broad agent access. Available permis | Permission | What it allows | |---|---| | `VIEW_TRANSACTIONS` | List and retrieve transactions and account balances | -| `CREATE_TRANSFERS` | Initiate same-currency transfers | -| `CREATE_QUOTES` | Create cross-currency quotes | -| `EXECUTE_QUOTES` | Execute cross-currency quotes | +| `CREATE_QUOTES` | Create quotes | +| `EXECUTE_QUOTES` | Execute quotes | | `MANAGE_EXTERNAL_ACCOUNTS` | Create and manage external accounts | These permissions are intentionally narrow and map to concrete Grid-backed actions rather than broad scopes such as "manage wallet." diff --git a/mintlify/global-p2p/sending-receiving-payments/sending-payments.mdx b/mintlify/global-p2p/sending-receiving-payments/sending-payments.mdx index d8e1b6b9d..450228c03 100644 --- a/mintlify/global-p2p/sending-receiving-payments/sending-payments.mdx +++ b/mintlify/global-p2p/sending-receiving-payments/sending-payments.mdx @@ -3,25 +3,23 @@ title: "Sending Payments" icon: "/images/icons/paper-plane-top-right.svg" "og:image": "/images/og/og-global-p2p.png" --- -This guide covers three methods to send payments: +Every payment goes through `POST /quotes`. What changes is where you are sending: -1. Same-currency transfer to an external account -2. Cross-currency transfer with a quote -3. Sending to an UMA address +1. To an account — internal or external, with or without currency conversion +2. To an UMA address ## Choosing the right method -- **Same-currency**: Best for domestic payouts when sender and recipient use the same currency. Uses local payment rails (e.g., RTP, SEPA Instant, PIX, FPS) for low cost and fast settlement. -- **Cross-currency**: Use when conversion is required or when paying globally across borders. Also supports sending to a crypto wallet address when configured. +- **Account**: Pay an internal or external account. Grid converts when the currencies differ and settles over local payment rails (e.g., ACH, RTP, SEPA Instant, PIX, FPS) when they match. Also covers sending to a crypto wallet address when configured. - **UMA**: Send using a Universal Money Address. Ideal for global counterparties on networks. -import SameCurrency from '/snippets/sending/same-currency.mdx' +import SendToAccount from '/snippets/sending/accounts.mdx' - + -import CrossCurrency from '/snippets/sending/cross-currency.mdx' +import CryptoFunding from '/snippets/sending/crypto-funding.mdx' - + import SendUMA from '/snippets/sending/uma.mdx' diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index 51644742f..21f570d74 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -36,9 +36,9 @@ tags: - name: VASPs description: Directory of Virtual Asset Service Providers (exchanges and other custodial platforms) recognized for counterparty declarations. - name: Same-Currency Transfers - description: Endpoints for transferring funds between internal and external accounts with the same currency + description: Deprecated endpoints for transferring funds between internal and external accounts with the same currency. Use the quote endpoints under Cross-Currency Transfers instead, which now serve same-currency transfers as well. - name: Cross-Currency Transfers - description: Endpoints for creating and confirming quotes for cross-currency transfers + description: Endpoints for creating and confirming quotes for transfers, both same-currency and cross-currency - name: Transactions description: Endpoints for retrieving transaction information - name: Webhooks @@ -3593,8 +3593,29 @@ paths: /transfer-in: post: summary: Create a transfer-in request + deprecated: true description: | - Transfer funds from an external account to an internal account for a specific customer. This endpoint should only be used for external account sources with pull functionality (e.g. ACH Pull). Otherwise, use the paymentInstructions on the internal account to deposit funds. + **Deprecated. Use `POST /quotes` instead.** + + Same-currency transfers are now served by the quote endpoint. Create a quote + with an external account source and an internal account destination and set + `immediatelyExecute: true` to move the funds in a single request, exactly as + this endpoint does. This endpoint continues to work and its request and + response shapes are unchanged. + + To migrate a request to `POST /quotes`: + + - add `sourceType: ACCOUNT` to `source` and `destinationType: ACCOUNT` to + `destination`; the account IDs are unchanged + - rename `amount` to `lockedCurrencyAmount` and add `lockedCurrencySide: SENDING` + - add `immediatelyExecute: true` to keep the single-request behavior + + The quote response is a `Quote` rather than a `Transaction`; read + `transactionId` from it to track the resulting transaction. + + Transfer funds from an external account to an internal account for a specific customer. + This endpoint should only be used for external account sources with pull functionality (e.g. ACH Pull). + Otherwise, use the paymentInstructions on the internal account to deposit funds. operationId: createTransferIn tags: - Same-Currency Transfers @@ -3658,7 +3679,27 @@ paths: /transfer-out: post: summary: Create a transfer-out request + deprecated: true description: | + **Deprecated. Use `POST /quotes` instead.** + + Same-currency transfers are now served by the quote endpoint. Create a quote + with an internal account source and an external account destination and set + `immediatelyExecute: true` to move the funds in a single request, exactly as + this endpoint does. This endpoint continues to work and its request and + response shapes are unchanged. + + To migrate a request to `POST /quotes`: + + - add `sourceType: ACCOUNT` to `source` and `destinationType: ACCOUNT` to + `destination`; the account IDs and `destination.paymentRail` are unchanged + - rename `amount` to `lockedCurrencyAmount` and add `lockedCurrencySide: SENDING` + - `remittanceInformation` and `purposeOfPayment` carry over unchanged + - add `immediatelyExecute: true` to keep the single-request behavior + + The quote response is a `Quote` rather than a `Transaction`; read + `transactionId` from it to track the resulting transaction. + Transfer funds from an internal account to an external account for a specific customer. operationId: createTransferOut tags: @@ -3924,12 +3965,12 @@ paths: post: summary: Create a transfer quote description: | - Generate a quote for a cross-currency transfer between any combination of accounts - and UMA addresses. This endpoint handles currency exchange and provides the necessary - instructions to execute the transfer. + Generate a quote for a transfer between any combination of accounts + and UMA addresses. This endpoint handles same-currency and cross-currency + transfers alike, and provides the necessary instructions to execute the transfer. **Transfer Types Supported:** - - **Account to Account**: Transfer between internal/external accounts with currency exchange. + - **Account to Account**: Transfer between internal/external accounts, with or without currency exchange. - **Account to UMA**: Transfer from an internal account to an UMA address. - **UMA to Account or UMA to UMA**: This transfer type will only be funded by payment instructions, not from an internal account. @@ -3938,8 +3979,9 @@ paths: - **Currency Exchange**: Handles all cross-currency transfers with real-time exchange rates - **Payment Instructions**: For UMA or customer ID sources, provides banking details needed for execution - **Important:** If you are transferring funds in the same currency (no exchange required), - use the `/transfer-in` or `/transfer-out` endpoints instead. + **Same-currency transfers:** Use this endpoint for same-currency transfers too. + Set `immediatelyExecute: true` to create and execute in a single request. The + older `/transfer-in` and `/transfer-out` endpoints are deprecated. Requires a token with the `TRANSACT` permission; `VIEW` alone is not sufficient. A quote is the instrument a later execute draws on, and @@ -3965,6 +4007,21 @@ paths: schema: $ref: '#/components/schemas/QuoteRequest' examples: + sameCurrencyAccountToAccount: + summary: Same-Currency Account to Account Transfer (immediate execution) + value: + source: + sourceType: ACCOUNT + accountId: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 + destination: + destinationType: ACCOUNT + accountId: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 + paymentRail: ACH + lockedCurrencySide: SENDING + lockedCurrencyAmount: 12550 + immediatelyExecute: true + remittanceInformation: INV-12345 + description: Same-currency payout, no exchange required. accountToAccount: summary: Account to Account Transfer value: @@ -8054,151 +8111,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' - /agents/me/transfer-in: - post: - summary: Create a transfer-in - description: | - Transfer funds from an external account to an internal account for the authenticated agent's customer. Accounts must belong to the agent's customer. Requires the CREATE_TRANSFERS permission in the agent's policy. - If the agent's policy requires approval for this amount, the transaction will be created in a pending state and must be approved by the platform via `POST /agents/{agentId}/actions/{actionId}/approve`. - This endpoint should only be used for external account sources with pull functionality (e.g. ACH Pull). Otherwise, use the payment instructions on the internal account to deposit funds. - operationId: agentCreateTransferIn - tags: - - Agent Operations - security: - - AgentAuth: [] - parameters: - - name: Idempotency-Key - in: header - required: false - description: | - A unique identifier for the request. If the same key is sent multiple times, the server will return the same response as the first request. - schema: - type: string - example: 550e8400-e29b-41d4-a716-446655440000 - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TransferInRequest' - examples: - transferIn: - summary: Transfer from external to internal account - value: - source: - accountId: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 - destination: - accountId: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 - amount: 12550 - responses: - '201': - description: Action submitted successfully. If the agent's policy requires approval, the returned `AgentAction` will have status `PENDING_APPROVAL` and no `transaction` yet. If the policy permits automatic execution, status will be `APPROVED` and `transaction` will be populated. - content: - application/json: - schema: - $ref: '#/components/schemas/AgentAction' - '400': - description: Bad request - Invalid parameters - content: - application/json: - schema: - $ref: '#/components/schemas/Error400' - '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error401' - '403': - description: Forbidden - Agent policy does not permit this operation or spending limit exceeded - content: - application/json: - schema: - $ref: '#/components/schemas/Error403' - '404': - description: Account not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404' - '500': - description: Internal service error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500' - /agents/me/transfer-out: - post: - summary: Create a transfer-out - description: | - Transfer funds from an internal account to an external account for the authenticated agent's customer. Accounts must belong to the agent's customer. Requires the CREATE_TRANSFERS permission in the agent's policy. - If the agent's policy requires approval for this amount, the transaction will be created in a pending state and must be approved by the platform via `POST /agents/{agentId}/actions/{actionId}/approve`. - operationId: agentCreateTransferOut - tags: - - Agent Operations - security: - - AgentAuth: [] - parameters: - - name: Idempotency-Key - in: header - required: false - description: | - A unique identifier for the request. If the same key is sent multiple times, the server will return the same response as the first request. - schema: - type: string - example: 550e8400-e29b-41d4-a716-446655440000 - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TransferOutRequest' - examples: - transferOut: - summary: Transfer from internal to external account - value: - source: - accountId: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 - destination: - accountId: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 - amount: 12550 - responses: - '201': - description: Action submitted successfully. If the agent's policy requires approval, the returned `AgentAction` will have status `PENDING_APPROVAL` and no `transaction` yet. If the policy permits automatic execution, status will be `APPROVED` and `transaction` will be populated. - content: - application/json: - schema: - $ref: '#/components/schemas/AgentAction' - '400': - description: Bad request - Invalid parameters - content: - application/json: - schema: - $ref: '#/components/schemas/Error400' - '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error401' - '403': - description: Forbidden - Agent policy does not permit this operation or spending limit exceeded - content: - application/json: - schema: - $ref: '#/components/schemas/Error403' - '404': - description: Account not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404' - '500': - description: Internal service error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500' /agents/me/internal-accounts: get: summary: List agent's internal accounts @@ -23879,11 +23791,10 @@ components: type: string enum: - VIEW_TRANSACTIONS - - CREATE_TRANSFERS - CREATE_QUOTES - EXECUTE_QUOTES - MANAGE_EXTERNAL_ACCOUNTS - description: 'Permission granted to an agent that determines what actions it can perform. VIEW_TRANSACTIONS: Can list and retrieve transactions and account balances. CREATE_TRANSFERS: Can initiate same-currency transfers. CREATE_QUOTES: Can create cross-currency quotes. EXECUTE_QUOTES: Can execute cross-currency quotes. MANAGE_EXTERNAL_ACCOUNTS: Can create and manage external accounts.' + description: 'Permission granted to an agent that determines what actions it can perform. VIEW_TRANSACTIONS: Can list and retrieve transactions and account balances. CREATE_QUOTES: Can create quotes. EXECUTE_QUOTES: Can execute quotes. MANAGE_EXTERNAL_ACCOUNTS: Can create and manage external accounts.' AgentExecutionMode: type: string enum: @@ -24161,42 +24072,12 @@ components: type: string enum: - EXECUTE_QUOTE - - TRANSFER_OUT - - TRANSFER_IN description: | The type of action the agent is requesting. | Type | Description | |------|-------------| - | `EXECUTE_QUOTE` | Execute a cross-currency quote | - | `TRANSFER_OUT` | Transfer from an internal account to an external account | - | `TRANSFER_IN` | Transfer from an external account to an internal account | - AgentTransferDetails: - type: object - description: Details of a transfer-type agent action (TRANSFER_OUT or TRANSFER_IN). - required: - - amount - - currency - - sourceAccountId - - destinationAccountId - properties: - amount: - type: integer - format: int64 - description: Transfer amount in the smallest unit of the specified currency. - example: 50000 - currency: - type: string - description: ISO 4217 currency code for the transfer amount. - example: USD - sourceAccountId: - type: string - description: ID of the source account (internal or external). - example: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 - destinationAccountId: - type: string - description: ID of the destination account (internal or external). - example: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 + | `EXECUTE_QUOTE` | Execute a quote | AgentAction: type: object description: An action submitted by an agent that may require platform approval before execution. All agent-initiated operations (quote execution, transfers) are represented as AgentActions, giving the platform a consistent object to approve, reject, and audit regardless of the underlying operation type. @@ -24233,11 +24114,7 @@ components: quote: allOf: - $ref: '#/components/schemas/Quote' - description: The quote being executed. Populated for `EXECUTE_QUOTE` actions; absent for transfer actions. Contains the full amount, currency, destination, and rate details needed to present an approval decision to the user. - transferDetails: - allOf: - - $ref: '#/components/schemas/AgentTransferDetails' - description: Details of the transfer being requested. Populated for `TRANSFER_OUT` and `TRANSFER_IN` actions; absent for `EXECUTE_QUOTE` actions. + description: The quote being executed. Contains the full amount, currency, destination, and rate details needed to present an approval decision to the user. transaction: allOf: - $ref: '#/components/schemas/TransactionOneOf' diff --git a/mintlify/payouts-and-b2b/payment-flow/send-payment.mdx b/mintlify/payouts-and-b2b/payment-flow/send-payment.mdx index bfcf16a1d..261bf3656 100644 --- a/mintlify/payouts-and-b2b/payment-flow/send-payment.mdx +++ b/mintlify/payouts-and-b2b/payment-flow/send-payment.mdx @@ -1,26 +1,35 @@ --- title: "Sending Payments" -description: "Learn how to send payments from internal accounts to external bank accounts with same-currency and cross-currency transfers" +description: "Learn how to send payments between accounts" icon: "/images/icons/paper-plane-top-right.svg" "og:image": "/images/og/og-payouts-b2b.png" --- import { FeatureCard, FeatureCardGrid } from '/snippets/feature-card.mdx'; -Send payments from your customers' internal accounts to their external bank accounts or to other destinations. Grid supports both same-currency transfers and cross-currency transfers with automatic exchange rate handling. +Send payments between internal and external accounts, with automatic exchange rate handling when the currencies differ. ## Overview -Grid provides two payment methods depending on your use case: +Every payment goes through `POST /quotes`, whether or not the currencies differ. A quote +prices the transfer — the amounts, the fees, and, when the currencies differ, the exchange +rate — and creates the transaction that carries the money. - - - Send funds in the same currency from an internal account to an external account. Fast and straightforward. - - - Send funds with currency conversion using real-time exchange rates. Supports multiple fiat currencies and payment rails. - - +What varies is when you execute it: + +- **In one request.** Set `immediatelyExecute` and Grid creates and executes the quote + together. Use this when you don't need to put rate or fee details in front of your user + before the money moves. +- **In two steps.** Create the quote, show your user what the transfer will cost, then call + execute before the quote expires. Use this whenever your UX surfaces rates or fees — which + includes same-currency transfers, where there is no exchange rate but there can still be + fees worth showing. + +Either way the request shape is the same, and the payment rail is chosen from the +destination account. + +The same endpoint sends to UMA addresses by giving the quote a `UMA_ADDRESS` destination. +See [Sending payments](/global-p2p/sending-receiving-payments/sending-payments) for that flow. ## Prerequisites @@ -37,17 +46,7 @@ Before sending payments, ensure you have: Accounts](/payouts-and-b2b/depositing-funds/external-accounts) guides first. -## Same-Currency Transfers - -Use the `/transfer-out` endpoint when sending funds in the same currency (no exchange rate needed). This is the simplest and fastest option for domestic transfers. - -### When to use same-currency transfers - -- Transferring USD from a USD internal account to a USD external account -- Sending funds within the same country using the same payment rail -- No currency conversion is required - -### Create a transfer +## Send a payment @@ -62,142 +61,8 @@ Note the `id` fields from both the internal and external accounts you want to us - - Create the transfer by specifying the source and destination accounts: - -```bash cURL -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/transfer-out' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "source": { - "accountId": "InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123" - }, - "destination": { - "accountId": "ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965", - "paymentRail": "ACH" - }, - "amount": 12550, - "remittanceInformation": "INV-12345" - }' -``` - - - The `paymentRail` field is optional. If omitted, Grid selects a default rail for the destination. Specify a rail (e.g., `ACH`, `WIRE`, `RTP`, `FEDNOW`) when you need to control which payment network processes the transfer. - - - - `remittanceInformation` is optional. Use it to send a reference that travels with the payment to the recipient (max 80 characters). This populates the ACH Addenda record, FedNow/RTP remittance information, or wire OBI field depending on the payment rail. - - - - `purposeOfPayment` is optional and accepts the same values as on a quote. Some destinations - require it, and some rails carry it on the payment itself. - - - -```json Success (201 Created) -{ - "id": "Transaction:019542f5-b3e7-1d02-0000-000000000015", - "status": "PENDING", - "type": "OUTGOING", - "direction": "DEBIT", - "source": { - "accountId": "InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123", - "currency": "USD" - }, - "destination": { - "accountId": "ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965", - "currency": "USD" - }, - "sentAmount": { - "amount": 12550, - "currency": { - "code": "USD", - "name": "United States Dollar", - "symbol": "$", - "decimals": 2 - } - }, - "receivedAmount": { - "amount": 12550, - "currency": { - "code": "USD", - "name": "United States Dollar", - "symbol": "$", - "decimals": 2 - } - }, - "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001", - "platformCustomerId": "customer_12345", - "createdAt": "2025-10-03T15:00:00Z", - "settledAt": null -} -``` - - - The `amount` is specified in the smallest unit of the currency (cents for USD, pence for GBP, etc.). For example, `12550` represents $125.50 USD. - - - - - The transaction is created with a `PENDING` status and progresses through `PROCESSING` to `COMPLETED` or `FAILED`. Monitor the status by: - -You'll receive `OUTGOING_PAYMENT.` webhooks as the transaction progresses. The webhook body contains the full transaction resource: - -```json -{ - "type": "OUTGOING_PAYMENT.COMPLETED", - "data": { - "id": "Transaction:019542f5-b3e7-1d02-0000-000000000015", - "status": "COMPLETED", - "type": "OUTGOING", - "direction": "DEBIT", - "sentAmount": { "amount": 12550, "currency": { "code": "USD", "decimals": 2 } }, - "receivedAmount": { "amount": 12550, "currency": { "code": "USD", "decimals": 2 } }, - "settledAt": "2025-10-03T15:02:30Z" - }, - "timestamp": "2025-10-03T15:03:00Z" -} -``` - -If a transaction fails, Grid initiates a refund automatically. You'll receive `OUTGOING_PAYMENT.REFUND_PENDING` followed by `OUTGOING_PAYMENT.REFUND_COMPLETED` or `OUTGOING_PAYMENT.REFUND_FAILED`. The transaction's `refund` object tracks the refund status and reference. - - - For the full state diagram, refund object details, and all webhook scenarios (including bank returns and manual cancellations), see the [Transaction Lifecycle](/platform-overview/core-concepts/transaction-lifecycle) guide. - - - - -### Transaction statuses - -| Status | Description | -| ------------ | --------------------------------------------- | -| `PENDING` | Transfer initiated and awaiting processing | -| `EXPIRED` | Quote wasn't executed before the expiry window | -| `PROCESSING` | Transfer in progress through the payment rail | -| `COMPLETED` | Transfer successfully completed | -| `FAILED` | Transfer failed — accompanied by a `failureReason` | - - -For the full state diagram including refund tracking and edge cases like bank returns, see the [Transaction Lifecycle](/platform-overview/core-concepts/transaction-lifecycle) guide. - - -## Cross-Currency Transfers - -Use the quotes flow when sending funds with currency conversion. This locks in an exchange rate and provides all details needed to execute the transfer. - -### When to use cross-currency transfers - -- Converting USD to EUR, MXN, BRL, or other supported currencies -- Sending international payments with automatic currency conversion -- Need to lock in a specific exchange rate for the transfer - -### Create and execute a quote - - - - Request a quote to lock in the exchange rate and get transfer details: + + Specify the source and destination accounts and the amount to lock: ```bash cURL curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ @@ -210,10 +75,12 @@ curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ }, "destination": { "destinationType": "ACCOUNT", - "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123" + "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123", + "paymentRail": "ACH" }, "lockedCurrencySide": "SENDING", "lockedCurrencyAmount": 10000, + "remittanceInformation": "INV-12345", "description": "Payment for services - Invoice #1234" }' ``` @@ -254,69 +121,68 @@ curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ } ``` + + **Same-currency transfers use this exact request.** The two currencies simply match, and + the quote comes back with an `exchangeRate` of `1` — the fee fields are still populated. + Add `"immediatelyExecute": true` to create and execute in this one request and skip the + next two steps. + + **Locked currency side** determines which amount is fixed: - `SENDING`: Lock the sending amount (receiving amount calculated based on exchange rate) - `RECEIVING`: Lock the receiving amount (sending amount calculated based on exchange rate) + + + The `paymentRail` field is optional. If omitted, Grid selects a default rail for the destination. Specify a rail (e.g., `ACH`, `WIRE`, `RTP`, `FEDNOW`) when you need to control which payment network processes the transfer. + + + + `remittanceInformation` is optional. Use it to send a reference that travels with the payment to the recipient (max 80 characters). This populates the ACH Addenda record, FedNow/RTP remittance information, or wire OBI field depending on the payment rail. + + + + `purposeOfPayment` is optional. Some destinations require it, and some rails carry it on + the payment itself. + + + + Amounts are specified in the smallest unit of the currency (cents for USD, pence for GBP, etc.). For example, `12550` represents $125.50 USD. + - - Before executing, review the quote to ensure: + + Before executing, check that: -- Exchange rate is acceptable +- The exchange rate is acceptable - Fees are as expected -- Receiving amount meets requirements -- Quote hasn't expired (check `expiresAt`) +- The receiving amount meets requirements +- The quote hasn't expired (check `expiresAt`) Quote expiration depends on the corridor but is typically ~5 minutes or greater. If expired, create a new quote to get an updated exchange rate. + + + Skip this step by setting `immediatelyExecute` on the quote. A same-currency quote has no + exchange rate to review, but check `feesIncluded` if your UX shows the customer what the + transfer costs. + Confirm and execute the quote to initiate the transfer: - ```bash cURL curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes/Quote:019542f5-b3e7-1d02-0000-000000000025/execute' \ -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" ``` -```json Success (200 OK) -{ - "id": "Quote:019542f5-b3e7-1d02-0000-000000000025", - "status": "PROCESSING", - "createdAt": "2025-10-03T15:00:00Z", - "expiresAt": "2025-10-03T15:15:00Z", - "source": { - "sourceType": "ACCOUNT", - "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965" - }, - "destination": { - "destinationType": "ACCOUNT", - "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123" - }, - "sendingCurrency": { - "code": "USD", - "name": "United States Dollar", - "symbol": "$", - "decimals": 2 - }, - "receivingCurrency": { - "code": "EUR", - "name": "Euro", - "symbol": "€", - "decimals": 2 - }, - "totalSendingAmount": 10000, - "totalReceivingAmount": 9200, - "exchangeRate": 0.92, - "feesIncluded": 50, - "platformFeesIncluded": 0, - "transactionId": "Transaction:019542f5-b3e7-1d02-0000-000000000030" -} -``` +The quote comes back with `status` `PROCESSING` and the same `transactionId` it carried at +creation — unless the customer requires +[Strong Customer Authentication](/platform-overview/core-concepts/quote-system), in which +case it returns `PENDING_AUTHORIZATION` and the transfer waits on that. Once executed, the quote creates a transaction and the transfer begins processing. The `transactionId` can be used to track the payment. @@ -364,13 +230,17 @@ If a transaction fails, Grid initiates a refund automatically. You'll receive `O ### Transaction statuses -| Status | Description | -| ------------ | ------------------------------------------ | -| `PENDING` | Quote created, awaiting execution | -| `PROCESSING` | Quote executed, transfer in progress | -| `COMPLETED` | Transfer successfully completed | -| `FAILED` | Transfer failed — refund initiated automatically (track via `refund` object) | -| `EXPIRED` | Quote expired without execution | +| Status | Description | +| ------------ | --------------------------------------------- | +| `PENDING` | Quote created, awaiting execution | +| `PROCESSING` | Quote executed, transfer in progress through the payment rail | +| `COMPLETED` | Transfer successfully completed | +| `FAILED` | Transfer failed — accompanied by a `failureReason`, and a refund is initiated automatically (track via the `refund` object) | +| `EXPIRED` | Quote wasn't executed before the expiry window | + + +For the full state diagram including refund tracking and edge cases, see the [Transaction Lifecycle](/platform-overview/core-concepts/transaction-lifecycle) guide. + ## Checking Payment Status diff --git a/mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx b/mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx index 2170b9d21..7bea16655 100644 --- a/mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx +++ b/mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx @@ -53,7 +53,7 @@ curl -X POST https://api.lightspark.com/grid/2025-10-13/sandbox/internal-account This endpoint returns the updated `InternalAccount` object with the new balance. -Alternatively, you can also fund internal accounts using the `/quotes` or `/transfer-in` endpoints as described below. +Alternatively, you can also fund internal accounts using the `/quotes` endpoint as described below. ## Testing Transfer Scenarios @@ -65,45 +65,36 @@ Alternatively, you can also fund internal accounts using the `/quotes` or `/tran -### Testing Transfer-In (Pull from External Account) +### Testing Transfer Outcomes -When you call `/transfer-in` with an external account created using test patterns, the transfer will complete instantly in sandbox with the behavior determined by the account number: - -```bash -POST /transfer-in - -{ - "source": { - "accountId": "ExternalAccount:abc123" // Uses test pattern from creation - }, - "destination": { - "accountId": "InternalAccount:xyz789" - }, - "amount": 10000 // $100 in cents -} -``` +The external account's test pattern determines the outcome whenever that account is used, +whether you are pushing funds to it or pulling funds from it: -### Testing Transfer-Out (Push to External Account) - -Transfer-out works the same way - the destination external account's test pattern determines the outcome: +Create a quote with the external account on the side you want to test and +`immediatelyExecute` set to `true`: ```bash -POST /transfer-out +POST /quotes { "source": { + "sourceType": "ACCOUNT", "accountId": "InternalAccount:xyz789" }, "destination": { - "accountId": "ExternalAccount:abc123" // Uses test pattern + "destinationType": "ACCOUNT", + "accountId": "ExternalAccount:abc123" // Uses test pattern from creation }, - "amount": 10000 + "lockedCurrencySide": "SENDING", + "lockedCurrencyAmount": 10000, // $100 in cents + "immediatelyExecute": true } ``` -The transfer will instantly simulate the bank transfer process and complete with the appropriate status based on the external account's test pattern. +Swap the two `accountId` values to pull from the external account instead. Either way the +transfer completes instantly in sandbox with the status the pattern dictates. ## Testing Cross-Currency Quotes @@ -229,22 +220,22 @@ Test each failure mode systematically: # Create external account ending in 002 POST /customers/external-accounts { "accountNumber": "000000002" } -# Attempt transfer-in - should fail immediately -POST /transfer-in +# Attempt to pull from it - should fail immediately +POST /quotes # 2. Test account closed # Create external account ending in 003 POST /customers/external-accounts { "accountNumber": "000000003" } -# Attempt transfer-out - should fail immediately -POST /transfer-out +# Attempt to push to it - should fail immediately +POST /quotes # 3. Test timeout scenario # Create external account ending in 005 POST /customers/external-accounts { "accountNumber": "000000005" } # Attempt transfer - should pend then fail after ~30s -POST /transfer-in +POST /quotes # Check status immediately - will show PENDING GET /transactions/{transactionId} # Wait 30s, check again - will show FAILED diff --git a/mintlify/platform-overview/core-concepts/account-model.mdx b/mintlify/platform-overview/core-concepts/account-model.mdx index e1089349e..c6559d1e1 100644 --- a/mintlify/platform-overview/core-concepts/account-model.mdx +++ b/mintlify/platform-overview/core-concepts/account-model.mdx @@ -218,19 +218,9 @@ You'll receive `INTERNAL_ACCOUNT.BALANCE_UPDATED` webhooks as balance changes, a - Send funds from internal account to external account: - - ```bash - POST /transfer-out - - { - "source": {"accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965"}, - "destination": {"accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123"}, - "amount": 100000 - } - ``` - - Or via quote for cross-currency: + Send funds from internal account to external account. Use `/quotes` for both + same-currency and cross-currency payouts; `immediatelyExecute` moves the funds + in the same request: ```bash POST /quotes @@ -239,21 +229,27 @@ You'll receive `INTERNAL_ACCOUNT.BALANCE_UPDATED` webhooks as balance changes, a "source": {"sourceType": "ACCOUNT", "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965"}, "destination": {"destinationType": "ACCOUNT", "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123"}, "lockedCurrencySide": "SENDING", - "lockedCurrencyAmount": 100000 + "lockedCurrencyAmount": 100000, + "immediatelyExecute": true } ``` + + Omit `immediatelyExecute` to review the rate and fees first, then call + `POST /quotes/{quoteId}/execute`. Pull funds from external account to internal account: ```bash - POST /transfer-in + POST /quotes { - "source": {"accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123"}, - "destination": {"accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965"}, - "amount": 100000 + "source": {"sourceType": "ACCOUNT", "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123"}, + "destination": {"destinationType": "ACCOUNT", "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965"}, + "lockedCurrencySide": "SENDING", + "lockedCurrencyAmount": 100000, + "immediatelyExecute": true } ``` diff --git a/mintlify/platform-overview/core-concepts/quote-system.mdx b/mintlify/platform-overview/core-concepts/quote-system.mdx index 766761168..e7ef7cd82 100644 --- a/mintlify/platform-overview/core-concepts/quote-system.mdx +++ b/mintlify/platform-overview/core-concepts/quote-system.mdx @@ -5,7 +5,7 @@ description: "How exchange rates, pricing, and payment execution work" "og:image": "/images/og/og-get-started.png" --- -Quotes are Grid's mechanism for providing locked-in exchange rates, transparent fee calculations, and payment instructions. Understanding quotes is essential for all cross-currency or crypto-involved transactions. +Quotes are Grid's mechanism for providing locked-in exchange rates, transparent fee calculations, and payment instructions. Every transfer goes through a quote, whether or not a currency conversion is involved. ## What is a Quote? @@ -20,26 +20,25 @@ Quotes ensure that your customers know exactly what they'll pay and what the rec ## When Do You Need a Quote? - - - Use quotes for: - - **Cross-currency transfers** (USD → EUR, BRL → MXN) - - **Fiat-to-crypto conversion** (USD → BTC) - - **Crypto-to-fiat conversion** (BTC → USD) - - **UMA payments** (always require quotes) - - **JIT funded payments** (need payment instructions) - - These scenarios involve currency conversion, exchange rate risk, or complex routing. - +Use `POST /quotes` for every transfer: - - For same-currency transfers, use simpler endpoints: - - `POST /transfer-out` - Send from internal to external account (same currency) - - `POST /transfer-in` - Pull from external to internal account (same currency) +- **Cross-currency transfers** (USD → EUR, BRL → MXN) +- **Fiat-to-crypto conversion** (USD → BTC) +- **Crypto-to-fiat conversion** (BTC → USD) +- **UMA payments** +- **JIT funded payments** (need payment instructions) +- **Same-currency transfers** (USD → USD), including pulling funds from a + pullable external account into an internal account - No quote needed because there's no currency conversion. - - +For a same-currency transfer there is no exchange rate to lock, so the two-step +create-then-execute flow rarely buys you anything. Set `immediatelyExecute` to +`true` and the quote is created and executed in a single request. + + + The `/transfer-out` and `/transfer-in` endpoints previously served same-currency + transfers and are now deprecated. They still work and their request and response + shapes are unchanged, but new integrations should use `/quotes`. + ## Creating a Quote diff --git a/mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx b/mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx index 4722f551d..6eb992ed3 100644 --- a/mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx +++ b/mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx @@ -72,49 +72,6 @@ Understanding the transaction lifecycle helps you build robust payment flows, ha Most transactions on Grid are completed in seconds. -## Same-Currency Transfers - -For same-currency transfers without quotes: - -### Transfer-Out (Internal → External) - -```bash -POST /transfer-out - -{ - "source": {"accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965"}, - "destination": {"accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123"}, - "amount": 100000 -} -``` - -**Response:** - -```json -{ - "id": "Transaction:...", - "status": "PENDING", - "type": "OUTGOING", - "direction": "DEBIT" -} -``` - -Follows same lifecycle as quote-based outgoing transactions. - -### Transfer-In (External → Internal) - -```bash -POST /transfer-in - -{ - "source": {"accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123"}, - "destination": {"accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965"}, - "amount": 100000 -} -``` - -Only works for "pullable" external accounts (e.g., debit cards). - ## Outgoing Payment Status A single `status` field represents whether the transaction reached its destination: @@ -196,7 +153,7 @@ Where a refund lands depends on how the transaction was funded: - **Real-time (JIT) funding via crypto** (for example USDC or BTC) — the refunded amount is credited to the customer's **internal account balance for that asset**. It is **not** returned to the wallet the funds were sent from. - Crypto deposits are not refunded to the source wallet because Grid cannot verify that the sending wallet belongs to your customer — the funds may have originated from an exchange or another third-party address. The credited internal balance is reusable: spend it with a new quote, or withdraw it to an external wallet with `POST /transfer-out`. + Crypto deposits are not refunded to the source wallet because Grid cannot verify that the sending wallet belongs to your customer — the funds may have originated from an exchange or another third-party address. The credited internal balance is reusable: spend it with a new quote, or withdraw it to an external wallet with a quote whose destination is that wallet. ## Webhooks diff --git a/mintlify/ramps/conversion-flows/self-custody-wallets.mdx b/mintlify/ramps/conversion-flows/self-custody-wallets.mdx index 519d5e015..6018a7609 100644 --- a/mintlify/ramps/conversion-flows/self-custody-wallets.mdx +++ b/mintlify/ramps/conversion-flows/self-custody-wallets.mdx @@ -173,24 +173,25 @@ console.log("Will receive:", `${quote.totalReceivingAmount / 100000000} BTC`); Transfer crypto from internal account to user's wallet: ```javascript -// Same-currency transfer (no quote needed) -const transaction = await fetch( - "https://api.lightspark.com/grid/2025-10-13/transfer-out", - { - method: "POST", - body: JSON.stringify({ - source: { - accountId: "InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123", - }, - destination: { - accountId: externalAccount.id, - }, - amount: 100000, // 0.001 BTC in satoshis - }), - } -).then((r) => r.json()); +// Same-currency transfer: immediatelyExecute creates and executes in one request +const quote = await fetch("https://api.lightspark.com/grid/2025-10-13/quotes", { + method: "POST", + body: JSON.stringify({ + source: { + sourceType: "ACCOUNT", + accountId: "InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123", + }, + destination: { + destinationType: "ACCOUNT", + accountId: externalAccount.id, + }, + lockedCurrencySide: "SENDING", + lockedCurrencyAmount: 100000, // 0.001 BTC in satoshis + immediatelyExecute: true, + }), +}).then((r) => r.json()); -console.log("Transfer initiated:", transaction.id); +console.log("Transfer initiated:", quote.transactionId); ``` ### Step 4: Monitor transfer completion diff --git a/mintlify/ramps/onboarding/implementation-overview.mdx b/mintlify/ramps/onboarding/implementation-overview.mdx index e8f292b3c..0f3c22054 100644 --- a/mintlify/ramps/onboarding/implementation-overview.mdx +++ b/mintlify/ramps/onboarding/implementation-overview.mdx @@ -132,7 +132,7 @@ Implement operational processes to keep your ledger in sync. Use Sandbox to build and validate end‑to‑end without moving real funds. - Simulate fiat funding using `/sandbox/send` endpoint -- Simulate crypto deposits using `/sandbox/internal-accounts/{accountId}/fund` endpoint or `/transfer-in` endpoint +- Simulate crypto deposits using `/sandbox/internal-accounts/{accountId}/fund` endpoint or a `/quotes` call that pulls from a pullable external account - Test quote creation, conversion, and webhook lifecycles - Validate customer onboarding flows with test data diff --git a/mintlify/rewards/platform-tools/sandbox-testing.mdx b/mintlify/rewards/platform-tools/sandbox-testing.mdx index 317fe5d55..6d208dabb 100644 --- a/mintlify/rewards/platform-tools/sandbox-testing.mdx +++ b/mintlify/rewards/platform-tools/sandbox-testing.mdx @@ -154,7 +154,7 @@ Note that these failure test patterns work for any external account type. If you you can create an external account with the appropriate test pattern and use that for the quote source for funding. There are also two other failure test patterns relevant for bank accounts: -- **002**: Insufficient funds (transfer-in will fail) +- **002**: Insufficient funds (pulling from the account will fail) - **004**: Transfer rejected (bank rejects the transfer) ## Testing Customer Onboarding diff --git a/mintlify/snippets/error-handling.mdx b/mintlify/snippets/error-handling.mdx index 9e7173bd1..a7e4d4914 100644 --- a/mintlify/snippets/error-handling.mdx +++ b/mintlify/snippets/error-handling.mdx @@ -98,7 +98,7 @@ async function safeSendPayment(accountId, amount) { ); } - return await createTransferOut({ accountId, amount }); + return await createQuote({ accountId, amount }); } ``` @@ -564,7 +564,7 @@ async function createTransferIdempotent(params) { } try { - const result = await createTransferOut(params); + const result = await createQuote(params); processedTransactions.add(idempotencyKey); return result; } catch (error) { diff --git a/mintlify/snippets/sending/cross-currency.mdx b/mintlify/snippets/sending/accounts.mdx similarity index 56% rename from mintlify/snippets/sending/cross-currency.mdx rename to mintlify/snippets/sending/accounts.mdx index 74ebeb2ef..c273e6bb2 100644 --- a/mintlify/snippets/sending/cross-currency.mdx +++ b/mintlify/snippets/sending/accounts.mdx @@ -1,12 +1,18 @@ -## Cross-Currency Transfers +## Sending to an Account -Use the quotes flow when sending funds with currency conversion. This locks in an exchange rate and provides all details needed to execute the transfer. +Every payment to an internal or external account goes through `POST /quotes`, whether or not +the currencies differ. The quote prices the transfer — amounts, fees, and, when converting, +a locked exchange rate — and creates the transaction that carries the money. -### When to use cross-currency transfers +What varies is when you execute it: -- Converting USD, USDC, USDT to EUR, MXN, BRL, BTC, or other supported fiat and crypto currencies -- Sending international payments with automatic currency conversion -- Need to lock in a specific exchange rate for the transfer +- **In one request.** Set `immediatelyExecute` and Grid creates and executes the quote + together. Use this when you don't need to put rate or fee details in front of your user + before the money moves. +- **In two steps.** Create the quote, show your user what the transfer will cost, then call + execute before the quote expires. Use this whenever your UX surfaces rates or fees — which + includes same-currency transfers, where there is no exchange rate but there can still be + fees worth showing. ### Create and execute a quote @@ -20,9 +26,10 @@ curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ -H 'Content-Type: application/json' \ -d '{ "source": { "sourceType": "ACCOUNT", "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965" }, - "destination": { "destinationType": "ACCOUNT", "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123" }, + "destination": { "destinationType": "ACCOUNT", "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123", "paymentRail": "ACH" }, "lockedCurrencySide": "SENDING", "lockedCurrencyAmount": 10000, + "remittanceInformation": "INV-12345", "description": "Payment for services - Invoice #1234" }' ``` @@ -47,12 +54,27 @@ curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ } ``` + + **Same-currency transfers use this exact request.** The two currencies simply match, and + the quote comes back with an `exchangeRate` of `1` — the fee fields are still populated. + Add `"immediatelyExecute": true` to create and execute in this one request and skip the + next two steps. + + **Locked currency side** determines which amount is fixed: - `SENDING`: Lock the sending amount (receiving amount calculated based on exchange rate) - `RECEIVING`: Lock the receiving amount (sending amount calculated based on exchange rate) + + The `paymentRail` field is optional. If omitted, Grid selects a default rail for the destination. Specify a rail (e.g., `ACH`, `WIRE`, `RTP`, `FEDNOW`) when you need to control which payment network processes the transfer. + + + + `remittanceInformation` is optional. Use it to send a reference that travels with the payment to the recipient (max 80 characters). This populates the ACH Addenda record, FedNow/RTP remittance information, or wire OBI field depending on the payment rail. + + For external account or UMA destinations, some payment corridors require a purpose of payment. Include the `purposeOfPayment` field in the quote request: @@ -85,7 +107,8 @@ curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ - Before executing, review the quote to ensure: + Skip this step and the next by setting `immediatelyExecute` on the quote. Otherwise, + before executing, review the quote to ensure: - Exchange rate is acceptable - Fees are as expected @@ -169,129 +192,3 @@ If a transaction fails, Grid initiates a refund automatically. You'll receive `O - -### Funding with cryptocurrencies - -Cross-currency transfers support funding via USDC and BTC on popular blockchains including Solana, Base, Lightning and Spark. When you create a quote specifying the source currency as USDC or BTC, the response includes payment instructions for multiple funding options. - -#### Supported blockchains - -| Blockchain Network | Cryptocurrencies | -|-------|-------------| -| Solana | USDC | -| Base | USDC | -| Tron | USDT | -| Polygon | USDC | -| Ethereum | USDC, USDT | -| Lightning | BTC | -| Spark | BTC | - -#### Create a quote for USDC-funded transfer - -Request a quote that provides blockchain funding options: - -```bash -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "source": { - "sourceType": "REALTIME_FUNDING", - "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001", - "currency": "USDC" - }, - "destination": { "destinationType": "ACCOUNT", "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123" }, - "lockedCurrencySide": "SENDING", - "lockedCurrencyAmount": 10000, - "description": "Payment for services - Invoice #1234" - }' -``` - -The response includes an array of payment instructions, including blockchain wallet addresses for USDC and invoices for BTC: - -```json Success (201 Created) -{ - "id": "Quote:019542f5-b3e7-1d02-0000-000000000025", - "status": "PENDING", - "createdAt": "2025-10-03T15:00:00Z", - "expiresAt": "2025-10-03T15:15:00Z", - "source": { "sourceType": "REALTIME_FUNDING", "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001", "currency": "USDC" }, - "destination": { "destinationType": "ACCOUNT", "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123" }, - "sendingCurrency": { "code": "USDC", "name": "USD Coin", "symbol": "USDC", "decimals": 2 }, - "receivingCurrency": { "code": "EUR", "name": "Euro", "symbol": "€", "decimals": 2 }, - "totalSendingAmount": 10000, - "totalReceivingAmount": 9200, - "exchangeRate": 0.92, - "feesIncluded": 50, - "platformFeesIncluded": 0, - "transactionId": "Transaction:019542f5-b3e7-1d02-0000-000000000030", - "paymentInstructions": [ - { - "accountOrWalletInfo": { - "accountType": "SOLANA_WALLET", - "assetType": "USDC", - "address": "4Nd1m6Qkq7RfKuE5vQ9qP9Tn6H94Ueqb4xXHzsAbd8Wg" - } - }, - { - "accountOrWalletInfo": { - "accountType": "BASE_WALLET", - "assetType": "USDC", - "address": "0x1234567890abcdef1234567890abcdef12345678" - } - } - ] -} -``` - -#### Transaction processing - -Grid automatically detects blockchain deposits and processes the transfer once funds are received: - - - - Transfer the exact amount of USDC specified in `totalSendingAmount` to your chosen blockchain wallet address. - - - - Grid monitors the blockchain for incoming deposits. You'll receive an `INTERNAL_ACCOUNT.BALANCE_UPDATED` webhook when the deposit is confirmed: - -```json -{ - "id": "Webhook:019542f5-b3e7-1d02-0000-000000000040", - "type": "INTERNAL_ACCOUNT.BALANCE_UPDATED", - "timestamp": "2025-10-03T15:05:00Z", - "data": { - "id": "InternalAccount:019542f5-b3e7-1d02-0000-000000000025", - "balance": { "amount": 10000, "currency": { "code": "USDC", "decimals": 2 } }, - "totalBalance": { "amount": 10000, "currency": { "code": "USDC", "decimals": 2 } } - } -} -``` - - - - Once the deposit is confirmed, Grid executes the cross-currency transfer. You'll receive `OUTGOING_PAYMENT.` webhooks as the transfer progresses: - -```json -{ - "id": "Webhook:019542f5-b3e7-1d02-0000-000000000041", - "type": "OUTGOING_PAYMENT.COMPLETED", - "timestamp": "2025-10-03T15:31:00Z", - "data": { - "id": "Transaction:019542f5-b3e7-1d02-0000-000000000030", - "status": "COMPLETED", - "type": "OUTGOING", - "direction": "DEBIT", - "sentAmount": { "amount": 10000, "currency": { "code": "USDC", "decimals": 2 } }, - "receivedAmount": { "amount": 9200, "currency": { "code": "EUR", "decimals": 2 } }, - "exchangeRate": 0.92, - "settledAt": "2025-10-03T15:30:00Z", - "quoteId": "Quote:019542f5-b3e7-1d02-0000-000000000025" - } -} -``` - -See the [Transaction Lifecycle](/platform-overview/core-concepts/transaction-lifecycle) guide for all possible status transitions and refund handling. - - diff --git a/mintlify/snippets/sending/crypto-funding.mdx b/mintlify/snippets/sending/crypto-funding.mdx new file mode 100644 index 000000000..dbc9a01c8 --- /dev/null +++ b/mintlify/snippets/sending/crypto-funding.mdx @@ -0,0 +1,125 @@ +## Funding with cryptocurrencies + +Transfers can be funded via USDC and BTC on popular blockchains including Solana, Base, Lightning and Spark. When you create a quote specifying the source currency as USDC or BTC, the response includes payment instructions for multiple funding options. + +### Supported blockchains + +| Blockchain Network | Cryptocurrencies | +|-------|-------------| +| Solana | USDC | +| Base | USDC | +| Tron | USDT | +| Polygon | USDC | +| Ethereum | USDC, USDT | +| Lightning | BTC | +| Spark | BTC | + +### Create a quote for USDC-funded transfer + +Request a quote that provides blockchain funding options: + +```bash +curl -X POST 'https://api.lightspark.com/grid/2025-10-13/quotes' \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -H 'Content-Type: application/json' \ + -d '{ + "source": { + "sourceType": "REALTIME_FUNDING", + "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001", + "currency": "USDC" + }, + "destination": { "destinationType": "ACCOUNT", "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123" }, + "lockedCurrencySide": "SENDING", + "lockedCurrencyAmount": 10000, + "description": "Payment for services - Invoice #1234" + }' +``` + +The response includes an array of payment instructions, including blockchain wallet addresses for USDC and invoices for BTC: + +```json Success (201 Created) +{ + "id": "Quote:019542f5-b3e7-1d02-0000-000000000025", + "status": "PENDING", + "createdAt": "2025-10-03T15:00:00Z", + "expiresAt": "2025-10-03T15:15:00Z", + "source": { "sourceType": "REALTIME_FUNDING", "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001", "currency": "USDC" }, + "destination": { "destinationType": "ACCOUNT", "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123" }, + "sendingCurrency": { "code": "USDC", "name": "USD Coin", "symbol": "USDC", "decimals": 2 }, + "receivingCurrency": { "code": "EUR", "name": "Euro", "symbol": "€", "decimals": 2 }, + "totalSendingAmount": 10000, + "totalReceivingAmount": 9200, + "exchangeRate": 0.92, + "feesIncluded": 50, + "platformFeesIncluded": 0, + "transactionId": "Transaction:019542f5-b3e7-1d02-0000-000000000030", + "paymentInstructions": [ + { + "accountOrWalletInfo": { + "accountType": "SOLANA_WALLET", + "assetType": "USDC", + "address": "4Nd1m6Qkq7RfKuE5vQ9qP9Tn6H94Ueqb4xXHzsAbd8Wg" + } + }, + { + "accountOrWalletInfo": { + "accountType": "BASE_WALLET", + "assetType": "USDC", + "address": "0x1234567890abcdef1234567890abcdef12345678" + } + } + ] +} +``` + +### Transaction processing + +Grid automatically detects blockchain deposits and processes the transfer once funds are received: + + + + Transfer the exact amount of USDC specified in `totalSendingAmount` to your chosen blockchain wallet address. + + + + Grid monitors the blockchain for incoming deposits. You'll receive an `INTERNAL_ACCOUNT.BALANCE_UPDATED` webhook when the deposit is confirmed: + +```json +{ + "id": "Webhook:019542f5-b3e7-1d02-0000-000000000040", + "type": "INTERNAL_ACCOUNT.BALANCE_UPDATED", + "timestamp": "2025-10-03T15:05:00Z", + "data": { + "id": "InternalAccount:019542f5-b3e7-1d02-0000-000000000025", + "balance": { "amount": 10000, "currency": { "code": "USDC", "decimals": 2 } }, + "totalBalance": { "amount": 10000, "currency": { "code": "USDC", "decimals": 2 } } + } +} +``` + + + + Once the deposit is confirmed, Grid executes the cross-currency transfer. You'll receive `OUTGOING_PAYMENT.` webhooks as the transfer progresses: + +```json +{ + "id": "Webhook:019542f5-b3e7-1d02-0000-000000000041", + "type": "OUTGOING_PAYMENT.COMPLETED", + "timestamp": "2025-10-03T15:31:00Z", + "data": { + "id": "Transaction:019542f5-b3e7-1d02-0000-000000000030", + "status": "COMPLETED", + "type": "OUTGOING", + "direction": "DEBIT", + "sentAmount": { "amount": 10000, "currency": { "code": "USDC", "decimals": 2 } }, + "receivedAmount": { "amount": 9200, "currency": { "code": "EUR", "decimals": 2 } }, + "exchangeRate": 0.92, + "settledAt": "2025-10-03T15:30:00Z", + "quoteId": "Quote:019542f5-b3e7-1d02-0000-000000000025" + } +} +``` + +See the [Transaction Lifecycle](/platform-overview/core-concepts/transaction-lifecycle) guide for all possible status transitions and refund handling. + + diff --git a/mintlify/snippets/sending/same-currency.mdx b/mintlify/snippets/sending/same-currency.mdx deleted file mode 100644 index 879698b9c..000000000 --- a/mintlify/snippets/sending/same-currency.mdx +++ /dev/null @@ -1,103 +0,0 @@ -## Same-Currency Transfers - -Use the `/transfer-out` endpoint when sending funds in the same currency (no exchange rate needed). This is the simplest and fastest option for domestic transfers. - -### When to use same-currency transfers - -- Transferring USD from a USD internal account to a USD external account -- Sending funds within the same country using the same payment rail -- No currency conversion is required - -### Create a transfer - - - - Retrieve the internal account (source) and external account (destination) IDs: - -```bash -curl -X GET 'https://api.lightspark.com/grid/2025-10-13/customers/internal-accounts?customerId=Customer:019542f5-b3e7-1d02-0000-000000000001' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" -``` - -Note the `id` fields from both the internal and external accounts you want to use. - - - - - Create the transfer by specifying the source and destination accounts: - -```bash -curl -X POST 'https://api.lightspark.com/grid/2025-10-13/transfer-out' \ - -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ - -H 'Content-Type: application/json' \ - -d '{ - "source": { "accountId": "InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123" }, - "destination": { "accountId": "ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965", "paymentRail": "ACH" }, - "amount": 12550, - "remittanceInformation": "INV-12345" - }' -``` - - - The `paymentRail` field is optional. If omitted, Grid selects a default rail for the destination. - - - - `remittanceInformation` is optional. Use it to send a reference that travels with the payment to the recipient (max 80 characters). This populates the ACH Addenda record, FedNow/RTP remittance information, or wire OBI field depending on the payment rail. - - -```json Success (201 Created) -{ - "id": "Transaction:019542f5-b3e7-1d02-0000-000000000015", - "status": "PENDING", - "type": "OUTGOING", - "direction": "DEBIT", - "source": { - "sourceType": "ACCOUNT", - "accountId": "InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123" - }, - "destination": { - "destinationType": "ACCOUNT", - "accountId": "ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965" - }, - "sentAmount": { "amount": 12550, "currency": { "code": "USD", "decimals": 2 } }, - "receivedAmount": { "amount": 12550, "currency": { "code": "USD", "decimals": 2 } }, - "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001", - "platformCustomerId": "customer_12345", - "createdAt": "2025-10-03T15:00:00Z", - "settledAt": null -} -``` - - - The `amount` is specified in the smallest unit of the currency (cents for USD, pence for GBP, etc.). For example, `12550` represents $125.50 USD. - - - - - The transaction is created with a `PENDING` status and progresses through `PROCESSING` to `COMPLETED` or `FAILED`. You'll receive `OUTGOING_PAYMENT.` webhooks as the transaction progresses. The webhook body contains the full transaction resource: - -```json -{ - "type": "OUTGOING_PAYMENT.COMPLETED", - "data": { - "id": "Transaction:019542f5-b3e7-1d02-0000-000000000015", - "status": "COMPLETED", - "type": "OUTGOING", - "direction": "DEBIT", - "sentAmount": { "amount": 12550, "currency": { "code": "USD", "decimals": 2 } }, - "receivedAmount": { "amount": 12550, "currency": { "code": "USD", "decimals": 2 } }, - "settledAt": "2025-10-03T15:02:30Z" - }, - "timestamp": "2025-10-03T15:03:00Z" -} -``` - -If a transaction fails, Grid initiates a refund automatically. You'll receive `OUTGOING_PAYMENT.REFUND_PENDING` followed by `OUTGOING_PAYMENT.REFUND_COMPLETED` or `OUTGOING_PAYMENT.REFUND_FAILED`. The transaction's `refund` object tracks the refund status and reference. - - - For the full state diagram, refund object details, and all webhook scenarios (including bank returns and manual cancellations), see the [Transaction Lifecycle](/platform-overview/core-concepts/transaction-lifecycle) guide. - - - - diff --git a/mintlify/snippets/terminology.mdx b/mintlify/snippets/terminology.mdx index 68f38d4db..83b24b4e6 100644 --- a/mintlify/snippets/terminology.mdx +++ b/mintlify/snippets/terminology.mdx @@ -133,9 +133,8 @@ Understanding how entities map to your specific use case helps clarify your inte - Includes amounts, currencies, and settlement information - May include counterparty information for compliance purposes if required by your platform configuration -Transactions are created when: -- A quote is executed (either incoming or outgoing) -- A same currency transfer is initiated (transfer-in or transfer-out) +Transactions are created when a quote is executed, incoming or outgoing. This covers +same-currency and cross-currency transfers alike. ### UMA Addresses (optional) diff --git a/openapi.yaml b/openapi.yaml index 51644742f..21f570d74 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -36,9 +36,9 @@ tags: - name: VASPs description: Directory of Virtual Asset Service Providers (exchanges and other custodial platforms) recognized for counterparty declarations. - name: Same-Currency Transfers - description: Endpoints for transferring funds between internal and external accounts with the same currency + description: Deprecated endpoints for transferring funds between internal and external accounts with the same currency. Use the quote endpoints under Cross-Currency Transfers instead, which now serve same-currency transfers as well. - name: Cross-Currency Transfers - description: Endpoints for creating and confirming quotes for cross-currency transfers + description: Endpoints for creating and confirming quotes for transfers, both same-currency and cross-currency - name: Transactions description: Endpoints for retrieving transaction information - name: Webhooks @@ -3593,8 +3593,29 @@ paths: /transfer-in: post: summary: Create a transfer-in request + deprecated: true description: | - Transfer funds from an external account to an internal account for a specific customer. This endpoint should only be used for external account sources with pull functionality (e.g. ACH Pull). Otherwise, use the paymentInstructions on the internal account to deposit funds. + **Deprecated. Use `POST /quotes` instead.** + + Same-currency transfers are now served by the quote endpoint. Create a quote + with an external account source and an internal account destination and set + `immediatelyExecute: true` to move the funds in a single request, exactly as + this endpoint does. This endpoint continues to work and its request and + response shapes are unchanged. + + To migrate a request to `POST /quotes`: + + - add `sourceType: ACCOUNT` to `source` and `destinationType: ACCOUNT` to + `destination`; the account IDs are unchanged + - rename `amount` to `lockedCurrencyAmount` and add `lockedCurrencySide: SENDING` + - add `immediatelyExecute: true` to keep the single-request behavior + + The quote response is a `Quote` rather than a `Transaction`; read + `transactionId` from it to track the resulting transaction. + + Transfer funds from an external account to an internal account for a specific customer. + This endpoint should only be used for external account sources with pull functionality (e.g. ACH Pull). + Otherwise, use the paymentInstructions on the internal account to deposit funds. operationId: createTransferIn tags: - Same-Currency Transfers @@ -3658,7 +3679,27 @@ paths: /transfer-out: post: summary: Create a transfer-out request + deprecated: true description: | + **Deprecated. Use `POST /quotes` instead.** + + Same-currency transfers are now served by the quote endpoint. Create a quote + with an internal account source and an external account destination and set + `immediatelyExecute: true` to move the funds in a single request, exactly as + this endpoint does. This endpoint continues to work and its request and + response shapes are unchanged. + + To migrate a request to `POST /quotes`: + + - add `sourceType: ACCOUNT` to `source` and `destinationType: ACCOUNT` to + `destination`; the account IDs and `destination.paymentRail` are unchanged + - rename `amount` to `lockedCurrencyAmount` and add `lockedCurrencySide: SENDING` + - `remittanceInformation` and `purposeOfPayment` carry over unchanged + - add `immediatelyExecute: true` to keep the single-request behavior + + The quote response is a `Quote` rather than a `Transaction`; read + `transactionId` from it to track the resulting transaction. + Transfer funds from an internal account to an external account for a specific customer. operationId: createTransferOut tags: @@ -3924,12 +3965,12 @@ paths: post: summary: Create a transfer quote description: | - Generate a quote for a cross-currency transfer between any combination of accounts - and UMA addresses. This endpoint handles currency exchange and provides the necessary - instructions to execute the transfer. + Generate a quote for a transfer between any combination of accounts + and UMA addresses. This endpoint handles same-currency and cross-currency + transfers alike, and provides the necessary instructions to execute the transfer. **Transfer Types Supported:** - - **Account to Account**: Transfer between internal/external accounts with currency exchange. + - **Account to Account**: Transfer between internal/external accounts, with or without currency exchange. - **Account to UMA**: Transfer from an internal account to an UMA address. - **UMA to Account or UMA to UMA**: This transfer type will only be funded by payment instructions, not from an internal account. @@ -3938,8 +3979,9 @@ paths: - **Currency Exchange**: Handles all cross-currency transfers with real-time exchange rates - **Payment Instructions**: For UMA or customer ID sources, provides banking details needed for execution - **Important:** If you are transferring funds in the same currency (no exchange required), - use the `/transfer-in` or `/transfer-out` endpoints instead. + **Same-currency transfers:** Use this endpoint for same-currency transfers too. + Set `immediatelyExecute: true` to create and execute in a single request. The + older `/transfer-in` and `/transfer-out` endpoints are deprecated. Requires a token with the `TRANSACT` permission; `VIEW` alone is not sufficient. A quote is the instrument a later execute draws on, and @@ -3965,6 +4007,21 @@ paths: schema: $ref: '#/components/schemas/QuoteRequest' examples: + sameCurrencyAccountToAccount: + summary: Same-Currency Account to Account Transfer (immediate execution) + value: + source: + sourceType: ACCOUNT + accountId: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 + destination: + destinationType: ACCOUNT + accountId: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 + paymentRail: ACH + lockedCurrencySide: SENDING + lockedCurrencyAmount: 12550 + immediatelyExecute: true + remittanceInformation: INV-12345 + description: Same-currency payout, no exchange required. accountToAccount: summary: Account to Account Transfer value: @@ -8054,151 +8111,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' - /agents/me/transfer-in: - post: - summary: Create a transfer-in - description: | - Transfer funds from an external account to an internal account for the authenticated agent's customer. Accounts must belong to the agent's customer. Requires the CREATE_TRANSFERS permission in the agent's policy. - If the agent's policy requires approval for this amount, the transaction will be created in a pending state and must be approved by the platform via `POST /agents/{agentId}/actions/{actionId}/approve`. - This endpoint should only be used for external account sources with pull functionality (e.g. ACH Pull). Otherwise, use the payment instructions on the internal account to deposit funds. - operationId: agentCreateTransferIn - tags: - - Agent Operations - security: - - AgentAuth: [] - parameters: - - name: Idempotency-Key - in: header - required: false - description: | - A unique identifier for the request. If the same key is sent multiple times, the server will return the same response as the first request. - schema: - type: string - example: 550e8400-e29b-41d4-a716-446655440000 - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TransferInRequest' - examples: - transferIn: - summary: Transfer from external to internal account - value: - source: - accountId: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 - destination: - accountId: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 - amount: 12550 - responses: - '201': - description: Action submitted successfully. If the agent's policy requires approval, the returned `AgentAction` will have status `PENDING_APPROVAL` and no `transaction` yet. If the policy permits automatic execution, status will be `APPROVED` and `transaction` will be populated. - content: - application/json: - schema: - $ref: '#/components/schemas/AgentAction' - '400': - description: Bad request - Invalid parameters - content: - application/json: - schema: - $ref: '#/components/schemas/Error400' - '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error401' - '403': - description: Forbidden - Agent policy does not permit this operation or spending limit exceeded - content: - application/json: - schema: - $ref: '#/components/schemas/Error403' - '404': - description: Account not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404' - '500': - description: Internal service error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500' - /agents/me/transfer-out: - post: - summary: Create a transfer-out - description: | - Transfer funds from an internal account to an external account for the authenticated agent's customer. Accounts must belong to the agent's customer. Requires the CREATE_TRANSFERS permission in the agent's policy. - If the agent's policy requires approval for this amount, the transaction will be created in a pending state and must be approved by the platform via `POST /agents/{agentId}/actions/{actionId}/approve`. - operationId: agentCreateTransferOut - tags: - - Agent Operations - security: - - AgentAuth: [] - parameters: - - name: Idempotency-Key - in: header - required: false - description: | - A unique identifier for the request. If the same key is sent multiple times, the server will return the same response as the first request. - schema: - type: string - example: 550e8400-e29b-41d4-a716-446655440000 - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TransferOutRequest' - examples: - transferOut: - summary: Transfer from internal to external account - value: - source: - accountId: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 - destination: - accountId: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 - amount: 12550 - responses: - '201': - description: Action submitted successfully. If the agent's policy requires approval, the returned `AgentAction` will have status `PENDING_APPROVAL` and no `transaction` yet. If the policy permits automatic execution, status will be `APPROVED` and `transaction` will be populated. - content: - application/json: - schema: - $ref: '#/components/schemas/AgentAction' - '400': - description: Bad request - Invalid parameters - content: - application/json: - schema: - $ref: '#/components/schemas/Error400' - '401': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error401' - '403': - description: Forbidden - Agent policy does not permit this operation or spending limit exceeded - content: - application/json: - schema: - $ref: '#/components/schemas/Error403' - '404': - description: Account not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404' - '500': - description: Internal service error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500' /agents/me/internal-accounts: get: summary: List agent's internal accounts @@ -23879,11 +23791,10 @@ components: type: string enum: - VIEW_TRANSACTIONS - - CREATE_TRANSFERS - CREATE_QUOTES - EXECUTE_QUOTES - MANAGE_EXTERNAL_ACCOUNTS - description: 'Permission granted to an agent that determines what actions it can perform. VIEW_TRANSACTIONS: Can list and retrieve transactions and account balances. CREATE_TRANSFERS: Can initiate same-currency transfers. CREATE_QUOTES: Can create cross-currency quotes. EXECUTE_QUOTES: Can execute cross-currency quotes. MANAGE_EXTERNAL_ACCOUNTS: Can create and manage external accounts.' + description: 'Permission granted to an agent that determines what actions it can perform. VIEW_TRANSACTIONS: Can list and retrieve transactions and account balances. CREATE_QUOTES: Can create quotes. EXECUTE_QUOTES: Can execute quotes. MANAGE_EXTERNAL_ACCOUNTS: Can create and manage external accounts.' AgentExecutionMode: type: string enum: @@ -24161,42 +24072,12 @@ components: type: string enum: - EXECUTE_QUOTE - - TRANSFER_OUT - - TRANSFER_IN description: | The type of action the agent is requesting. | Type | Description | |------|-------------| - | `EXECUTE_QUOTE` | Execute a cross-currency quote | - | `TRANSFER_OUT` | Transfer from an internal account to an external account | - | `TRANSFER_IN` | Transfer from an external account to an internal account | - AgentTransferDetails: - type: object - description: Details of a transfer-type agent action (TRANSFER_OUT or TRANSFER_IN). - required: - - amount - - currency - - sourceAccountId - - destinationAccountId - properties: - amount: - type: integer - format: int64 - description: Transfer amount in the smallest unit of the specified currency. - example: 50000 - currency: - type: string - description: ISO 4217 currency code for the transfer amount. - example: USD - sourceAccountId: - type: string - description: ID of the source account (internal or external). - example: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 - destinationAccountId: - type: string - description: ID of the destination account (internal or external). - example: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 + | `EXECUTE_QUOTE` | Execute a quote | AgentAction: type: object description: An action submitted by an agent that may require platform approval before execution. All agent-initiated operations (quote execution, transfers) are represented as AgentActions, giving the platform a consistent object to approve, reject, and audit regardless of the underlying operation type. @@ -24233,11 +24114,7 @@ components: quote: allOf: - $ref: '#/components/schemas/Quote' - description: The quote being executed. Populated for `EXECUTE_QUOTE` actions; absent for transfer actions. Contains the full amount, currency, destination, and rate details needed to present an approval decision to the user. - transferDetails: - allOf: - - $ref: '#/components/schemas/AgentTransferDetails' - description: Details of the transfer being requested. Populated for `TRANSFER_OUT` and `TRANSFER_IN` actions; absent for `EXECUTE_QUOTE` actions. + description: The quote being executed. Contains the full amount, currency, destination, and rate details needed to present an approval decision to the user. transaction: allOf: - $ref: '#/components/schemas/TransactionOneOf' diff --git a/openapi/components/schemas/agents/AgentAction.yaml b/openapi/components/schemas/agents/AgentAction.yaml index 105614494..260c11588 100644 --- a/openapi/components/schemas/agents/AgentAction.yaml +++ b/openapi/components/schemas/agents/AgentAction.yaml @@ -38,15 +38,8 @@ properties: allOf: - $ref: ../quotes/Quote.yaml description: >- - The quote being executed. Populated for `EXECUTE_QUOTE` actions; absent for transfer actions. - Contains the full amount, currency, destination, and rate details needed to present an - approval decision to the user. - transferDetails: - allOf: - - $ref: ./AgentTransferDetails.yaml - description: >- - Details of the transfer being requested. Populated for `TRANSFER_OUT` and `TRANSFER_IN` - actions; absent for `EXECUTE_QUOTE` actions. + The quote being executed. Contains the full amount, currency, destination, and rate + details needed to present an approval decision to the user. transaction: allOf: - $ref: ../transactions/TransactionOneOf.yaml diff --git a/openapi/components/schemas/agents/AgentActionType.yaml b/openapi/components/schemas/agents/AgentActionType.yaml index 8b9573470..1b8929b4c 100644 --- a/openapi/components/schemas/agents/AgentActionType.yaml +++ b/openapi/components/schemas/agents/AgentActionType.yaml @@ -1,13 +1,9 @@ type: string enum: - EXECUTE_QUOTE - - TRANSFER_OUT - - TRANSFER_IN description: | The type of action the agent is requesting. | Type | Description | |------|-------------| - | `EXECUTE_QUOTE` | Execute a cross-currency quote | - | `TRANSFER_OUT` | Transfer from an internal account to an external account | - | `TRANSFER_IN` | Transfer from an external account to an internal account | + | `EXECUTE_QUOTE` | Execute a quote | diff --git a/openapi/components/schemas/agents/AgentPermission.yaml b/openapi/components/schemas/agents/AgentPermission.yaml index 4cef5cb03..4f0b768d8 100644 --- a/openapi/components/schemas/agents/AgentPermission.yaml +++ b/openapi/components/schemas/agents/AgentPermission.yaml @@ -1,14 +1,12 @@ type: string enum: - VIEW_TRANSACTIONS - - CREATE_TRANSFERS - CREATE_QUOTES - EXECUTE_QUOTES - MANAGE_EXTERNAL_ACCOUNTS description: >- Permission granted to an agent that determines what actions it can perform. VIEW_TRANSACTIONS: Can list and retrieve transactions and account balances. - CREATE_TRANSFERS: Can initiate same-currency transfers. - CREATE_QUOTES: Can create cross-currency quotes. - EXECUTE_QUOTES: Can execute cross-currency quotes. + CREATE_QUOTES: Can create quotes. + EXECUTE_QUOTES: Can execute quotes. MANAGE_EXTERNAL_ACCOUNTS: Can create and manage external accounts. diff --git a/openapi/components/schemas/agents/AgentTransferDetails.yaml b/openapi/components/schemas/agents/AgentTransferDetails.yaml deleted file mode 100644 index d8eb2f5c3..000000000 --- a/openapi/components/schemas/agents/AgentTransferDetails.yaml +++ /dev/null @@ -1,25 +0,0 @@ -type: object -description: Details of a transfer-type agent action (TRANSFER_OUT or TRANSFER_IN). -required: - - amount - - currency - - sourceAccountId - - destinationAccountId -properties: - amount: - type: integer - format: int64 - description: Transfer amount in the smallest unit of the specified currency. - example: 50000 - currency: - type: string - description: ISO 4217 currency code for the transfer amount. - example: USD - sourceAccountId: - type: string - description: ID of the source account (internal or external). - example: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 - destinationAccountId: - type: string - description: ID of the destination account (internal or external). - example: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 8c164aafd..b99aa2d11 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -45,9 +45,15 @@ tags: Directory of Virtual Asset Service Providers (exchanges and other custodial platforms) recognized for counterparty declarations. - name: Same-Currency Transfers - description: Endpoints for transferring funds between internal and external accounts with the same currency + description: >- + Deprecated endpoints for transferring funds between internal and external + accounts with the same currency. Use the quote endpoints under + Cross-Currency Transfers instead, which now serve same-currency transfers + as well. - name: Cross-Currency Transfers - description: Endpoints for creating and confirming quotes for cross-currency transfers + description: >- + Endpoints for creating and confirming quotes for transfers, both + same-currency and cross-currency - name: Transactions description: Endpoints for retrieving transaction information - name: Webhooks @@ -334,10 +340,6 @@ paths: $ref: paths/agents/agents_me_actions.yaml /agents/me/actions/{actionId}: $ref: paths/agents/agents_me_actions_{actionId}.yaml - /agents/me/transfer-in: - $ref: paths/agents/agents_me_transfer-in.yaml - /agents/me/transfer-out: - $ref: paths/agents/agents_me_transfer-out.yaml /agents/me/internal-accounts: $ref: paths/agents/agents_me_internal-accounts.yaml /agents/me/external-accounts: diff --git a/openapi/paths/agents/agents_me_transfer-in.yaml b/openapi/paths/agents/agents_me_transfer-in.yaml deleted file mode 100644 index 4deba5af0..000000000 --- a/openapi/paths/agents/agents_me_transfer-in.yaml +++ /dev/null @@ -1,85 +0,0 @@ -post: - summary: Create a transfer-in - description: > - Transfer funds from an external account to an internal account for the authenticated - agent's customer. Accounts must belong to the agent's customer. Requires the - CREATE_TRANSFERS permission in the agent's policy. - - If the agent's policy requires approval for this amount, the transaction will be - created in a pending state and must be approved by the platform via - `POST /agents/{agentId}/actions/{actionId}/approve`. - - This endpoint should only be used for external account sources with pull functionality - (e.g. ACH Pull). Otherwise, use the payment instructions on the internal account to - deposit funds. - operationId: agentCreateTransferIn - tags: - - Agent Operations - security: - - AgentAuth: [] - parameters: - - name: Idempotency-Key - in: header - required: false - description: > - A unique identifier for the request. If the same key is sent multiple times, - the server will return the same response as the first request. - schema: - type: string - example: 550e8400-e29b-41d4-a716-446655440000 - requestBody: - required: true - content: - application/json: - schema: - $ref: ../../components/schemas/transfers/TransferInRequest.yaml - examples: - transferIn: - summary: Transfer from external to internal account - value: - source: - accountId: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 - destination: - accountId: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 - amount: 12550 - responses: - '201': - description: >- - Action submitted successfully. If the agent's policy requires approval, the returned - `AgentAction` will have status `PENDING_APPROVAL` and no `transaction` yet. If the - policy permits automatic execution, status will be `APPROVED` and `transaction` will - be populated. - content: - application/json: - schema: - $ref: ../../components/schemas/agents/AgentAction.yaml - '400': - description: Bad request - Invalid parameters - content: - application/json: - schema: - $ref: ../../components/schemas/errors/Error400.yaml - '401': - description: Unauthorized - content: - application/json: - schema: - $ref: ../../components/schemas/errors/Error401.yaml - '403': - description: Forbidden - Agent policy does not permit this operation or spending limit exceeded - content: - application/json: - schema: - $ref: ../../components/schemas/errors/Error403.yaml - '404': - description: Account not found - content: - application/json: - schema: - $ref: ../../components/schemas/errors/Error404.yaml - '500': - description: Internal service error - content: - application/json: - schema: - $ref: ../../components/schemas/errors/Error500.yaml diff --git a/openapi/paths/agents/agents_me_transfer-out.yaml b/openapi/paths/agents/agents_me_transfer-out.yaml deleted file mode 100644 index 24ef251e8..000000000 --- a/openapi/paths/agents/agents_me_transfer-out.yaml +++ /dev/null @@ -1,81 +0,0 @@ -post: - summary: Create a transfer-out - description: > - Transfer funds from an internal account to an external account for the authenticated - agent's customer. Accounts must belong to the agent's customer. Requires the - CREATE_TRANSFERS permission in the agent's policy. - - If the agent's policy requires approval for this amount, the transaction will be - created in a pending state and must be approved by the platform via - `POST /agents/{agentId}/actions/{actionId}/approve`. - operationId: agentCreateTransferOut - tags: - - Agent Operations - security: - - AgentAuth: [] - parameters: - - name: Idempotency-Key - in: header - required: false - description: > - A unique identifier for the request. If the same key is sent multiple times, - the server will return the same response as the first request. - schema: - type: string - example: 550e8400-e29b-41d4-a716-446655440000 - requestBody: - required: true - content: - application/json: - schema: - $ref: ../../components/schemas/transfers/TransferOutRequest.yaml - examples: - transferOut: - summary: Transfer from internal to external account - value: - source: - accountId: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 - destination: - accountId: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 - amount: 12550 - responses: - '201': - description: >- - Action submitted successfully. If the agent's policy requires approval, the returned - `AgentAction` will have status `PENDING_APPROVAL` and no `transaction` yet. If the - policy permits automatic execution, status will be `APPROVED` and `transaction` will - be populated. - content: - application/json: - schema: - $ref: ../../components/schemas/agents/AgentAction.yaml - '400': - description: Bad request - Invalid parameters - content: - application/json: - schema: - $ref: ../../components/schemas/errors/Error400.yaml - '401': - description: Unauthorized - content: - application/json: - schema: - $ref: ../../components/schemas/errors/Error401.yaml - '403': - description: Forbidden - Agent policy does not permit this operation or spending limit exceeded - content: - application/json: - schema: - $ref: ../../components/schemas/errors/Error403.yaml - '404': - description: Account not found - content: - application/json: - schema: - $ref: ../../components/schemas/errors/Error404.yaml - '500': - description: Internal service error - content: - application/json: - schema: - $ref: ../../components/schemas/errors/Error500.yaml diff --git a/openapi/paths/quotes/quotes.yaml b/openapi/paths/quotes/quotes.yaml index 973b4ada7..cde5a52be 100644 --- a/openapi/paths/quotes/quotes.yaml +++ b/openapi/paths/quotes/quotes.yaml @@ -1,12 +1,12 @@ post: summary: Create a transfer quote description: | - Generate a quote for a cross-currency transfer between any combination of accounts - and UMA addresses. This endpoint handles currency exchange and provides the necessary - instructions to execute the transfer. + Generate a quote for a transfer between any combination of accounts + and UMA addresses. This endpoint handles same-currency and cross-currency + transfers alike, and provides the necessary instructions to execute the transfer. **Transfer Types Supported:** - - **Account to Account**: Transfer between internal/external accounts with currency exchange. + - **Account to Account**: Transfer between internal/external accounts, with or without currency exchange. - **Account to UMA**: Transfer from an internal account to an UMA address. - **UMA to Account or UMA to UMA**: This transfer type will only be funded by payment instructions, not from an internal account. @@ -15,8 +15,9 @@ post: - **Currency Exchange**: Handles all cross-currency transfers with real-time exchange rates - **Payment Instructions**: For UMA or customer ID sources, provides banking details needed for execution - **Important:** If you are transferring funds in the same currency (no exchange required), - use the `/transfer-in` or `/transfer-out` endpoints instead. + **Same-currency transfers:** Use this endpoint for same-currency transfers too. + Set `immediatelyExecute: true` to create and execute in a single request. The + older `/transfer-in` and `/transfer-out` endpoints are deprecated. Requires a token with the `TRANSACT` permission; `VIEW` alone is not sufficient. A quote is the instrument a later execute draws on, and @@ -43,6 +44,21 @@ post: schema: $ref: ../../components/schemas/quotes/QuoteRequest.yaml examples: + sameCurrencyAccountToAccount: + summary: Same-Currency Account to Account Transfer (immediate execution) + value: + source: + sourceType: ACCOUNT + accountId: InternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123 + destination: + destinationType: ACCOUNT + accountId: ExternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965 + paymentRail: ACH + lockedCurrencySide: SENDING + lockedCurrencyAmount: 12550 + immediatelyExecute: true + remittanceInformation: INV-12345 + description: 'Same-currency payout, no exchange required.' accountToAccount: summary: Account to Account Transfer value: diff --git a/openapi/paths/transfers/transfer_in.yaml b/openapi/paths/transfers/transfer_in.yaml index 9dff344f9..d78c474e2 100644 --- a/openapi/paths/transfers/transfer_in.yaml +++ b/openapi/paths/transfers/transfer_in.yaml @@ -1,6 +1,25 @@ post: summary: Create a transfer-in request - description: > + deprecated: true + description: | + **Deprecated. Use `POST /quotes` instead.** + + Same-currency transfers are now served by the quote endpoint. Create a quote + with an external account source and an internal account destination and set + `immediatelyExecute: true` to move the funds in a single request, exactly as + this endpoint does. This endpoint continues to work and its request and + response shapes are unchanged. + + To migrate a request to `POST /quotes`: + + - add `sourceType: ACCOUNT` to `source` and `destinationType: ACCOUNT` to + `destination`; the account IDs are unchanged + - rename `amount` to `lockedCurrencyAmount` and add `lockedCurrencySide: SENDING` + - add `immediatelyExecute: true` to keep the single-request behavior + + The quote response is a `Quote` rather than a `Transaction`; read + `transactionId` from it to track the resulting transaction. + Transfer funds from an external account to an internal account for a specific customer. This endpoint should only be used for external account sources with pull functionality (e.g. ACH Pull). Otherwise, use the paymentInstructions on the internal account to deposit funds. diff --git a/openapi/paths/transfers/transfer_out.yaml b/openapi/paths/transfers/transfer_out.yaml index a76e9e80f..d1c773af7 100644 --- a/openapi/paths/transfers/transfer_out.yaml +++ b/openapi/paths/transfers/transfer_out.yaml @@ -1,6 +1,26 @@ post: summary: Create a transfer-out request - description: > + deprecated: true + description: | + **Deprecated. Use `POST /quotes` instead.** + + Same-currency transfers are now served by the quote endpoint. Create a quote + with an internal account source and an external account destination and set + `immediatelyExecute: true` to move the funds in a single request, exactly as + this endpoint does. This endpoint continues to work and its request and + response shapes are unchanged. + + To migrate a request to `POST /quotes`: + + - add `sourceType: ACCOUNT` to `source` and `destinationType: ACCOUNT` to + `destination`; the account IDs and `destination.paymentRail` are unchanged + - rename `amount` to `lockedCurrencyAmount` and add `lockedCurrencySide: SENDING` + - `remittanceInformation` and `purposeOfPayment` carry over unchanged + - add `immediatelyExecute: true` to keep the single-request behavior + + The quote response is a `Quote` rather than a `Transaction`; read + `transactionId` from it to track the resulting transaction. + Transfer funds from an internal account to an external account for a specific customer. operationId: createTransferOut tags: