Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .stainless/stainless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,14 @@ resources:
quote_source_one_of: "#/components/schemas/QuoteSourceOneOf"
base_destination: "#/components/schemas/BaseDestination"
quote_request: "#/components/schemas/QuoteRequest"
quote_document_requirement: "#/components/schemas/QuoteDocumentRequirement"
methods:
retrieve: get /quotes/{quoteId}
create: post /quotes
execute: post /quotes/{quoteId}/execute
upload_document:
endpoint: post /quotes/{quoteId}/documents
body_param_name: QuoteDocumentUploadRequest

transactions:
models:
Expand Down
323 changes: 320 additions & 3 deletions mintlify/openapi.yaml

Large diffs are not rendered by default.

323 changes: 320 additions & 3 deletions openapi.yaml

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions openapi/components/schemas/errors/Error409.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ properties:
| STABLECOIN_SYMBOL_ALREADY_EXISTS | A stablecoin with this symbol is already registered |
| STABLECOIN_TOKEN_IDENTIFIER_ALREADY_EXISTS | A stablecoin with this token identifier is already registered |
| WALLET_NOT_PROVISIONED | The embedded wallet has not been provisioned |
| DOCUMENT_REQUIREMENT_ALREADY_SATISFIED | A file has already been accepted for this quote document requirement. A satisfied requirement cannot be replaced; create a new quote to send a different file |
| DOCUMENT_UPLOAD_IN_PROGRESS | Another document upload for this quote is still being handled. Uploads for one quote are serialized, so retry once the in-flight one returns |
| QUOTE_NOT_ACCEPTING_DOCUMENTS | The quote has moved past the state where it accepts supporting documents |
| DOCUMENTS_REQUIRED | The quote has unsatisfied `documentRequirements`. Upload the outstanding documents via `POST /quotes/{quoteId}/documents`, then retry execution |
enum:
- TRANSACTION_NOT_PENDING_PLATFORM_APPROVAL
- TRANSACTION_NOT_CANCELLABLE
Expand All @@ -55,6 +59,10 @@ properties:
- STABLECOIN_SYMBOL_ALREADY_EXISTS
- STABLECOIN_TOKEN_IDENTIFIER_ALREADY_EXISTS
- WALLET_NOT_PROVISIONED
- DOCUMENT_REQUIREMENT_ALREADY_SATISFIED
- DOCUMENT_UPLOAD_IN_PROGRESS
- QUOTE_NOT_ACCEPTING_DOCUMENTS
- DOCUMENTS_REQUIRED
reason:
type: string
description: Error message
Expand Down
2 changes: 2 additions & 0 deletions openapi/components/schemas/errors/Error410.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ properties:
| Error Code | Description |
|------------|-------------|
| CUSTOMER_DELETED | Customer has been permanently deleted |
| QUOTE_EXPIRED | The quote has expired and can no longer be acted on; request a new quote |
enum:
- CUSTOMER_DELETED
- QUOTE_EXPIRED
reason:
type: string
description: Error message
Expand Down
11 changes: 11 additions & 0 deletions openapi/components/schemas/quotes/ChinaB2BServiceCategory.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type: string
description: >-
Which kind of service a China B2B `SERVICE_CHARGES` payment pays for. The
receiving bank requires this breakdown; `SERVICE_CHARGES` alone is not
specific enough to clear.
enum:
- COMMISSION_ON_GOODS
- COMMISSION_ON_SERVICES
- ACCOUNTING_SERVICES
- EXHIBITION_SERVICES
example: COMMISSION_ON_SERVICES
21 changes: 21 additions & 0 deletions openapi/components/schemas/quotes/PaymentDocumentType.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
type: string
description: >-
The kind of evidence a file provides. These are logical evidence types, not
file formats: `INVOICE` means the file is an invoice, whatever the corridor
or provider behind the payment calls it.


