openapi: 3.2.0 info: title: Grid API Tokens API description: API for managing global payments on the open Money Grid. Built by Lightspark. See the full documentation at https://docs.lightspark.com/. version: '2025-10-13' contact: name: Lightspark Support email: support@lightspark.com license: name: Proprietary url: https://lightspark.com/terms servers: - url: https://api.lightspark.com/grid/2025-10-13 description: Production server security: - BasicAuth: [] - AgentAuth: [] tags: - name: API Tokens description: Endpoints to programmatically manage API tokens paths: /tokens: post: summary: Create a new API token description: Create a new API token to access the Grid APIs. operationId: createToken tags: - API Tokens security: - BasicAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ApiTokenCreateRequest' responses: '201': description: API token created successfully content: application/json: schema: $ref: '#/components/schemas/ApiToken' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/Error400' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error401' '500': description: Internal service error content: application/json: schema: $ref: '#/components/schemas/Error500' get: summary: List tokens description: 'Retrieve a list of API tokens with optional filtering parameters. Returns all tokens that match the specified filters. If no filters are provided, returns all tokens (paginated).' operationId: listTokens tags: - API Tokens security: - BasicAuth: [] parameters: - name: name in: query description: Filter by name of the token required: false schema: type: string - name: createdAfter in: query description: Filter customers created after this timestamp (inclusive) required: false schema: type: string format: date-time - name: createdBefore in: query description: Filter customers created before this timestamp (inclusive) required: false schema: type: string format: date-time - name: updatedAfter in: query description: Filter customers updated after this timestamp (inclusive) required: false schema: type: string format: date-time - name: updatedBefore in: query description: Filter customers updated before this timestamp (inclusive) required: false schema: type: string format: date-time - name: limit in: query description: Maximum number of results to return (default 20, max 100) required: false schema: type: integer minimum: 1 maximum: 100 default: 20 - name: cursor in: query description: Cursor for pagination (returned from previous request) required: false schema: type: string responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/TokenListResponse' '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' '500': description: Internal service error content: application/json: schema: $ref: '#/components/schemas/Error500' /tokens/{tokenId}: parameters: - name: tokenId in: path description: System-generated unique token identifier required: true schema: type: string get: summary: Get API token by ID description: Retrieve an API token by their system-generated ID operationId: getTokenById tags: - API Tokens security: - BasicAuth: [] responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/ApiToken' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error401' '404': description: Token not found content: application/json: schema: $ref: '#/components/schemas/Error404' '500': description: Internal service error content: application/json: schema: $ref: '#/components/schemas/Error500' delete: summary: Delete API token by ID description: Delete an API token by their system-generated ID operationId: deleteTokenById tags: - API Tokens security: - BasicAuth: [] responses: '204': description: API token deleted successfully '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/Error400' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/Error401' '404': description: Token not found content: application/json: schema: $ref: '#/components/schemas/Error404' '500': description: Internal service error content: application/json: schema: $ref: '#/components/schemas/Error500' components: schemas: TokenListResponse: type: object required: - data - hasMore properties: data: type: array description: List of tokens matching the filter criteria items: $ref: '#/components/schemas/ApiToken' hasMore: type: boolean description: Indicates if more results are available beyond this page nextCursor: type: string description: Cursor to retrieve the next page of results (only present if hasMore is true) totalCount: type: integer description: Total number of tokens matching the criteria (excluding pagination) PaymentDocumentRequirementId: type: string description: 'A stable identifier for one required document within a purpose''s requirements. The same ID means the same requirement across quotes. It is separate from `PaymentDocumentType`. The requirement ID names the document to supply, and the document type names what a file is. The two differ where a requirement accepts alternatives. For example, a file declared as either `PURCHASE_ORDER` or `DELIVERY_SLIP` fills the `SUPPORTING_PROOF` requirement. [Supporting Documents](https://docs.lightspark.com/payouts-and-b2b/payment-flow/send-payment#supporting-documents) lists the IDs each purpose requires. Treat the ID as an opaque value, not a member of a fixed list. Grid may add new IDs as requirements change.' example: SUPPORTING_PROOF FieldError: type: object required: - field description: One field-level validation failure. Field-validation errors on submit endpoints (e.g. `POST /customers`, `PATCH /customers/{id}`) emit an array of these under `details.errors` so platforms can render form-field-level UX for every failure in a single round-trip. properties: field: type: string description: Dot-notation path to the offending field. example: identifier constraint: $ref: '#/components/schemas/FieldConstraint' message: type: string description: Human-readable explanation of what's wrong with this field. example: Value is not one of the allowed enum members. ApiTokenCreateRequest: type: object required: - name - permissions properties: name: type: string description: Name of the token to help identify it example: Sandbox read-only permissions: type: array description: A list of permissions to grant to the token items: $ref: '#/components/schemas/Permission' Error500: type: object required: - reason - code properties: code: type: string description: '| Error Code | Description | |------------|-------------| | GRID_SWITCH_ERROR | Grid switch error | | INTERNAL_ERROR | Internal server or UMA error | ' enum: - GRID_SWITCH_ERROR - INTERNAL_ERROR reason: type: string description: Error message details: type: object description: Additional error details additionalProperties: true ApiToken: type: object required: - id - name - permissions - clientId - createdAt - updatedAt properties: id: type: string description: System-generated unique identifier example: Token:019542f5-b3e7-1d02-0000-000000000001 name: type: string description: Name of the token example: Sandbox read-only token permissions: type: array description: A list of permissions granted to the token items: $ref: '#/components/schemas/Permission' clientId: type: string description: An opaque identifier that should be used as a client_id (or username) in the HTTP Basic Authentication scheme when issuing http requests to Grid. example: 01947d2284054f890000e63bca4810df clientSecret: type: string description: The secret that should be used to authenticate against Grid API. This secret is not stored and will never be available again after creation. Platform must keep this secret secure as it grants access to the account. example: ed0ad25881e234cc28fb2dec0a4fe64e4172 expiresAt: type: string format: date-time description: Timestamp after which the token no longer authenticates. Requests made with an expired token return `401`. Omitted when the token does not expire. example: '2026-07-21T17:32:28Z' createdAt: type: string format: date-time description: Creation timestamp example: '2025-07-21T17:32:28Z' updatedAt: type: string format: date-time description: Last update timestamp example: '2025-07-21T17:32:28Z' Error404: type: object required: - reason - code properties: code: type: string description: '| Error Code | Description | |------------|-------------| | TRANSACTION_NOT_FOUND | Transaction not found | | INVITATION_NOT_FOUND | Invitation not found | | USER_NOT_FOUND | Customer not found | | QUOTE_NOT_FOUND | Quote not found | | LOOKUP_REQUEST_NOT_FOUND | Lookup request not found | | TOKEN_NOT_FOUND | Token not found | | BULK_UPLOAD_JOB_NOT_FOUND | Bulk upload job not found | | REFERENCE_NOT_FOUND | Reference not found | | UMA_NOT_FOUND | The UMA address is well-formed but no receiver exists at the counterparty VASP | | STABLECOIN_PROVIDER_ACCOUNT_NOT_FOUND | Stablecoin provider account link not found | | ACCOUNT_NOT_FOUND | Account not found | | AUTH_METHOD_NOT_FOUND | Authentication credential not found | | CUSTOMER_NOT_FOUND | Customer not found | | DOCUMENT_HOLDER_NOT_FOUND | Document holder not found | | NOT_FOUND | The requested resource was not found | | PAYMENT_URL_NOT_FOUND | Payment URL not found | | PLATFORM_NOT_FOUND | Platform not found | | REQUEST_NOT_FOUND | Pending request not found | | SESSION_NOT_FOUND | Session not found | | STABLECOIN_EXTERNAL_ACCOUNT_NOT_FOUND | Stablecoin external account not found | | STABLECOIN_NOT_FOUND | Stablecoin not found | | STABLECOIN_OPERATION_NOT_FOUND | Stablecoin operation not found | | VERIFICATION_NOT_FOUND | Verification not found | | PAYMENT_DOCUMENT_NOT_FOUND | Payment document not found | ' enum: - TRANSACTION_NOT_FOUND - INVITATION_NOT_FOUND - USER_NOT_FOUND - QUOTE_NOT_FOUND - LOOKUP_REQUEST_NOT_FOUND - TOKEN_NOT_FOUND - BULK_UPLOAD_JOB_NOT_FOUND - REFERENCE_NOT_FOUND - UMA_NOT_FOUND - STABLECOIN_PROVIDER_ACCOUNT_NOT_FOUND - ACCOUNT_NOT_FOUND - AUTH_METHOD_NOT_FOUND - CUSTOMER_NOT_FOUND - DOCUMENT_HOLDER_NOT_FOUND - NOT_FOUND - PAYMENT_URL_NOT_FOUND - PLATFORM_NOT_FOUND - REQUEST_NOT_FOUND - SESSION_NOT_FOUND - STABLECOIN_EXTERNAL_ACCOUNT_NOT_FOUND - STABLECOIN_NOT_FOUND - STABLECOIN_OPERATION_NOT_FOUND - VERIFICATION_NOT_FOUND - PAYMENT_DOCUMENT_NOT_FOUND reason: type: string description: Error message details: type: object description: Additional error details additionalProperties: true Error400: type: object required: - reason - code properties: code: type: string description: '| Error Code | Description | |------------|-------------| | INVALID_INPUT | Invalid input provided | | END_USER_TERMS_VERSION_NOT_FOUND | The submitted version is not supported for the agreement it was sent for | | MISSING_MANDATORY_USER_INFO | Required customer information is missing | | INVITATION_ALREADY_CLAIMED | Invitation has already been claimed | | INVITATIONS_NOT_CONFIGURED | Invitations are not configured | | INVALID_UMA_ADDRESS | UMA address format is invalid | | INVITATION_CANCELLED | Invitation has been cancelled | | INVALID_RECEIVER | Receiver is invalid | | PARSE_PAYREQ_RESPONSE_ERROR | Error parsing receiver PayReq response | | CERT_CHAIN_INVALID | Counterparty certificate chain is invalid | | CERT_CHAIN_EXPIRED | Counterparty certificate chain has expired | | INVALID_PUBKEY_FORMAT | Counterparty Public key format is invalid | | MISSING_REQUIRED_UMA_PARAMETERS | Counterparty required UMA parameters are missing | | SENDER_NOT_ACCEPTED | The receiving institution declined this sender. Final; a retry returns the same answer | | AMOUNT_OUT_OF_RANGE | Amount is out of range | | INVALID_CURRENCY | Currency is invalid | | INVALID_TIMESTAMP | Timestamp is invalid | | INVALID_NONCE | Nonce is invalid | | INVALID_REQUEST_FORMAT | Request format is invalid | | INVALID_BANK_ACCOUNT | Bank account is invalid | | SELF_PAYMENT | Self payment not allowed | | PARSE_LNURLP_RESPONSE_ERROR | Error parsing LNURLP response | | INVALID_AMOUNT | Amount is invalid | | WEBHOOK_ENDPOINT_NOT_SET | Webhook endpoint is not set | | WEBHOOK_DELIVERY_ERROR | Webhook delivery error | | LOW_QUALITY | Document quality too low to process | | DATA_MISMATCH | Document details don''t match provided information | | EXPIRED | Document has expired | | SUSPECTED_FRAUD | Document suspected of being forged or edited | | UNSUITABLE_DOCUMENT | Document type is not accepted or not supported | | INCOMPLETE | Document is missing pages or sides | | EMAIL_OTP_CREDENTIAL_ALREADY_EXISTS | An EMAIL_OTP credential is already registered on the target internal account; only one email OTP credential is supported per internal account at this time | | SMS_OTP_CREDENTIAL_ALREADY_EXISTS | An SMS_OTP credential is already registered on the target internal account; only one SMS OTP credential is supported per internal account at this time | | PASSKEY_CREDENTIAL_ALREADY_EXISTS | A PASSKEY credential with the same WebAuthn credentialId is already registered on the target internal account | | AUTH_CREDENTIAL_VERIFICATION_REQUIRED | The new email or phone number has no verified replacement credential | | AUTH_CREDENTIAL_VERIFICATION_EXPIRED | The replacement credential''s verification has expired | | STABLECOIN_PROVIDER_ACCOUNT_INVALID | The stablecoin provider account link is not usable | | STABLECOIN_PROVIDER_ACCOUNT_REVOKED | The stablecoin provider account link has been revoked | | STABLECOIN_PROVIDER_ACCOUNT_SELECTION_REQUIRED | Multiple active provider account links exist; pass `stablecoinProviderAccountId` to select one | | CARDHOLDER_KYC_NOT_APPROVED | The cardholder''s KYC status is not `APPROVED`, so a card cannot be issued | | ACCOUNTHOLDER_AGREEMENT_NOT_ACCEPTED | The customer create request omits an accountholder agreement its accounts require | | TRANSACTION_SIZE_LIMIT_EXCEEDED | The requested amount exceeds the configured maximum single-transaction amount for this trade corridor or withdrawal currency | | EXTERNAL_ACCOUNT_VERIFICATION_REQUIRED | The destination account''s ownership must be verified before this transfer can proceed | | INSUFFICIENT_FUNDS | Insufficient funds for this operation | | QUOTE_EXPIRED | The quote has expired; request a new quote | | QUOTE_RATE_UNAVAILABLE | No exchange rate is available for this corridor right now | | STABLECOIN_AMOUNT_NOT_REPRESENTABLE | The amount cannot be represented at the token''s precision | | STABLECOIN_BURN_SOURCE_NOT_SUPPORTED | The burn source account cannot be used for this operation | | STABLECOIN_EXTERNAL_ACCOUNT_LINK_FAILED | Linking the external account for stablecoin operations failed | | STABLECOIN_EXTERNAL_ACCOUNT_LINK_METHOD_REQUIRED | The external account needs a link method before it can be used | | STABLECOIN_EXTERNAL_ACCOUNT_NOT_LINKED | The external account is not linked for stablecoin operations | | STABLECOIN_EXTERNAL_ACCOUNT_NOT_SUPPORTED | This external account type is not supported for stablecoin operations | | STABLECOIN_EXTERNAL_ACCOUNT_PROVIDER_LINK_FAILED | The provider could not link the external account | | STABLECOIN_EXTERNAL_ACCOUNT_PROVIDER_LINK_REQUIRED | The external account must be linked with the provider first | | STABLECOIN_GRID_OPERATIONS_NOT_ENABLED | The stablecoin is not enabled for Grid operations | | STABLECOIN_NOT_PROVISIONED | The stablecoin is not provisioned for issuer operations | | STABLECOIN_OPERATION_NOT_SUPPORTED | The stablecoin does not support this operation | | STABLECOIN_PROVIDER_ERROR | The stablecoin provider rejected the operation | | STABLECOIN_PROVIDER_SOURCE_NOT_LINKED | The provider source account is not linked | | STABLECOIN_VERIFICATION_FAILED | The stablecoin could not be verified with the provider | | DOCUMENTS_REQUIRED | The destination requires supporting documents for the quote''s `purposeOfPayment` that the request did not supply. `details.missingRequirements` lists the requirement ID of each one | ' enum: - INVALID_INPUT - END_USER_TERMS_VERSION_NOT_FOUND - MISSING_MANDATORY_USER_INFO - INVITATION_ALREADY_CLAIMED - INVITATIONS_NOT_CONFIGURED - INVALID_UMA_ADDRESS - INVITATION_CANCELLED - INVALID_RECEIVER - PARSE_PAYREQ_RESPONSE_ERROR - CERT_CHAIN_INVALID - CERT_CHAIN_EXPIRED - INVALID_PUBKEY_FORMAT - MISSING_REQUIRED_UMA_PARAMETERS - SENDER_NOT_ACCEPTED - AMOUNT_OUT_OF_RANGE - INVALID_CURRENCY - INVALID_TIMESTAMP - INVALID_NONCE - INVALID_REQUEST_FORMAT - INVALID_BANK_ACCOUNT - SELF_PAYMENT - PARSE_LNURLP_RESPONSE_ERROR - INVALID_AMOUNT - WEBHOOK_ENDPOINT_NOT_SET - WEBHOOK_DELIVERY_ERROR - LOW_QUALITY - DATA_MISMATCH - EXPIRED - SUSPECTED_FRAUD - UNSUITABLE_DOCUMENT - INCOMPLETE - EMAIL_OTP_CREDENTIAL_ALREADY_EXISTS - SMS_OTP_CREDENTIAL_ALREADY_EXISTS - PASSKEY_CREDENTIAL_ALREADY_EXISTS - AUTH_CREDENTIAL_VERIFICATION_REQUIRED - AUTH_CREDENTIAL_VERIFICATION_EXPIRED - STABLECOIN_PROVIDER_ACCOUNT_INVALID - STABLECOIN_PROVIDER_ACCOUNT_REVOKED - STABLECOIN_PROVIDER_ACCOUNT_SELECTION_REQUIRED - CARDHOLDER_KYC_NOT_APPROVED - ACCOUNTHOLDER_AGREEMENT_NOT_ACCEPTED - TRANSACTION_SIZE_LIMIT_EXCEEDED - EXTERNAL_ACCOUNT_VERIFICATION_REQUIRED - INSUFFICIENT_FUNDS - QUOTE_EXPIRED - QUOTE_RATE_UNAVAILABLE - STABLECOIN_AMOUNT_NOT_REPRESENTABLE - STABLECOIN_BURN_SOURCE_NOT_SUPPORTED - STABLECOIN_EXTERNAL_ACCOUNT_LINK_FAILED - STABLECOIN_EXTERNAL_ACCOUNT_LINK_METHOD_REQUIRED - STABLECOIN_EXTERNAL_ACCOUNT_NOT_LINKED - STABLECOIN_EXTERNAL_ACCOUNT_NOT_SUPPORTED - STABLECOIN_EXTERNAL_ACCOUNT_PROVIDER_LINK_FAILED - STABLECOIN_EXTERNAL_ACCOUNT_PROVIDER_LINK_REQUIRED - STABLECOIN_GRID_OPERATIONS_NOT_ENABLED - STABLECOIN_NOT_PROVISIONED - STABLECOIN_OPERATION_NOT_SUPPORTED - STABLECOIN_PROVIDER_ERROR - STABLECOIN_PROVIDER_SOURCE_NOT_LINKED - STABLECOIN_VERIFICATION_FAILED - DOCUMENTS_REQUIRED reason: type: string description: Error message details: type: object description: Additional error details. Shape varies by `code`. For field-validation errors on submit endpoints (e.g. `POST /customers`, `PATCH /customers/{id}`), `details.errors[]` enumerates every invalid field so platforms can render form-field-level UX for the entire request in a single round-trip. properties: errors: type: array description: One entry per invalid field. Present on field-validation errors from submit endpoints. items: $ref: '#/components/schemas/FieldError' missingRequirements: type: array description: The requirement ID of each required document that the quote request did not supply. Present on `DOCUMENTS_REQUIRED`. items: $ref: '#/components/schemas/PaymentDocumentRequirementId' additionalProperties: true Permission: type: string enum: - VIEW - TRANSACT - MANAGE description: 'Permission of an API token that determines what actions the token can perform: VIEW: Can view all data, including platform config, customers and transactions TRANSACT: Can send payments MANAGE: Can manage platform config, api tokens and customers' Error401: type: object required: - reason - code properties: code: type: string description: '| Error Code | Description | |------------|-------------| | UNAUTHORIZED | Issue with API credentials | | INVALID_SIGNATURE | Signature header is invalid | | WALLET_SIGNATURE_MISSING | The `Grid-Wallet-Signature` header is required for this Embedded Wallet action but was not supplied | | WALLET_SIGNATURE_MALFORMED | The `Grid-Wallet-Signature` header could not be parsed (bad encoding, structure, or fields) | | WALLET_SIGNATURE_BODY_MISMATCH | The `Grid-Wallet-Signature` was computed over a different request body than the one received | | WALLET_SIGNATURE_INVALID | The `Grid-Wallet-Signature` failed cryptographic verification against the registered credential | | REQUEST_ID_MISSING | The `Request-Id` header is required on the signed retry but was not supplied (paired with `Grid-Wallet-Signature`) | ' enum: - UNAUTHORIZED - INVALID_SIGNATURE - WALLET_SIGNATURE_MISSING - WALLET_SIGNATURE_MALFORMED - WALLET_SIGNATURE_BODY_MISMATCH - WALLET_SIGNATURE_INVALID - REQUEST_ID_MISSING reason: type: string description: Error message details: type: object description: Additional error details additionalProperties: true FieldConstraint: type: object description: Machine-readable validator hint accompanying a 400 `INVALID_INPUT` error. Consumers use it to drive form UI (input types, dropdowns, masking, length limits) and to pre-validate the field client-side before re-submitting. Fields are additive. properties: format: type: string description: Named format the value must satisfy — HTML5 input type names (`email`, `tel`, `url`, `date`, ...) or semantic slugs (`iso3166-1-alpha-2`, `bcp47-language-tag`, `us-ssn`, `e.164`). example: email pattern: type: string description: Regular expression the value must match (JavaScript-flavor). example: ^\d{5}(-\d{4})?$ enum: type: array items: type: string description: Allowed values when the field is drawn from a fixed set. example: - SSN - ITIN - NON_US_TAX_ID minLength: type: integer description: Minimum length in characters. example: 1 maxLength: type: integer description: Maximum length in characters. example: 500 securitySchemes: BasicAuth: type: http scheme: basic description: API token authentication using format `:` AgentAuth: type: http scheme: bearer description: 'Bearer token authentication for agent-scoped endpoints. The token is the `accessToken` returned when redeeming a device code via `POST /agents/device-codes/redeem`. Agent credentials are user-scoped: all requests are automatically bound to the agent''s associated customer and subject to the agent''s policy.' WebhookSignature: type: apiKey in: header name: X-Grid-Signature description: 'Secp256r1 (P-256) asymmetric signature of the webhook payload, which can be used to verify that the webhook was sent by Grid. To verify the signature: 1. Get the Grid public key provided to you during integration 2. Decode the base64 signature from the header 3. Create a SHA-256 hash of the request body 4. Verify the signature using the public key and the hash If the signature verification succeeds, the webhook is authentic. If not, it should be rejected. ' x-provenance: method: harvested publisher: Lightspark source: https://docs.lightspark.com/openapi.yaml note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json); stamped by stamp-openapi-provenance.py (roadmap#793)