Each entry in a quote's `documentRequirements` lists the types it accepts in
`acceptedDocumentTypes`, and an upload declares which of them the file is.
enum:
- PURCHASE_ORDER
- LOGISTICS_BILL
- CUSTOMS_DECLARATION
- INVOICE
- CONTRACT
- DELIVERY_SLIP
- BILL_OF_LADING
- FLIGHT_TICKET
- TRAVEL_DOCUMENT
- HOTEL_BOOKING_CONFIRMATION
example: INVOICE
51 changes: 50 additions & 1 deletion openapi/components/schemas/quotes/Quote.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,13 @@ properties:
example: 5
paymentInstructions:
type: array
description: Payment instructions for executing the payment. This is not required when using an internal account source.
description: >-
Payment instructions for executing the payment. This is not required when
using an internal account source. Absent while `documentStatus` is
`PENDING`: a quote whose supporting documents are outstanding has no
instructions to give yet, and they are issued once every requirement is
satisfied, subject to the same source and Strong Customer Authentication
rules that otherwise apply.
items:
$ref: ../common/PaymentInstructions.yaml
example:
Expand Down Expand Up @@ -148,3 +154,46 @@ properties:
Customer Authentication challenge to satisfy before this quote can be
executed (or, for realtime-funding sources, before `paymentInstructions`
are issued). Omitted for customers outside SCA-regulated regions (non-EU).
documentStatus:
$ref: ./QuoteDocumentStatus.yaml
description: >-
Whether this quote's supporting documents are all in. Present only
alongside `documentRequirements`; both are omitted on a quote that needs
no documents.
documentRequirements:
type: array
description: >-
The supporting documents this quote needs before it can be executed, one
entry per file. Every entry must be satisfied — there is no optional
requirement in this array — and each is satisfied by exactly one file
uploaded via `POST /quotes/{quoteId}/documents`. A requirement listing
several `acceptedDocumentTypes` still takes one file; the types are
alternatives for it.


Which documents a corridor asks for depends on the payment. A business
payout to China, for instance, derives them from `purposeOfPayment`: an
`EXPORTED_GOODS_POSTPAYMENT` quote needs a logistics bill, a customs
declaration, and one of a purchase order, invoice, or contract — three
files, three requirements. Read the array rather than deriving it, since
policies change.


Omitted, along with `documentStatus`, when the quote needs no documents.
items:
$ref: ./QuoteDocumentRequirement.yaml
example:
- requirementId: LOGISTICS_BILL
acceptedDocumentTypes:
- LOGISTICS_BILL
satisfied: false
- requirementId: CUSTOMS_DECLARATION
acceptedDocumentTypes:
- CUSTOMS_DECLARATION
satisfied: false
- requirementId: COMMERCIAL_AGREEMENT
acceptedDocumentTypes:
- PURCHASE_ORDER
- INVOICE
- CONTRACT
satisfied: false
34 changes: 34 additions & 0 deletions openapi/components/schemas/quotes/QuoteDocumentRequirement.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
type: object
description: >-
One supporting document the quote needs before it can be executed. Exactly
one file satisfies it: the values in `acceptedDocumentTypes` are alternatives
for that single file, not a list of files to send.
required:
- requirementId
- acceptedDocumentTypes
- satisfied
properties:
requirementId:
$ref: ./QuoteDocumentRequirementId.yaml
description: >-
Identifies this requirement. Pass it back as the `requirementId` form
field when uploading the file that satisfies it.
acceptedDocumentTypes:
type: array
minItems: 1
description: >-
The document types that satisfy this requirement. Any one of them is
enough; the upload declares which one the file is. A single-value array
means the requirement accepts only that type.
items:
$ref: ./PaymentDocumentType.yaml
example:
- PURCHASE_ORDER
- INVOICE
- CONTRACT
satisfied:
type: boolean
description: >-
Whether a file has been accepted for this requirement. Once `true` it
stays `true` — a satisfied requirement cannot be replaced.
example: false
25 changes: 25 additions & 0 deletions openapi/components/schemas/quotes/QuoteDocumentRequirementId.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
type: string
description: >-
Identifies one requirement within a quote, stable across quotes for the same
policy. It is a separate concept from `PaymentDocumentType`: the ID names the
slot to fill, the document type names what the file is. Where a requirement
accepts alternatives, the two differ — a `SUPPORTING_PROOF` requirement is
satisfied by a file declared as either `PURCHASE_ORDER` or `DELIVERY_SLIP`.


New values may be added as policies change, so treat an unrecognized value as
a requirement you cannot yet render rather than an error.
enum:
- PURCHASE_ORDER
- LOGISTICS_BILL
- CUSTOMS_DECLARATION
- COMMERCIAL_AGREEMENT
- CONTRACT
- INVOICE
- SUPPORTING_PROOF
- BILL_OF_LADING
- CONTRACT_OR_INVOICE
- FLIGHT_TICKET
- TRAVEL_DOCUMENT
- HOTEL_BOOKING_CONFIRMATION
example: COMMERCIAL_AGREEMENT
10 changes: 10 additions & 0 deletions openapi/components/schemas/quotes/QuoteDocumentStatus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type: string
description: >-
Whether the supporting documents this quote requires have all been uploaded.
`PENDING` means at least one entry in `documentRequirements` is still
unsatisfied; `COMPLETE` means every one of them is satisfied and the quote can
be executed. Omitted entirely on quotes that require no supporting documents.
enum:
- PENDING
- COMPLETE
example: PENDING
28 changes: 28 additions & 0 deletions openapi/components/schemas/quotes/QuoteDocumentUploadRequest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
title: Quote Document Upload Request
type: object
required:
- file
- requirementId
- documentType
properties:
file:
type: string
format: binary
description: |
The document file. Grid accepts three formats, matched on the
`Content-Type` of the multipart part rather than the file extension:
`application/pdf`, `image/jpeg`, and `image/png`. Grid also reads the
file's leading bytes and rejects one whose real format contradicts the
declared `Content-Type`. An empty file, a file over 8 MB, and any other
format return `400 INVALID_INPUT`.
requirementId:
$ref: ./QuoteDocumentRequirementId.yaml
description: >-
Which of the quote's `documentRequirements` this file satisfies. Must be
the `requirementId` of an entry on this quote whose `satisfied` is still
`false`.
documentType:
$ref: ./PaymentDocumentType.yaml
description: >-
What the file is. Must be one of the `acceptedDocumentTypes` of the
requirement named by `requirementId`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
required: true
content:
multipart/form-data:
schema:
$ref: ./QuoteDocumentUploadRequest.yaml
encoding:
file:
contentType: application/pdf, image/jpeg, image/png
16 changes: 16 additions & 0 deletions openapi/components/schemas/quotes/QuoteRequest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ properties:
first with `immediatelyExecute: false` and then call
`POST /quotes/{quoteId}/execute` with the `Grid-Wallet-Signature` stamp
header.

Not supported either when the quote requires supporting documents, since
those can only be uploaded against a quote that already exists. Setting
it on such a request returns `400 INVALID_INPUT`. Create the quote with
`immediatelyExecute: false`, upload every document in
`documentRequirements` via `POST /quotes/{quoteId}/documents`, then call
`POST /quotes/{quoteId}/execute`.
example: false
description:
type: string
Expand All @@ -68,6 +75,15 @@ properties:
example: '12345'
purposeOfPayment:
$ref: ./PurposeOfPayment.yaml
serviceCategory:
$ref: ./ChinaB2BServiceCategory.yaml
description: >-
What kind of service the payment pays for. Required on a business payout
in CNY to China whose `purposeOfPayment` is `SERVICE_CHARGES`, where the
receiving bank needs the breakdown to clear the payment; omitting it on
such a request returns `400 INVALID_INPUT`. The rule is specific to that
route, so the field is optional in the schema and enforced at runtime.
Ignored elsewhere.
platformFeeOverride:
$ref: ./PlatformFeeOverride.yaml
scaFactor:
Expand Down
2 changes: 2 additions & 0 deletions openapi/openapi.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 31 additions & 1 deletion openapi/paths/quotes/quotes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,23 @@ post:
lockedCurrencySide: SENDING
lockedCurrencyAmount: 1000
description: 'Payment for invoice #1234'
chinaB2BServiceCharges:
summary: >-
China B2B payout requiring supporting documents. Created without
immediate execution so the documents can be uploaded.
value:
source:
sourceType: ACCOUNT
accountId: InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965
destination:
destinationType: ACCOUNT
accountId: ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123
lockedCurrencySide: SENDING
lockedCurrencyAmount: 1000000
immediatelyExecute: false
purposeOfPayment: SERVICE_CHARGES
serviceCategory: COMMISSION_ON_SERVICES
description: 'Q3 sales commission'
realTimeFundingToSparkWallet:
summary: Real-time funding to Spark Wallet as an on-ramp flow. Immediate execution.
value:
Expand All @@ -106,6 +123,13 @@ post:
Transfer quote created successfully. The response includes exchange rates,
fees, and transfer details. For transfers involving UMA addresses, payment
instructions are also included for execution through banking systems.

A corridor that requires supporting documents returns the quote with
`documentStatus: PENDING` and a `documentRequirements` array, and
without `paymentInstructions`. Upload one file per requirement via
`POST /quotes/{quoteId}/documents`; the upload that satisfies the last
one flips `documentStatus` to `COMPLETE`, after which the quote can be
executed.
content:
application/json:
schema:
Expand Down Expand Up @@ -150,7 +174,13 @@ post:
schema:
$ref: ../../components/schemas/quotes/Quote.yaml
'400':
description: Bad request - Missing or invalid parameters
description: >-
Bad request - Missing or invalid parameters. Returned with
`INVALID_INPUT` when `immediatelyExecute` is set on a quote that
requires supporting documents (they can only be uploaded against an
existing quote, so create it with `immediatelyExecute: false`), and
when a China B2B CNY request with `purposeOfPayment: SERVICE_CHARGES`
omits `serviceCategory`.
content:
application/json:
schema:
Expand Down
Loading
Loading