# Tesser Documentation > Complete documentation for Large Language Models --- ## Document: Treasury Updates Webhook events fired during the deposit and withdrawal lifecycle URL: /webhooks/treasury-updates # Treasury Updates Treasury webhook events are delivered inside the standard envelope described on the [General](./general) page. The `data.object` field contains a [Deposit](/api/~schemas#Deposit) or [Withdrawal](/api/~schemas#Withdrawal) resource. ## Deposit Events | Event | Fired when | | --- | --- | | `deposit.created` | Deposit record is created | | `deposit.submitted` | Deposit has been submitted for processing | | `deposit.confirmed` | Deposit is confirmed on-chain or by the partner | ## Withdrawal Events | Event | Fired when | | --- | --- | | `withdrawal.created` | Withdrawal record is created | | `withdrawal.submitted` | Withdrawal has been submitted for processing | | `withdrawal.confirmed` | Withdrawal is confirmed on-chain or by the partner | ## Step Events Once a deposit or withdrawal begins execution, individual step lifecycle events fire as each step progresses: | Event | Fired when | | --- | --- | | `step.submitted` | Step has been submitted for execution | | `step.confirmed` | Step execution is confirmed on-chain or by the partner | | `step.finalized` | Step has reached finality | | `step.completed` | Step finished successfully | | `step.failed` | Step encountered an error and could not complete | The `data.object` for step events is a [TransferStep](/api/~schemas#transfer-step) resource. ## Payload The `data.object` in each event contains the full resource. For the complete field reference, see the [Deposit schema](/api/~schemas#Deposit) and [Withdrawal schema](/api/~schemas#Withdrawal). --- ## Document: Payment Updates Webhook events fired during the payment lifecycle URL: /webhooks/payment-updates # Payment Updates Payment webhook events are delivered inside the standard envelope described on the [General](./general) page. The `data.object` field contains a [Payment](/api/~schemas#Payment) resource. ## Event Types | Event | Fired when | | --- | --- | | `payment.quote_created` | Exchange rate is locked and the quote is ready | | `payment.steps_created` | Route planning is complete and execution steps are created | | `payment.balance_updated` | Balance check result is available (reserved or awaiting funds) | | `payment.risk_updated` | Risk status has changed (e.g. `auto_approved`, `awaiting_decision`, or `auto_rejected`) | For a detailed breakdown of what each event means in the context of a payout, see [Payout Workflow](/how-tos/send-a-stablecoin-payout/payout-workflow). ## Step Events Once steps are created (`payment.steps_created`), individual step lifecycle events fire as each step progresses: | Event | Fired when | | --- | --- | | `step.submitted` | Step has been submitted for execution | | `step.confirmed` | Step execution is confirmed on-chain or by the partner | | `step.finalized` | Step has reached finality | | `step.completed` | Step finished successfully | | `step.failed` | Step encountered an error and could not complete | The `data.object` for step events is a [TransferStep](/api/~schemas#transfer-step) resource. ## Payload The `data.object` in each event contains the full payment resource, including its steps. For the complete field reference, see the [Payment schema](/api/~schemas#Payment). For a walkthrough of how these events appear during a real payout lifecycle, see [Create a Payout](/how-tos/send-a-stablecoin-payout/create-a-stablecoin-payout). ## Key Status Fields For details on how `risk_status` and `balance_status` evolve through a payout, see [Payout Workflow](/how-tos/send-a-stablecoin-payout/payout-workflow). --- ## Document: General Common envelope structure shared by all Tesser webhook events URL: /webhooks/general # General All Tesser webhook events share a common envelope structure. The envelope wraps event-specific data in a consistent format so your handler can route and process events uniformly. ## Envelope Fields | Field | Type | Description | | --- | --- | --- | | `id` | string | Unique event identifier | | `type` | string | Event type in `scope.action` format (e.g. `payment.quote_created`) | | `created_at` | string | ISO 8601 timestamp of when the event was created | | `data` | object | Contains the event-specific payload under `data.object` | ## Event Type Format Event types follow the pattern **`scope.action`**. Current scopes are `payment`, `deposit`, `withdrawal`, and `step`. See [Payment Updates](./payment-updates) and [Treasury Updates](./treasury-updates) for event details. ## Example Payload ```json { "id": "event_111", "type": "payment.quote_created", "created_at": "2025-12-01T09:00:00.045Z", "data": { "object": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "from_account_id": null, "funding_account_id": null, "to_account_id": null, "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_amount": "1000", "to_currency": "MXN", "to_network": null, "risk_status": "unchecked", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "unreserved", "balance_reserved_at": null, "steps": [], "created_at": "2025-12-01T09:00:00.000Z", "updated_at": "2025-12-01T09:00:00.040Z", "expires_at": "2025-12-01T23:59:59.999Z" } } } ``` --- ## Document: Webhook Authentication Verify that webhooks originate from Tesser using Ed25519 signatures URL: /webhooks/authentication # Webhook Authentication Tesser signs every outgoing webhook request with an **Ed25519** asymmetric signature. You should verify this signature on your server before processing the payload. ## Signature Header Each webhook request includes the following headers: | Header | Description | | --- | --- | | `X-Tesser-Signature` | Base64-encoded Ed25519 signature of the request body | | `Content-Type` | Always `application/json` | | `User-Agent` | `Tesser-Webhooks/1.0` | The signature is computed over the exact UTF-8 bytes of the JSON request body. Do not parse and re-serialize the body before verifying — use the raw bytes. ## Public Key Tesser's webhook public key is provided in **SPKI DER** format, base64-encoded. You can also import it from the SDK types package: ```ts import { WEBHOOK_PUBLIC_KEY } from "@tesser-payments/types"; ``` ## Verifying Signatures ```js import { createPublicKey, verify } from "node:crypto"; import { WEBHOOK_PUBLIC_KEY } from "@tesser-payments/types"; function verifyWebhook(rawBody, signature) { const publicKeyObj = createPublicKey({ key: Buffer.from(WEBHOOK_PUBLIC_KEY, "base64"), type: "spki", format: "der", }); return verify( null, Buffer.from(rawBody, "utf8"), publicKeyObj, Buffer.from(signature, "base64"), ); } // In your webhook handler: const signature = req.headers["x-tesser-signature"]; const isValid = verifyWebhook(req.rawBody, signature); if (!isValid) { return res.status(401).json({ error: "Invalid signature" }); } ``` ## Important Notes - Always verify using the **raw request body** bytes. Parsing the JSON and re-serializing may change whitespace or key order, which will invalidate the signature. - If verification fails, respond with `401` and do not process the event. - The public key may be rotated in the future. Key rotation will be announced in advance and communicated through the Tesser Dashboard. --- ## Document: Treasury Management Stablecoin balance and yield management URL: /overviews/treasury-management # Treasury Management Tesser provides comprehensive treasury management capabilities for stablecoins. > Note: Most treasury management features are currently under development. Contact us to learn more about our roadmap and early access programs. **Balance Management** Effective balance management ensures payments can be processed successfully: - **Balance checks:** Before payment processing, the system validates that the source treasury wallet has sufficient funds to cover the payment amount and associated network fees and processing costs - **Balance reconciliation:** Regular balance verification for wallets against blockchain state - **Balance Monitoring:** Low balance alerts when balances fall below thresholds or based on typical usage - **Automatic Rebalancing**: Rebalance across tokens and chains to maintain optimal distribution **Yield Generation** Generate yield on otherwise idle stablecoin balances: - **Multiple Providers**: Integrations with yield providers to offer a range of options - **Risk Spectrum**: From US treasury-backed yield (lower risk) to DeFi yield options (higher yield, higher risk) - **Policy Controls**: Enable yield only where allowed by your policy and risk appetite - **Operational Safety**: Emphasis on capital preservation and liquidity availability for payments **Treasury Analytics** Comprehensive reporting and analytics: - **Utilization Reports**: Track fund usage across corridors - **Yield Performance**: Monitor returns on treasury holdings - **Cash Flow Forecasting**: Predict funding needs based on historical patterns - **Cost Analysis**: Compare treasury costs across different strategies --- ## Document: Transfers Internal movement of funds URL: /overviews/transfers # Transfers A Transfer is a movement of funds on the Tesser platform among accounts that your organization or your customers own. There are no arms-length third parties involved in a transfer. Transfers involving two treasury/customer wallets are not routed through shield wallets. **Transfers occur during:** - **Rebalancing among treasury wallets:** To ensure sufficient funds in your organization’s wallet(s), you or Tesser with your authorization may redistribute funds among your treasury wallets. - **Funds flow through a shield wallet to/from a Treasury wallet:** When processing a payment, funds will move from a treasury wallet to a shield wallet prior to being distributed to a beneficiary (outbound payment) or from a shield wallet to a treasury wallet (inbound payment). --- ## Document: Supported Tokens and Networks Supported blockchain networks and stablecoins URL: /overviews/tokens-and-networks # Supported Tokens and Networks
**Chain** **Token** **Availability**
POLYGON USDC, USDT Available
ETHEREUM USDC, USDT Coming soon
STELLAR USDC Coming soon
SOLANA USDC, USDT Coming soon
> Note: Need support for other EVM-compatible networks? Contact us and we can quickly add support for additional chains. --- ## Document: Tenants Manage business customers and their integrations URL: /overviews/tenants # Tenants A tenant represents an organization’s customer when that customer is itself a platform with its own users who need to be represented in Tesser’s systems. When an organization’s customers are tenants, originators and/or beneficiaries are customers of the tenant and thus end-customers to the organization. Example structure of resources for an organization with tenants: ![image.png](Tenants/image.png) --- ## Document: Stablecoin Custody Secure non-custodial wallet architecture URL: /overviews/stablecoin-custody # Stablecoin Custody Tesser provides both non-custodial and third-party custodial options for financial institutions to hold and manage stablecoins. We generally recommend a non-custodial model (also called self-custodial) to eliminate dependency on third-party custodians and maintain full operational control. In the self-custodial model, you or your customer is the owner and custodian of the provisioned wallet. This section covers non-custodial (self-custodial) wallets. ## **Wallet Security** Tesser provides enterprise-grade security with a **non-custodial** architecture, meaning: - **Who can custody:** Either your organization or your customers can be the custodians of wallets Tesser provisions. Typically, your organization will custody all the wallets, whether you opt to have a few omnibus wallets for all originator activity or establish one wallet per originator, or a combination of the above. - **You maintain control**: Tesser cannot move your funds without your or your customer’s authorization. For wallets custodied by your customer, your customer can delegate access and authorization for payment instructions to your organization. - **Private key isolation**: Raw private keys are never exposed to Tesser, your software, or your team. - **Secure enclaves**: Private API keys are generated and used for access to the wallet. These keys are generated and stored in hardware-isolated secure enclaves. - **Cryptographic attestation**: Cryptographic proof that only authorized code is running - **Reproducible deployments**: Auditable system configurations with minimal attack surface - **End-to-end audit trail**: Complete cryptographic verification of all operations - **Automated backup management**: We handle secure backup and disaster recovery for your keys - **Multi-factor access controls**: Hardware-backed authentication and authorization - **Quorum-based operations**: Distributed security architecture preventing single points of compromise - **Enclave secure channels**: Direct encrypted communication between secure enclaves and authorized users ## **Wallet Provisioning** During integration, wallets can be created for your team to support testing. Certain payment operations are gated until full production approval is granted. Once in production, wallets can be provisioned on-demand for omnibus treasury management purposes or per customer. Retrieve wallets: ```bash curl -X GET https://api.tesser.xyz/wallets \ -H "Authorization: Bearer your-access-token" ``` Each wallet includes `id`, `workspace_id` ,`address` (and one or more associated token addresses `ata_address`for Solana), and friendly `name` . Optionally, wallets can be assigned to a counterparty by specifying a `counterparty_id` . Wallets can hold balances in more than one stablecoin, denominated by `currency_symbol`, and operate on one or more network, denominated by `network` . --- ## Document: Resources Overview Overview of the Platform API Resources URL: /overviews/resources-overview # Resources Overview The table below outlines the core resources of the Tesser platform and how they relate to each other.
Resource Description
Organization

An organization represents Tesser’s customer, with whom Tesser has a contractual relationship. All other resources belong to an organization.{" "}

Workspace

A workspace is a container for counterparties, accounts, payments, and deposits/withdrawals. Users and their roles, API keys, and webhooks are also established at the workspace level.

Every organization is starts out with with one workspace in the Tesser platform. Additional workspaces can be created by contacting Tesser Customer Support. You may want an additional workspace to segregate activity by line of business, business unit, geography, etc.

Tenant

A tenant represents an organization’s customer when that customer is itself a platform with its own users who need to be represented in Tesser’s systems. When an organization’s customers are tenants, originators and/or beneficiaries are customers of the tenant, and thus end-customers to the organization.{" "}

{"*Note: Most organizations will not need to use tenants to manage their integrations with Tesser."}

Counterparty

A counterparty represents an originator (ultimate sender) or beneficiary (ultimate receiver) of a payment. Counterparties can be individuals or businesses. Counterparties are associated to Accounts and belong to a Workspace.

Registering counterparties in advance of submitting payments enables sanction screening and helps meet regulatory requirements. Counterparty information will be transmitted for fiat payouts and, as applicable,{" "} for stablecoin payouts and be included in payment instructions sent to fiat off-ramps to comply with Travel Rule obligations.

Account

An account represents a store of value that holds fiat currency(ies) or stablecoin(s). Accounts can belong to a counterparty or to a workspace. Accounts may be external to the Tesser platform (e.g. pre-existing fiat bank accounts or wallets) or wallets provisioned by Tesser.

Quote

A quote represents the cost to deliver a payment to a beneficiary. Quotes include the exchange rate between the source currency and the destination currency.{" "} Quotes can be based on a source amount and currency to be sent or a destination amount and currency to be delivered.

Payment

A payment is the movement of funds from an account provisioned by Tesser to a third party, or vice versa. Most commonly, payments will move funds from an originator to a beneficiary. Payments may be outbound (aka payouts) or inbound (receiving stablecoins, aka pay-ins).{" "}

Payments also include funds movement to/from a yield provider.

Deposit/Withdrawal

Deposits and withdrawals are first-party movements of funds into or out of treasury wallets.

Deposits can occur by on-ramping funds through a liquidity provider or via an on-chain transfer that you originate from a wallet your organization custodies that was not provisioned by Tesser.

Withdrawals can occur by off-ramping funds through a liquidity provider or by creating a stablecoin payout to your organization as a beneficiary.{" "}

Transfer

A transfer represents funds movement among Tesser-provisioned wallets for treasury management purposes.

--- ## Document: Payments Movement of funds to/from counterparties URL: /overviews/payments # Payments A payment is the movement of funds from an account provisioned by Tesser to a third party, or vice versa. Most commonly, payments will move funds from an originator to a beneficiary. Payments may be outbound (aka payouts) or inbound (receiving stablecoins, aka pay-ins). Payments also include funds movement to/from a stablecoin yield provider. **Shield wallets in payments processing** Payments always involve a counterparty that is not you or your customer (direct or end-customer):
**Originator is you or your customer/end-customer** **Beneficiary is you or your customer/end-customer**
**Outbound payment**
**Inbound payment**
Because of these arms-length counterparties, Tesser processes payments through “shield” wallets. When funds flow through shield wallets, your organization’s treasury wallets are protected from direct exposure to wallets with potentially risky activity. This means your Treasury wallets never have as direct counterparties a wallet that is, or later becomes tainted with, undesirable activity. Outbound payments: ![image.png](./payments1.png) Inbound payments: ![image.png](./payments2.png) --- ## Document: Payment Planning Quotes, costs, and routing for payments URL: /overviews/payment-planning # Payment Planning As you submit information about the payment request, Tesser will update the plan for the payment. **Cost information** Once you supply information about the `from_currency`, `to_currency`, amount (one of `from_amount` or `to_amount`), and, if a stablecoin payout, the `from_network` and `to_network`, Tesser will respond with a quote for costs associated with the payment. A cost quote includes the following elements: - **Exchange rate**: The quote locks in an exchange rate between the `from_currency` and `to_currency`. For stablecoin payouts, when the source currency of the originator and destination currency of the beneficiary are both stablecoins, the exchange rate will always be 1:1. - ***Note: Exchange rates are implicit based on the `from_amount` and `to_amount` provided in the response to the payment creation request.** - **Requested source or destination amount:** You may request a quote based on the source (from) amount to be sent or the destination (to) amount to be received. For instance, if an originator wants to guarantee a certain amount of MXN to deliver to a beneficiary, you can request a quote for the necessary source amount of a stablecoin given the destination amount and currency. Alternatively, if an originator has a defined amount of USDC to send, the quote will provide information about how much MXN will be delivered to the beneficiary. - **Other fees:** Tesser will supply details on the network or provider fees that can be known prior to payment execution. *Note that blockchain network (gas) fees are only determined at the time of payment execution. After payment execution, gas fee info will be updated on the payment record. - Fee information is stored as an array in the `fees` [object](/api/~schemas#payment-fee) for each step for the payment. Each fee will include information on the `fee_amount`, `fee_currency`, `fee_type`, and optionally `fee_metadata`. **Payment expiration** Payments are valid for a certain amount of time. The length may vary by currency(ies), from/to country, and amount to be paid out. When the expiration time elapses, a new payment must be created in order for the payment to be processed. The time when a payment expires is indicated by `expires_at`. > All payments will have an expiration length, even stablecoin payments. This is because risk and compliance checks must be re-initiated after a certain amount of time has passed if the payment has not been executed. > **Routing** Once you supply information about the `funding_account_id`, `from_account_id`, and `to_account_id`, Tesser will respond with the route plan to execute the payment. - **Transfer steps:** The plan will indicate the route the payment will take to deliver funds to the beneficiary. - Stablecoin payouts will always include at least one step of type `transfer`, and potentially more if token or network swaps are required. - Fiat payouts will always include at least two steps (on-chain `transfer` to an off-ramp and last-mile `transfer` using a local payment network). --- ## Document: Networks Supported blockchain networks URL: /overviews/networks # Networks import { Badge } from "zudoku/ui/Badge"; import { Callout } from "zudoku/ui/Callout"; ## Networks The Networks resource provides information about the blockchain networks supported by the platform. ### Overview We support a curated list of major blockchain networks for crypto transactions. This resource allows you to query the available networks dynamically. We recommend dynamically querying the `/networks` endpoint rather than hardcoding values, as supported networks may expand over time. ### Supported Networks Commonly supported networks include: - ETHEREUM **Ethereum** - POLYGON **Polygon** - STELLAR **Stellar** - SOLANA **Solana** See the [API Reference](/api#tag/Networks) for the live list of supported networks. --- ## Document: Liquidity Providers Integration with global fiat on/off ramps URL: /overviews/liquidity-providers # Liquidity Providers Tesser partners with multiple liquidity providers, also known as on/off ramps, to provide conversion capabilities between stablecoins and fiat currencies. ## **Geographic Coverage** Tesser can tap into liquidity in any region through a global provider network. We activate new corridors with short turnaround based on customer demand. > Need coverage in another region? Contact us and we can quickly add support for additional markets. ## **Onboarding Experience** - If your organization has any existing provider integrations, for example, Circle for USDC, we will reuse those. - For a new provider, where possible, Tesser provides an embedded onboarding experience. For embedded onboarding, your organization will not have to contract with the liquidity provider or proceed through their onboarding flows. Instead, Tesser will use information already collected about your organization and request any additional information needed through the Tesser dashboard or API. ## **On-Ramping** When making a fiat payout to a beneficiary, on-ramps will be typically be used to convert fiat to stablecoins: - **Depositing instructions**: Tesser will generate and communicate instructions specific to each deposit for you to follow. The supported funds delivery mechanisms to an on-ramp are dependent on the local market; on-ramps typically accept push methods (e.g. ACH credit or Wire in the U.S.) - **Same-Day Settlement**: Fast conversion for operational efficiency. *Settlement timing is dependent on the local market and may only be available during business hours - **Competitive Rates**: Institutional-grade FX rates - **Automated Processing**: Scheduled conversions based on payment needs - **Funds distribution:** On-ramped funds can be deposited into one or more wallets that you specify during the deposit instruction process ## **Off-Ramping** As part of Treasury management, your organization may off-ramp funds back into your local fiat currency based on adjusted forecasts. When making a fiat payout to a beneficiary, off-ramps in the destination country will be used to convert stablecoins to the local fiat currency: ### **Payout Methods to Beneficiaries** Currently available: - **Bank Transfers**: Direct deposit to recipient bank accounts - **Digital Wallets**: Local e-wallet integrations Coming soon: - **Mobile Money**: Integration with mobile payment systems (under development) - **Cash Pickup**: Physical cash collection points (under development) ### **Key Benefits** - **Competitive Rates**: Market-leading conversion rates - **Real-time funds delivery:** When real-time payment methods are available in the local market, funds can be delivered to recipients instantly - **Detailed Reporting**: Complete reconciliation data for all conversions --- ## Document: Errors Complete reference of all API error codes and their meanings URL: /overviews/errors # Errors {/* AUTO-GENERATED - DO NOT EDIT. Run: bun run apps/gateway/docs/scripts/generate-error-docs.ts */} ## Error Response Format All API errors return a consistent JSON response: ```json { "errors": [ { "error_code": "domain-YZZZ", "error_message": "Human-readable error description" } ] } ``` ## Error Code Convention Error codes follow the format `{domain}-{YZZZ}` where: - **domain** identifies the resource area (e.g., `accounts`, `payments`, `treasury`) - **Y** indicates the HTTP status category - **ZZZ** is the specific error number within that category | Range | HTTP Status | Meaning | | --- | --- | --- | | 1000–1999 | 404 | Not Found | | 2000–2999 | 401 / 403 | Unauthorized / Forbidden | | 3000–3999 | 400 | Bad Request | | 4000–4999 | 429 | Too Many Requests | | 5000–5999 | 502 / 503 | Bad Gateway / Service Unavailable | :::note Some domains (Circle, Idempotency) use legacy numbering that does not follow the range convention above. ::: ## Accounts
Error Code HTTP Status Error Message Description
`accounts-1000` 404 Account with id '{id}' not found The specified account ID does not exist in this workspace
`accounts-1001` 404 Entity with id '{id}' not found The tenant or counterparty specified does not exist
`accounts-2000` 403 The entity does not belong to your workspace User tries to link an account to an entity that belongs to a different workspace
`accounts-3000` 400 Cannot provide both tenant_id and counterparty_id User provides both tenant_id and counterparty_id when only one is allowed
`accounts-3001` 400 A workspace-level bank account already exists. Only one is allowed per workspace. User tries to create a second workspace-level bank account
`accounts-3002` 400 wallet_address is required for unmanaged wallets (is_managed=false) User creates an unmanaged wallet without providing a wallet_address
`accounts-3003` 400 Cannot determine network for wallet type '{type}' The provided wallet type does not map to a known blockchain network
`accounts-3004` 400 signature is required for managed wallets (is_managed=true) User creates a managed wallet without providing the required signature
`accounts-3005` 400 Invalid signature format. Expected base64-encoded JSON with body and stamp fields. The signature parameter could not be decoded or is missing required fields
`accounts-3006` 400 Circle Mint ledgers require a tenant_id or counterparty_id. Workspace-level sub-ledgers are not supported. User tries to create a Circle Mint ledger without linking it to a tenant or counterparty
`accounts-3007` 400 This entity already has a Circle Mint ledger. Only one Circle Mint ledger per tenant/counterparty is allowed. User tries to create a duplicate Circle Mint ledger for the same entity
`accounts-3008` 400 A workspace-level Circle Mint master wallet ledger already exists. User tries to create a second master wallet ledger for the workspace
`accounts-3009` 400 CIRCLE_MINT provider requires a tenant_id or counterparty_id Circle Mint metadata preparation requires an entity to be linked
`accounts-3010` 400 CIRCLE_MINT provider requires a business entity (not individual) Circle Mint only supports business-classified entities, not individuals
`accounts-3011` 400 Entity is missing required fields for Circle The entity does not have all required business fields populated for Circle onboarding
`accounts-3012` 400 Cannot create VAN: compliance state is not ACCEPTED Virtual account number creation requires the account to have ACCEPTED compliance state
`accounts-3013` 400 Cannot create VAN: circle_wallet_id is missing from account metadata The ledger account does not have a Circle wallet ID configured
`accounts-3014` 400 No workspace-level bank account found. Please create a bank account first. A workspace-level bank account is required but none exists
`accounts-3015` 400 No wire bank accounts found in Circle. Please register a bank account on Circle dashboard first. Circle does not have any wire bank accounts registered for this workspace
`accounts-3016` 400 Multiple wire bank accounts found in Circle Production requires exactly one bank account in Circle, but multiple were found
`accounts-3017` 400 Could not determine Circle bank ID Failed to resolve the Circle bank ID needed for wire transfers
`accounts-3018` 400 Unsupported provider. Must be one of : CIRCLE_MINT, KRAKEN The specified provider is not supported for this operation. Must be one of : CIRCLE_MINT, KRAKEN
`accounts-3019` 400 Account does not have a provider configured The account metadata does not contain provider configuration
`accounts-3020` 400 Entity type must be 'counterparty' or 'tenant' The referenced entity is not a valid type for account linking
`accounts-3100` 400 account_name is required and must be between 1-255 characters User provides an account name that doesn't meet length requirements
`accounts-3101` 400 tenant_id must be a valid UUID User provides a tenant_id that is not a valid UUID
`accounts-3102` 400 counterparty_id must be a valid UUID User provides a counterparty_id that is not a valid UUID
`accounts-3103` 400 bank_name is required and must be between 1-255 characters User provides a bank name that doesn't meet length requirements
`accounts-3104` 400 bank_code_type must be one of: SWIFT, BIC, IBAN, ROUTING User provides a bank_code_type that is not in the allowed enum
`accounts-3105` 400 bank_identifier_code is required User creates a bank account without providing the bank identifier code
`accounts-3106` 400 bank_account_number is required User creates a bank account without providing the account number
`accounts-3107` 400 type must be one of: stablecoin_ethereum, stablecoin_solana, stablecoin_stellar User provides a wallet type that is not in the allowed enum
`accounts-3108` 400 wallet_address must be a valid blockchain address for the specified network User provides a wallet address that doesn't match the expected format for the network
`accounts-3109` 400 Wallet signature is malformed or invalid User provides a signature that is not properly formatted or cannot be verified
`accounts-3110` 400 provider must be one of: CIRCLE_MINT, KRAKEN User provides a provider value that is not in the allowed enum
`accounts-5000` 502 Failed to create wallet. Please try again or contact support if the issue persists. Turnkey or other wallet provider failed during wallet creation
`accounts-5001` 502 Failed to create Circle external entity Circle API call to create the external entity failed
`accounts-5002` 502 Unable to create virtual account number (VAN) for this ledger account. Circle API call to create the virtual account number failed
`accounts-5003` 502 Failed to retrieve entity business fields from vault Basis Theory vault call to retrieve entity fields failed
## Counterparties
Error Code HTTP Status Error Message Description
`counterparties-1000` 404 Counterparty not found The specified counterparty ID does not exist
`counterparties-1001` 404 Tenant with id '{id}' not found. Cannot assign counterparty to non-existent tenant. User tries to assign a counterparty to a tenant_id that doesn't exist
`counterparties-2000` 403 You do not have access to this counterparty User tries to access a counterparty that belongs to a different workspace
`counterparties-3002` 400 classification must be 'individual' or 'business' User provides a classification value that is not 'individual' or 'business'
`counterparties-3003` 400 business_legal_name is required for business counterparties and must be 1-255 characters User creates a business counterparty with missing or improperly formatted business_legal_name
`counterparties-3004` 400 business_address_country is required for business counterparties and must be a valid ISO 3166-1 alpha-2 country code User provides a business_address_country that is not a valid 2-letter country code (e.g., "US", "GB")
`counterparties-3005` 400 individual_first_name is required for individual counterparties and must be 1-255 characters User creates an individual counterparty with missing or improperly formatted first name
`counterparties-3006` 400 individual_last_name is required for individual counterparties and must be 1-255 characters User creates an individual counterparty with missing or improperly formatted last name
`counterparties-3007` 400 individual_address_country is required for individual counterparties and must be a valid ISO 3166-1 alpha-2 country code User provides an individual_address_country that is not a valid 2-letter country code
`counterparties-3008` 400 individual_date_of_birth must be a valid date in YYYY-MM-DD format User provides a date_of_birth that doesn't match the required format or is not a valid date
`counterparties-3009` 400 tenant_id must be a valid UUID User provides a tenant_id that is not a validly formatted UUID
`counterparties-3010` 400 individual_street_address1 is required for individual counterparties User creates an individual counterparty without providing the street address
`counterparties-3011` 400 individual_city is required for individual counterparties User creates an individual counterparty without providing the city
`counterparties-3012` 400 individual_postal_code is required for individual counterparties User creates an individual counterparty without providing the postal code
`counterparties-3013` 400 business_street_address1 is required for business counterparties User creates a business counterparty without providing the street address
`counterparties-3014` 400 business_city is required for business counterparties User creates a business counterparty without providing the city
`counterparties-3015` 400 business_postal_code is required for business counterparties User creates a business counterparty without providing the postal code
## Currencies
Error Code HTTP Status Error Message Description
`currencies-1000` 404 Currency not found The specified currency code does not exist
`currencies-3000` 400 Invalid currency code format User provides a currency code that is not a valid ISO 4217 format (e.g., USD, EUR, GBP)
`currencies-3001` 400 Currency is not supported for this operation User attempts to use a currency that is valid but not supported for the requested operation
`currencies-3002` 400 Invalid currency pair for exchange User attempts to exchange between currencies where the pair is not supported
## Networks
Error Code HTTP Status Error Message Description
`networks-1000` 404 Network not found The specified network identifier does not exist
`networks-3000` 400 Invalid network identifier User provides a network identifier that is not a valid format (e.g., ethereum, polygon, base)
`networks-3001` 400 Network is not supported for this operation User attempts to use a network that is valid but not supported for the requested operation
`networks-3002` 400 Currency is not compatible with the specified network User provides a currency/network combination that is not compatible (e.g., BTC on Ethereum network)
`networks-3003` 400 Network is currently unavailable or under maintenance User attempts to use a network that is temporarily unavailable
`networks-5000` 502 Failed to connect to network RPC endpoint Connection to the blockchain network RPC endpoint failed due to external service error
## Payments
Error Code HTTP Status Error Message Description
`payments-1000` 404 Payment not found The specified payment ID does not exist
`payments-3000` 400 from_network must equal to_network User provides different networks for from_network and to_network
`payments-3001` 400 invalid from_amount or to_amount from_amount and to_amount should be positive and be valid numbers
`payments-3002` 400 Either from_amount or to_amount must be provided. Cannot create payment without an amount. User does not provide either from_amount or to_amount
`payments-3003` 400 Only one of from_amount or to_amount should be provided. The other will be calculated using the exchange rate. User provides both from_amount and to_amount when only one should be provided
`payments-3004` 400 from_network is required for crypto-to-crypto payments User creates a payment with stablecoin from_currency but does not provide from_network
`payments-3005` 400 to_network is required for crypto-to-crypto payments User creates a payment with stablecoin to_currency but does not provide to_network
`payments-3006` 400 Onramp (fiat-to-crypto) payments are not yet supported. Coming soon! User attempts to create an onramp payment which is not supported yet
`payments-3007` 400 Invalid from_currency User provides a from_currency that is not supported
`payments-3008` 400 Invalid to_currency User provides a to_currency that is not supported
`payments-3009` 400 funding_account_id not found User provides a funding_account_id that does not exist
`payments-3010` 400 to_account_id not found User provides a to_account_id that does not exist
`payments-3011` 400 from_account_id not found User provides a from_account_id that does not exist
`payments-3012` 400 Missing input parameter is_approved User submits a payment review without the required is_approved parameter
`payments-3013` 400 signature is malformed or signed with incorrect key User provides a signature that is malformed or not signed with the correct key
`payments-3014` 400 The signed transaction does not match the details of the payment User provides a signature that does not match the payment details
`payments-3015` 400 The exchange rate quote has expired. Please create a new payment to get a fresh quote. User attempts to execute a payment with an expired exchange rate quote (valid for 24 hours)
`payments-3016` 400 Payment quote expiration data is missing. Please create a new payment to get a fresh quote. Payment has an exchange rate but is missing expiration data, indicating a data integrity issue
`payments-3017` 400 to_account has not yet been risk approved by custodian Beneficiary account has a Circle recipient that is still pending verification or has not been registered yet
`payments-3018` 400 from_account_id and to_account_id should not both be managed accounts for payments. Use /v1/treasury/rebalances instead. Transfers between two managed accounts are treasury operations. Use /v1/treasury/rebalances instead.
## Tenants
Error Code HTTP Status Error Message Description
`tenants-1000` 404 Tenant not found The specified tenant ID does not exist
`tenants-2000` 403 You do not have access to this tenant User tries to access a tenant that belongs to a different workspace
`tenants-3000` 400 business_legal_name is required to create a tenant User creates a tenant without providing the required business_legal_name field
`tenants-3001` 400 business_legal_name is required and must be 1-255 characters User provides a business_legal_name that doesn't meet length requirements
`tenants-3002` 400 business_address_country must be a valid ISO 3166-1 alpha-2 country code User provides a business_address_country that is not a valid 2-letter country code
`tenants-3003` 400 webhook_url must be a valid HTTPS URL User provides a webhook_url that is not a properly formatted HTTPS URL
## Treasury
Error Code HTTP Status Error Message Description
`treasury-1000` 404 Rebalance with id '{id}' not found The specified rebalance ID does not exist
`treasury-1001` 404 Transfer step not found for rebalance with id '{id}' The transfer step associated with the rebalance could not be found
`treasury-1002` 404 Account with id '{id}' not found The specified account ID does not exist or does not belong to this workspace
`treasury-1100` 404 Deposit with id '{id}' not found The specified deposit ID does not exist in this workspace
`treasury-1101` 404 Account with id '{id}' not found The specified account ID does not exist or does not belong to this workspace
`treasury-1102` 404 Source account with id '{id}' not found The source bank account for this deposit could not be found
`treasury-1103` 404 VAN account with id '{id}' not found The virtual account number (VAN) account could not be found
`treasury-3000` 400 Only Circle Mint ledger-to-ledger rebalancing is currently supported Rebalancing is only available between Circle Mint ledger accounts
`treasury-3001` 400 Network must not be specified for ledger accounts Ledger-to-ledger rebalances operate without a blockchain network
`treasury-3002` 400 At least one of from_amount or to_amount must be provided A rebalance requires at least one amount to determine the transfer size
`treasury-3003` 400 Invalid currency pair for rebalance The specified from_currency and to_currency combination is not supported for Circle rebalancing
`treasury-3004` 400 from_amount and to_amount must be equal when currencies are the same When both amounts are provided for same-currency rebalances, they must match
`treasury-3005` 400 Source or destination account is missing Circle wallet ID The account does not have a Circle wallet ID configured, which is required for ledger transfers
`treasury-3006` 400 Transfer step is missing account asset IDs The transfer step does not have the required from/to account asset references
`treasury-3100` 400 Account '{id}' is not a ledger account Deposits can only be made to ledger accounts
`treasury-3101` 400 Account '{id}' is not configured for deposits. No supported provider found The destination account does not have a supported deposit provider configured
`treasury-3102` 400 Ledger '{id}' is missing Circle Mint metadata The ledger account does not have the required Circle Mint configuration
`treasury-3103` 400 Circle compliance not yet accepted for ledger. Cannot create deposit Circle compliance must be accepted before deposits can be created
`treasury-3104` 400 Source account '{id}' does not match the configured source bank for this ledger The provided source account does not match the bank account configured for this ledger
`treasury-3105` 400 Source bank account '{id}' not found or is not a fiat bank account The source bank account could not be found or is not the correct account type
`treasury-3106` 400 Ledger account '{id}' does not have a '{currency}' asset The destination ledger account does not hold the requested currency
`treasury-3107` 400 Invalid currency combination for Circle deposit: {fromCurrency} → {toCurrency} The specified from_currency and to_currency combination is not supported for Circle deposits
`treasury-3108` 400 Deposit '{id}' is already finalized. Wire instructions are no longer available The deposit has already been finalized and instructions cannot be retrieved
`treasury-3109` 400 Deposit '{id}' has no transfer step The deposit does not have the expected transfer step
`treasury-3110` 400 Deposit '{id}' transfer step has no source account The deposit transfer step is missing its source account reference
`treasury-3111` 400 Deposit '{id}' transfer step has no destination account The deposit transfer step is missing its destination account reference
`treasury-3112` 400 Source account '{id}' is missing required bank details The source account does not have all required bank details (bank name, code type, identifier code, or account number)
`treasury-3113` 400 VAN account '{id}' missing virtual_account_number metadata The VAN account does not have the required virtual account number metadata
`treasury-3114` 400 VAN account '{id}' is missing required field: {field} The VAN account is missing a required field for wire instructions (e.g., bank name, account number, SWIFT code, beneficiary name)
`treasury-3115` 400 Simulated deposits are not available in production Deposit simulation is only available in sandbox environments
## Vault
Error Code HTTP Status Error Message Description
`vault-0001` 500 Failed to store sensitive data in vault The vault provider failed to store the token. This may be due to a temporary outage or configuration issue.
`vault-0002` 500 Vault provider did not return a token ID The vault provider accepted the data but did not return a token ID. This indicates an unexpected API response.
`vault-0003` 400 Unknown vault field The specified field name is not configured for vault storage. Check the VaultFieldConfig for supported fields.
`vault-0004` 400 Invalid field type for operation The operation does not match the field type. For example, trying to store text in a file-only field.
`vault-0010` 404 Vault token not found The specified token does not exist in the vault. It may have been deleted or never created.
`vault-0011` 500 Failed to retrieve token from vault The vault provider failed to retrieve the token. This may be due to a temporary outage or authentication issue.
`vault-0012` 500 Failed to reveal token value The vault provider failed to reveal the token value. The API key may not have sufficient permissions.
`vault-0020` 500 Failed to delete token from vault The vault provider failed to delete the token. This may be due to a temporary outage or authentication issue.
`vault-0030` 502 Vault proxy request failed The vault proxy failed to forward the request to the destination. Check the destination URL and authentication.
`vault-0031` 502 Vault proxy destination returned an error The vault proxy successfully forwarded the request, but the destination returned an error response.
`vault-0040` 503 Vault provider is not configured The vault provider API key is not configured. Contact support to enable vault functionality.
`vault-0041` 400 Liquidation provider not found The specified liquidation provider is not configured. Check the available providers.
`vault-0050` 502 Failed to forward vaulted data to provider The vaulted data could not be forwarded to the liquidation provider. This may be due to a provider outage or misconfiguration.
`vault-0051` 422 Provider rejected the forwarded data The liquidation provider rejected the forwarded data. Check the data format and provider requirements.
## Circle
Error Code HTTP Status Error Message Description
`circle-1000` 404 Circle API key not configured for organization The organization does not have a Circle Mint API key configured in the vault
`circle-2000` 401 Circle API key authentication failed The configured Circle Mint API key failed authentication with Circle API
`circle-4290` 429 Cannot complete request because rate limited by provider Circle Mint The Circle Mint API returned a 429 rate limit response
`circle-5000` 502 Circle Mint service error An error occurred while communicating with the Circle Mint API
`circle-5001` 503 Circle Mint service temporarily unavailable The Circle Mint API is temporarily unavailable
## Idempotency
Error Code HTTP Status Error Message Description
`idempotency-0001` 409 A request with this idempotency key is currently being processed. Please wait and retry. Another request with the same idempotency key is still in progress
`idempotency-0002` 400 Keys for idempotent requests can only be used with the same parameters they were first used with. The idempotency key was previously used with a different request body. Use a different key for different requests.
--- ## Document: Deposits and Withdrawals On-ramping and off-ramping operations URL: /overviews/deposits-and-withdrawals # Deposits and Withdrawals Deposits and Withdrawals involve funds exchange with a liquidity provider to on-ramp funds into your organization’s wallets or off-ramp funds back into external bank accounts. - **On-ramping:** Exchange fiat for stablecoin(s) via a stablecoin liquidity provider. Fiat funds leave your organization’s, or your customers’, fiat bank account(s) and stablecoins are deposited to your wallets. - **Off-ramping:** Exchanges stablecoin(s) for fiat via a liquidity provider. Stablecoins leave your organization’s, or your customers’, wallets and fiat is deposited to fiat bank account(s). --- ## Document: Currencies Supported fiat and crypto currencies URL: /overviews/currencies # Currencies import { Badge } from "zudoku/ui/Badge"; import { Callout } from "zudoku/ui/Callout"; ## Currencies The Currencies resource lists all fiat and digital assets supported by the platform. ### Overview You can retrieve a comprehensive list of supported currencies, including details about their decimals and associated blockchain networks (for crypto assets). Always pay attention to the `decimals` field when handling amounts to ensure accurate calculations. ### Currency Types - Fiat Traditional currencies like USD. - Stablecoins Digital assets pegged to fiat currencies (e.g., USDC, USDT). ### Data Model Each currency object includes: - `key`: The currency symbol (e.g., `USD`, `USDC`). - `name`: Display name (e.g., `US Dollar`, `Circle USD`). - `decimals`: Precision of the currency. - `network`: The blockchain network (null for fiat). See the [API Reference](/api#tag/Currencies) for the full list. --- ## Document: Counterparties Manage external individuals and businesses URL: /overviews/counterparties # Counterparties A counterparty represents an originator (ultimate sender) or beneficiary (ultimate receiver) of a payment. Counterparties can be individuals or businesses. Counterparties are associated to Accounts and belong to a Workspace. Registering counterparties in advance of submitting payments enables OFAC (sanctions) screening and helps meet regulatory requirements. To comply with Travel Rule obligations, counterparty information will be recorded for stablecoin payouts and be included in payment instructions sent to fiat off-ramps. \*Note: Tesser does not conduct KYC or KYB verification on counterparties. Organizations must have completed KYC/KYB verification of originator counterparties prior to registering them with the Tesser platform. To meet regulatory obligations and maintain consistency of data requirements, Tesser requires the following fields to be supplied about counterparties for registration: **Required Fields** - Legal name (first name and last name) - Physical address (legal street address, no P.O. Boxes or virtual addresses) **Optional Fields** - Date of birth - National identification number (Passport, ID card number, Tax Identification number, Social Security Number) **Required Fields** - Legal entity name - Physical address (legal street address, no P.O. Boxes or virtual addresses) - Legal entity identifier. Legal entity identifier may be a registration number or tax ID. \*Required only for counterparties who will be originators of fiat payouts. **Optional Fields** - Doing business as (DBA) or Trade name - Legal entity identifier (for beneficiaries) > If you did not supply required data during registration that is required in order to send a payment, you will receive an error indicating the missing data. You can update the counterparty record and then retry the payment. --- ## Document: Compliance and Risk Management Comprehensive compliance management to meet regulatory requirements URL: /overviews/compliance-and-risk # Compliance and Risk Management Tesser provides comprehensive compliance management to meet regulatory requirements for financial institutions. ## Pre-transaction screening **All wallets in the payout flow are screened pre-transaction, including risk categorization and scoring:** - For stablecoin payouts, the beneficiary's wallet is automatically screened. - For fiat payouts, risk assessment is performed on any intermediary wallets. - If your customers settle with you in stablecoins to fund payouts, wallets that customers send from can screened as well. **Wallets are screened on 152 factors across 4 categories:** - **Ownership.** The wallet is directly associated with or controlled by entities engaged in risky activities. - **Counterparty.** The wallet has directly transaction with entities or addresses flagged for risky behavior. - **Behavioral.** The wallet exhibits transaction patterns or behaviors commonly associated with illicit activity or obfuscation techniques. - **Indirect.** The wallet has transacted with another address that is connected to risky activity. The activity of wallets up to 20 degrees removed is assessed as part of indirect exposure calculations. See the full list of [risk factors for a wallet](#wallet-risk-categories) below. **Transaction patterns for the originator and beneficiary are assessed:** This includes total volumes sent and received, frequency and velocity of activity, suspicious amounts, etc., as well as the specific interaction pattern between the originator and beneficiary. **Risk Scores and Outcomes:** Each payment is assessed for multiple risk factors, each scored from Low to Severe. The most severe detected risk factor, along with your compliance policy, determines whether the payment is approved, approved with a flag, requires review, or rejected. - **Low or Medium Risk**: Automatic approval - **High Risk**: Requires manual review by your organization - **Severe Risk**: Automatically rejected **Risk Profiles** Tesser offers three pre-configured risk profiles to match your organization's risk appetite: 1. **Conservative**: Lower risk thresholds, more transactions require manual review 2. **Balanced**: Moderate risk tolerance with selective manual review 3. **Permissive**: Higher risk tolerance, fewer manual reviews required Each profile defines how the platform responds to different risk categories. Need a custom risk profile? Contact us to configure specific thresholds and actions tailored to your requirements. **[Optional] Counterparties can be sanctions screened.** In addition to any screening an organization conducts, Tesser can perform OFAC, PEP, and adverse media screening of beneficiaries and their fiat accounts prior to payment initiation. Contact us if you are interested in having Tesser perform sanctions screening. ## Manual Review Process Payments requiring manual review can be processed through the compliance review endpoint (`/payments/{paymentId}/review`): ```bash curl -X POST https://api.tesser.xyz/v1/payments/{paymentId}/review \ -H "Authorization: Bearer your-access-token" \ -H "Content-Type: application/json" \ -d '{ "is_approved": true }' ``` The response includes timestamp, and final decision. Payments can also be reviewed and processed in the Tesser dashboard. ## On-going Monitoring Even after a transaction is complete, beneficiary wallets are monitored to track any changes in risk factors about the wallet. ## Travel Rule Tesser handles travel rule requirements automatically as you use the platform: - No special actions are required to be compliant — the platform ensures required originator and beneficiary data is attached to payments where applicable. - During counterparty and account creation, we collect the information needed to support compliant payments to/from that account (jurisdiction- and method-specific). - In rare cases, additional KYB details may be requested at payment intent or execution time to satisfy provider- or corridor-specific rules. Account information is collected and transmitted as part of Travel Rule compliance for stablecoin payouts or fiat payouts: | **Information transmitted** | **Required for Originator** | **Required for Beneficiary** | **Notes** | | --- | --- | --- | --- | | **Legal Name** | Individual's legal first and last name, or Business's legal entity name | Individual's legal first and last name, or Business's legal entity name | | | **Physical Address** | Legal address of the individual or business. (Street address, City, State/District/Region, Postal Code, Country) | Legal address of the individual or business. (Street address, City, State/District/Region, Postal Code, Country) | No P.O. Boxes or virtual addresses. | | **Legal Entity Identifier** | Required for business originators of fiat payouts. Not required for individuals. | Not required for beneficiaries | Legal entity Identifier may be a registration number or tax ID. | | **Account Identifier*** | Account Number or IBAN. | Account Number, IBAN, or Wallet Address. | For cash-funded remittance transaction, will be a unique identifier for the originator or transaction | | **Financial Institution (FI) info** | Name and Identifier of the FI | Name and Identifier of the FI (For fiat payouts only) | | > *For Travel Rule purposes, information about the originator's fiat account is typically transmitted to beneficiary financial institutions, unless wallets are provisioned for *and* self-custodied by the originator. ## Wallet Risk Categories | **Type of risk** | **Category** | **Description** | | --- | --- | --- | | Behavioral | Binary Tree | Part of a Binary Tree transaction | | Behavioral | CoinJoin Transactions | Involved in a CoinJoin-like transaction | | Behavioral | Extortion with Common Destination | Part of a Extortion with Common Destination transaction | | Behavioral | Graphton | Part of a unique "trail" of transactions | | Behavioral | Mass Registration | Involved in Mass Registration | | Behavioral | Peeling Chain | Involved in a Peeling Chain | | Behavioral | Peeling Chain with Common Destination | Part of a Peeling Chain with Common Destination transaction | | Behavioral | Web Flow | Part of a Web Flow transaction | | Counterparty | Adult Content | Address previously transacted with Adult Content | | Counterparty | Banned or Controlled Substances | Address previously transacted with Banned or Controlled Substances | | Counterparty | Blocklisted | Address previously transacted with Blocklisted | | Counterparty | Carding / PII Shop | Address previously transacted with Carding / PII Shop | | Counterparty | Cash-to-Crypto | Address previously transacted with Cash-to-Crypto | | Counterparty | Child Sexual Abuse Material (CSAM) | Address previously transacted with Child Sexual Abuse Material (CSAM) | | Counterparty | Child Sexual Abuse Material (CSAM) Consumer | Address previously transacted with Child Sexual Abuse Material (CSAM) Consumer | | Counterparty | Child Sexual Abuse Material (CSAM) Scam | Address previously transacted with Child Sexual Abuse Material (CSAM) Scam | | Counterparty | Child Sexual Abuse Material (CSAM) Vendor | Address previously transacted with Child Sexual Abuse Material (CSAM) Vendor | | Counterparty | Community Complaint | Address previously transacted with Community Complaint | | Counterparty | Counterfeit Goods | Address previously transacted with Counterfeit Goods | | Counterparty | Cybercrime Services | Address previously transacted with Cybercrime Services | | Counterparty | Darknet Market | Address previously transacted with Darknet Market | | Counterparty | Decentralized Exchange | Address previously transacted with Decentralized Exchange | | Counterparty | Decentralized File Sharing Service | Address previously transacted with Decentralized File Sharing Service | | Counterparty | Decentralized Gambling | Address previously transacted with Decentralized Gambling Service | | Counterparty | Decentralized Investment Fraud | Address previously transacted with Decentralized Investment Fraud | | Counterparty | Decentralized Investment Scheme | Address previously transacted with Decentralized Investment Scheme | | Counterparty | Decentralized Marketplace | Address previously transacted with Decentralized Marketplace | | Counterparty | Escort Service / Prostitution | Address previously transacted with Escort Service / Prostitution | | Counterparty | Extortion / Blackmail | Address previously transacted with Extortion / Blackmail | | Counterparty | Gambling Service | Address previously transacted with Gambling Service | | Counterparty | Hacked or Exploited Funds | Address previously transacted with Hacked or Exploited Funds | | Counterparty | High-Risk Exchange | Address previously transacted with High-Risk Exchange | | Counterparty | Human Trafficking | Address previously transacted with Human Trafficking | | Counterparty | Illicit Goods and Services | Address previously transacted with Illicit Goods and Services | | Counterparty | Imposter Site or Service | Address previously transacted with Imposter Site or Service | | Counterparty | Investment Fraud | Address previously transacted with Investment Fraud | | Counterparty | Investment Scheme | Address previously transacted with Investment Scheme | | Counterparty | Known Hacker Group | Address previously transacted with Known Hacker Group | | Counterparty | Lending Service | Address previously transacted with Lending Service | | Counterparty | Malware | Address previously transacted with Malware | | Counterparty | Mining | Address previously transacted with Mining | | Counterparty | Mixer | Address previously transacted with Mixer | | Counterparty | Non-Custodial Exchange | Address previously transacted with Non-Custodial Exchange | | Counterparty | Online Username Reselling | Address previously transacted with Online Username Reselling | | Counterparty | P2P Crypto Marketplace | Address previously transacted with P2P Crypto Marketplace | | Counterparty | Piracy | Address previously transacted with Piracy | | Counterparty | Politically Exposed Person | Address previously transacted with Politically Exposed Person | | Counterparty | Ponzi Scheme | Address previously transacted with Ponzi Scheme | | Counterparty | Ransomware | Address previously transacted with Ransomware | | Counterparty | Sanctions | Address previously transacted with Sanctions | | Counterparty | Scam | Address previously transacted with Scam | | Counterparty | Sexual Exploitation | Address previously transacted with Sexual Exploitation | | Counterparty | Special Measures | Address previously transacted with Special Measures | | Counterparty | Terrorist Financing | Address previously transacted with Terrorist Financing | | Counterparty | Trusted Community Complaint | Address associated with Trusted Community Complaint | | Counterparty | Violent Extremism | Address previously transacted with Violent Extremism | | Indirect | Adult Content | Address has indirect exposure to Adult Content | | Indirect | Banned or Controlled Substances | Address has indirect exposure to Banned or Controlled Substances | | Indirect | Blocklisted | Address has indirect exposure to Blocklisted | | Indirect | Carding / PII Shop | Address has indirect exposure to Carding / PII Shop | | Indirect | Cash-to-Crypto | Address has indirect exposure to Cash-to-Crypto | | Indirect | Child Sexual Abuse Material (CSAM) | Address has indirect exposure to Child Sexual Abuse Material (CSAM) | | Indirect | Child Sexual Abuse Material (CSAM) Consumer | Address has indirect exposure to Child Sexual Abuse Material (CSAM) Consumer | | Indirect | Child Sexual Abuse Material (CSAM) Scam | Address has indirect exposure to Child Sexual Abuse Material (CSAM) Scam | | Indirect | Child Sexual Abuse Material (CSAM) Vendor | Address has indirect exposure to Child Sexual Abuse Material (CSAM) Vendor | | Indirect | Community Complaint | Address has indirect exposure to Community Complaint | | Indirect | Counterfeit Goods | Address has indirect exposure to Counterfeit Goods | | Indirect | Cybercrime Services | Address has indirect exposure to Cybercrime Services | | Indirect | Darknet Market | Address has indirect exposure to Darknet Market | | Indirect | Decentralized Exchange | Address has indirect exposure to Decentralized Exchange | | Indirect | Decentralized File Sharing Service | Address has indirect exposure to Decentralized File Sharing Service | | Indirect | Decentralized Gambling | Address has indirect exposure to Decentralized Gambling | | Indirect | Decentralized Investment Fraud | Address has indirect exposure to Decentralized Investment Fraud | | Indirect | Decentralized Investment Scheme | Address has indirect exposure to Decentralized Investment Scheme | | Indirect | Decentralized Marketplace | Address has indirect exposure to Decentralized Marketplace | | Indirect | Escort Service / Prostitution | Address has indirect exposure to Escort Service / Prostitution | | Indirect | Extortion / Blackmail | Address has indirect exposure to Extortion / Blackmail | | Indirect | Gambling Service | Address has indirect exposure to Gambling Service | | Indirect | Hacked or Exploited Funds | Address has indirect exposure to Hacked or Exploited Funds | | Indirect | High-Risk Exchange | Address has indirect exposure to High-Risk Exchange | | Indirect | Human Trafficking | Address has indirect exposure to Human Trafficking | | Indirect | Illicit Goods and Services | Address has indirect exposure to Illicit Goods and Services | | Indirect | Imposter Site or Service | Address has indirect exposure to Imposter Site or Service | | Indirect | Investment Fraud | Address has indirect exposure to Investment Fraud | | Indirect | Investment Scheme | Address has indirect exposure to Investment Scheme | | Indirect | Known Hacker Group | Address has indirect exposure to Known Hacker Group | | Indirect | Lending Service | Address has indirect exposure to Lending Service | | Indirect | Malware | Address has indirect exposure to Malware | | Indirect | Mining | Address has indirect exposure to Mining | | Indirect | Mixer | Address has indirect exposure to Mixer | | Indirect | Non-Custodial Exchange | Address has indirect exposure to Non-Custodial Exchange | | Indirect | Online Username Reselling | Address has indirect exposure to Online Username Reselling | | Indirect | P2P Crypto Marketplace | Address has indirect exposure to P2P Crypto Marketplace | | Indirect | Piracy | Address has indirect exposure to Piracy | | Indirect | Politically Exposed Person | Address has indirect exposure to Politically Exposed Person | | Indirect | Ponzi Scheme | Address has indirect exposure to Ponzi Scheme | | Indirect | Ransomware | Address has indirect exposure to Ransomware | | Indirect | Sanctions | Address has indirect exposure to Sanctions | | Indirect | Scam | Address has indirect exposure to Scam | | Indirect | Sexual Exploitation | Address has indirect exposure to Sexual Exploitation | | Indirect | Special Measures | Address has indirect exposure to Special Measures | | Indirect | Terrorist Financing | Address has indirect exposure to Terrorist Financing | | Indirect | Trusted Community Complaint | Address associated with Trusted Community Complaint | | Indirect | Violent Extremism | Address has indirect exposure to Violent Extremism | | Ownership | Adult Content | Address associated with Adult Content | | Ownership | Banned or Controlled Substances | Address associated with Banned or Controlled Substances | | Ownership | Blocklisted | Address associated with Blocklisted | | Ownership | Carding / PII Shop | Address associated with Carding / PII Shop | | Ownership | Cash-to-Crypto | Address associated with Cash-to-Crypto | | Ownership | Child Sexual Abuse Material (CSAM) | Address associated with Child Sexual Abuse Material (CSAM) | | Ownership | Child Sexual Abuse Material (CSAM) Consumer | Address associated with Child Sexual Abuse Material (CSAM) Consumer | | Ownership | Child Sexual Abuse Material (CSAM) Scam | Address associated with Child Sexual Abuse Material (CSAM) Scam | | Ownership | Child Sexual Abuse Material (CSAM) Vendor | Address associated with Child Sexual Abuse Material (CSAM) Vendor | | Ownership | Community Complaint | Address associated with Community Complaint | | Ownership | Counterfeit Goods | Address associated with Counterfeit Goods | | Ownership | Cybercrime Services | Address associated with Cybercrime Services | | Ownership | Darknet Market | Address associated with Darknet Market | | Ownership | Decentralized Exchange | Address associated with Decentralized Exchange | | Ownership | Decentralized File Sharing Service | Address associated with Decentralized File Sharing Service | | Ownership | Decentralized Gambling | Address associated with Decentralized Gambling Service | | Ownership | Decentralized Investment Fraud | Address associated with Decentralized Investment Fraud | | Ownership | Decentralized Investment Scheme | Address associated with Decentralized Investment Scheme | | Ownership | Decentralized Marketplace | Address associated with Decentralized Marketplace | | Ownership | Escort Service / Prostitution | Address associated with Escort Service / Prostitution | | Ownership | Extortion / Blackmail | Address associated with Extortion / Blackmail | | Ownership | Gambling Service | Address associated with Gambling Service | | Ownership | Hacked or Exploited Funds | Address associated with Hacked or Exploited Funds | | Ownership | High-Risk Exchange | Address associated with High-Risk Exchange | | Ownership | Human Trafficking | Address associated with Human Trafficking | | Ownership | Illicit Goods and Services | Address associated with Illicit Goods and Services | | Ownership | Imposter Site or Service | Address associated with Imposter Site or Service | | Ownership | Investment Fraud | Address associated with Investment Fraud | | Ownership | Investment Scheme | Address associated with Investment Scheme | | Ownership | Known Hacker Group | Address associated with Known Hacker Group | | Ownership | Lending Service | Address associated with Lending Service | | Ownership | Malware | Address associated with Malware | | Ownership | Mining | Address associated with Mining | | Ownership | Mixer | Address associated with Mixer | | Ownership | Non-Custodial Exchange | Address associated with Non-Custodial Exchange | | Ownership | Online Username Reselling | Address associated with Online Username Reselling | | Ownership | P2P Crypto Marketplace | Address associated with P2P Crypto Marketplace | | Ownership | Piracy | Address associated with Piracy | | Ownership | Politically Exposed Person | Address associated with Politically Exposed Person | | Ownership | Ponzi Scheme | Address associated with Ponzi Scheme | | Ownership | Ransomware | Address associated with Ransomware | | Ownership | Sanctions | Address associated with Sanctions | | Ownership | Scam | Address associated with Scam | | Ownership | Sexual Exploitation | Address associated with Sexual Exploitation | | Ownership | Special Measures | Address associated with Special Measures | | Ownership | Terrorist Financing | Address associated with Terrorist Financing | | Ownership | Trusted Community Complaint | Address associated with Trusted Community Complaint | | Ownership | Violent Extremism | Address associated with Violent Extremism | --- ## Document: Authentication How to authenticate with the Tesser API URL: /overviews/authentication # Authentication All requests to the Tesser API must include a valid access token. Tokens are generated using your API credentials, which are provisioned in the [Tesser Dashboard](https://app.tesser.xyz). ## Credentials Each workspace has a **Client ID** and **Client Secret** pair. You can find these in the Tesser Dashboard under **Settings > API Keys**. Keep your client secret secure and never expose it in client-side code or public repositories. ## Generate an API Token To obtain an access token, send a `POST` request to the Tesser token endpoint with your credentials: ```bash curl --request POST \ --url https://auth.tesser.xyz/oauth/token \ --header 'Content-Type: application/json' \ --data '{ "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "audience": "https://api.tesser.xyz", "grant_type": "client_credentials" }' ``` ### Token Response A successful request returns a JSON response containing your access token: ```json { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6Ikp...", "token_type": "Bearer", "expires_in": 86400 } ``` | Field | Description | | --- | --- | | `access_token` | The token to include in API requests | | `token_type` | Always `Bearer` | | `expires_in` | Token lifetime in seconds (default: 86400 = 24 hours) | ## Using the Token Include the access token in the `Authorization` header of every API request: ```bash curl --request GET \ --url https://api.tesser.xyz/counterparties \ --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6Ikp...' ``` ## Token Expiration Tokens expire after the duration specified in `expires_in` (default 24 hours). When a token expires, the API returns a `401 Unauthorized` response. To maintain uninterrupted access: - Request a new token before the current one expires. - Do not cache tokens indefinitely. - There are no refresh tokens. Simply request a new token using the same credentials. --- ## Document: Accounts Manage fiat bank accounts and crypto wallets URL: /overviews/accounts # Accounts An account represents a store of value for fiat currencies and/or stablecoins. - **Bank account**: Account that exists at a regulated depository financial institution (i.e. a bank). Stores fiat. - **Wallet**: An on-chain wallet. Stores stablecoins. - **Ledger**: An account at a liquidity provider/custodian. May store fiat and/or stablecoins. Accounts may be managed by Tesser or unmanaged. "Unmanaged" accounts are accounts that were not provisioned by Tesser, and instead were provisioned by a third party. "Managed" accounts are accounts that are provisioned by Tesser. Accounts will always belong to the workspace they are created in. They can optionally also belong to one of a counterparty or tenant.
*Belongs to:* **Type: Bank account** **Type: Wallet** **Type: Ledger**
**Workspace** n/a

An omnibus wallet an organization uses to manage its treasury operations in an aggregated manner.

(Managed)

An omnibus wallet an organization uses to manage its treasury operations in an aggregated manner.

(Managed)

**Tenant** n/a

A wallet designated for funds belonging to a tenant.

(Managed)

A wallet designated for funds belonging to a tenant.

(Managed)

**Counterparty**

A bank account that belongs to an originator or a beneficiary.

(Unmanaged)

For fiat payouts, bank account info as transmitted as part of Travel Rule compliance.

  • Bank accounts of originators are the ultimate source of funds.
  • Bank accounts of beneficiaries are the ultimate destination of funds.

A wallet designated for an originator or beneficiary provisioned by Tesser. (Managed)

A wallet provisioned for the originator or beneficiary by a non-Tesser provider. (Unmanaged)

A wallet designated for an originator or beneficiary.

(Managed)

--- ## Document: Create an Account Pre-register accounts for payouts on the Tesser platform URL: /how-tos/create-an-account # Create an Account Accounts must be pre-registered to transact on the Tesser platform. Registering accounts in advance of transacting enables wallet risk assessment and helps meet regulatory requirements. **Account creation** To create an account, submit a request to create a bank, wallet, or ledger account and populate the appropriate fields. Accounts will always belong to the workspace they are created in and can also optionally belong to a tenant or counterparty. See the [Accounts overview](/overviews/accounts) for more details. Bank account creation request ```json { "counterparty_id": "2a7e1c9f-4b3d-4a82-b6e0-8f5c2d1a9b3e", "name": "Operating Account - EU", "bank_name": "Chase Bank", "bank_code_type": "SWIFT", "bank_identifier_code": "CHASUS33", "bank_account_number": "123456789" } ``` The response will provide a unique identifier for the account that can be used when requesting payments or transfers: ```json { "data": { "id": "8f3b1e7c-9a2d-4f58-b6c0-4e7d2a9f1b3c", "workspace_id": "b53f6690-3242-4942-9907-885779632832", "tenant_id": null, "counterparty_id": "2a7e1c9f-4b3d-4a82-b6e0-8f5c2d1a9b3e", "type": "fiat_bank", "name": "Operating Account - EU", "bank_name": "Chase Bank", "bank_code_type": "SWIFT", "bank_identifier_code": "CHASUS33", "crypto_wallet_address": null, "created_at": "2024-03-02T14:30:00.000Z", "updated_at": "2024-03-02T14:30:00.000Z" } } ``` Wallet account creation request ```json { "workspace_id": "b53f6690-3242-4942-9907-885779632832", "name": "Treasury Wallet (Omnibus)", "type": "stablecoin_ethereum", "signature": "eyJwdWJsaWNLZXkiOiJwdWJfZXhhbXBsZSIsInNpZ25hdHVyZSI6InNpZ19leGFtcGxlIiwic2NoZW1lIjoiRUQyNTUxOSJ9" } ``` The response will provide a unique identifier for the account that can be used when requesting payments or transfers: ```json { "data": { "id": "7a3d8f2e-6b4c-4a91-b8e5-2f9c1d7e3a0b", "workspace_id": "b53f6690-3242-4942-9907-885779632832", "tenant_id": null, "counterparty_id": null, "type": "stablecoin_ethereum", "name": "Treasury Wallet (Omnibus)", "bank_name": null, "bank_code_type": null, "bank_identifier_code": null, "crypto_wallet_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f8fE0B", "created_at": "2024-03-01T10:00:00.000Z", "updated_at": "2024-03-01T10:00:00.000Z" } } ``` Ledger account creation request ```json { "workspace_id": "b53f6690-3242-4942-9907-885779632832", "name": "Treasury Ledger", "provider": "CIRCLE_MINT" } ``` The response will provide a unique identifier for the account that can be used when requesting payments or transfers: ```json { "data": { "id": "5d2e8f1a-7c3b-4a69-9e0f-1b4c6d8a2e5f", "workspace_id": "b53f6690-3242-4942-9907-885779632832", "tenant_id": null, "counterparty_id": null, "name": "Treasury Ledger", "type": "ledger", "provider": "CIRCLE_MINT" } } ``` **Associating wallets and ledgers with a tenant or counterparty** A wallet or ledger can optionally belong to either a counterparty or tenant in addition to the workspace. - Do not specify a tenant or counterparty if you want the wallet or ledger to be used in a fully omnibus manner, where funds are commingled across all of your customers. Upon onboarding, your organization will be provisioned with a wallet or ledger that only belongs to your workspace. You may create additional wallets or ledgers that only belong to the workspace as needed. - Create a wallet or ledger that belongs to a tenant to manage proprietary funds belonging to that tenant, or to commingle funds belonging to that tenant's customers (e.g. originators and/or beneficiaries). - Create a wallet or ledger that belongs to a counterparty to fully segregate funds only for that counterparty. For more information on the relationship between accounts and counterparties, see the [Accounts overview](/overviews/accounts). --- ## Document: Create a Tenant How to create and manage tenants for platform customers URL: /how-tos/create-a-tenant # Create a Tenant A tenant represents an organization’s customer when that customer is itself a platform with its own users who need to be represented in Tesser’s systems. When an organization’s customers are tenants, originators and/or beneficiaries are customers of the tenant and thus end-customers to the organization. To create a tenant, submit a request to the [tenant creation API](/api/tenants#create-a-new-tenant). ```json { "business_legal_name": "Acme Corporation", "business_dba": "Acme Co", "business_address_country": "US", "business_street_address1": "123 Corp Blvd", "business_street_address2": "Suite 100", "business_city": "New York", "business_state": "NY", "business_legal_entity_identifier": "123456789", "webhook_url": "https://acme.com/webhooks/tesser" } ``` Example response: ```json { "data": { "id": "29c580bd-43d2-4dbf-bc9e-a3b1ccb8e7ee", "workspace_id": "b53f6690-3242-4942-9907-885779632832", "business_legal_name": "Acme Corporation", "business_dba": "Acme Co", "business_address_country": "US", "business_street_address1": "123 Corp Blvd", "business_street_address2": "Suite 100", "business_city": "New York", "business_state": "NY", "business_legal_entity_identifier": "9876543210", "country": "US", "webhook_url": "https://acme.com/webhooks/tesser", "created_at": "2024-01-15T10:30:00.000Z", "updated_at": "2024-01-15T10:30:00.000Z" } } ``` **Creating resources for a tenant** To initiate counterparty, account, payment, or transfer creation on behalf of the tenant, you will supply supply the `id` of the tenant returned in the creation response in API calls using your own API keys. --- ## Document: Create a Deposit Deposit funds via a liquidity provider to on-ramp fiat to stablecoins URL: /how-tos/create-a-deposit # Create a Deposit In order to send payouts, you will need to deposit funds to a liquidity provider to exchange fiat to stablecoins (i.e. on-ramp funds). Tesser treats deposits via a liquidity provider as a special class of payments, so the structure of the deposits API experience will be similar to sending a payment. ## Register the source fiat bank account Liquidity providers require that funds are on-ramped from an account owned by your organization. Ensure you have registered the source bank account prior to beginning the deposit process. For more information on account creation, see [Create an account](/how-tos/create-an-account). ## Deposit workflow Like a payment, a deposit will execute over multiple steps. - A `transfer` step indicates funds are moving from one account to another. Accounts can be a bank account, ledger, or wallet. The `from_currency` and `to_currency` may be the same in a transfer step or different. - A `swap` step indicates currencies have been exchanged within an account. E.g. a trade was performed to sell USD and buy USDC or USDT within your ledger. Each step has a status. For more information on the statuses of a transfer step, see [Transfer steps statuses](/how-tos/send-a-stablecoin-payout/payout-workflow#transfer-steps-status). ## Deposit creation Submit a request to the [Deposit API](/api/treasury#create-deposit). - For all deposits, populate: - `from_currency`: Fiat currency you are on-ramping from - `to_currency`: Stablecoin currency you are on-ramping to - `from_amount`: Fiat amount to deposit - `from_account_id`: Identifier of the bank account fiat funds will be sent from. Previously registered (see [above](#register-the-source-fiat-bank-account)). - `to_account_id`: Identifier of the wallet or ledger account on the Tesser platform to deposit funds to. :::note When depositing funds to a ledger at a custodian, ensure the account identifier supplied is for a custodian that can support your requested `from_currency` and `to_currency`. ::: - For deposits to a wallet account: - `to_network`: Stablecoin network on-ramping to. Not applicable if `to_account_id` has a type of "ledger". Example request for deposit creation to a ledger account using Circle: ```json { "from_currency": "USD", "to_currency": "USDC", "from_amount": "1000", "from_account_id": "55042f8f-e527-56f1-b57c-eef23ca862db", "to_account_id": "44031e7e-d416-45f0-a46b-ded12b9751ca" } ``` In the API response, Tesser will create and return an `id` for the deposit request. Example response for deposit creation to a ledger account using Circle: ```json { "data": { "id": "1c8e4a6f-9b2d-4f53-a0e7-5d3c1b9f2a8e", "workspace_id": "b53f6690-3242-4942-9907-885779632832", "organization_reference_id": null, "direction": "inbound", "funding_account_id": null, "from_amount": "1000", "from_currency": "USD", "from_network": null, "from_account_id": "55042f8f-e527-56f1-b57c-eef23ca862db", "to_amount": null, "to_currency": "USDC", "to_network": null, "to_account_id": "44031e7e-d416-45f0-a46b-ded12b9751ca", "steps": [], "created_at": "2024-03-01T10:00:00.000Z", "updated_at": "2024-03-01T10:00:00.000Z", "expires_at": "2024-03-01T14:00:00.000Z" } } ``` ## Deposit updated with estimated amounts After obtaining the exchange rate from the liquidity provider, Tesser will send a webhook notifying you of the updated deposit information. Based on the populated `from_amount` and `to_amount` fields, you can calculate an exchange rate between the fiat `from_currency` and stablecoin `to_currency`. Also with this update, the steps for on-ramping will be articulated; each step will have a `status` of "created". If you want to proceed with the deposit, [obtain the account information for the liquidity provider](#obtain-instructions-from-the-liquidity-provider) from Step 1 and send funds to the provider. Example webhook schema for deposit to a ledger account using Circle: ```json { "id": "event_222", "type": "deposit.quote_created", "created_at": "2025-12-01T10:00:00.100Z", "data": { "object": { "id": "1c8e4a6f-9b2d-4f53-a0e7-5d3c1b9f2a8e", "workspace_id": "b53f6690-3242-4942-9907-885779632832", "organization_reference_id": null, "direction": "inbound", "funding_account_id": null, "from_account_id": "55042f8f-e527-56f1-b57c-eef23ca862db", "from_amount": "1000", "from_currency": "USD", "from_network": null, "to_account_id": "44031e7e-d416-45f0-a46b-ded12b9751ca", "to_amount": null, "to_currency": "USDC", "to_network": null, "steps": [ { "id": "8a4f2c1e-9b6d-4e35-b7a0-3c5d1e9f2b8a", "transfer_id": "1c8e4a6f-9b2d-4f53-a0e7-5d3c1b9f2a8e", "step_sequence": 1, "step_type": "transfer", "from_account_id": "55042f8f-e527-56f1-b57c-eef23ca862db", "to_account_id": "a81bc1f4-7e3d-4926-b04f-3d2e8a9c5f17", "from_network": null, "from_amount": "1000", "from_currency": "USD", "to_network": null, "to_amount": "1000", "to_currency": "USD", "transaction_hash": null, "fees": [], "provider_key": "circle_mint", "status": "created", "status_reasons": null, "created_at": "2024-03-01T10:00:00.000Z", "updated_at": "2024-03-01T10:00:00.000Z", "submitted_at": null, "confirmed_at": null, "finalized_at": null, "completed_at": null, "failed_at": null }, { "id": "3b7e9d2f-1c4a-4f68-a5b0-6e8c1d3f9a2b", "transfer_id": "1c8e4a6f-9b2d-4f53-a0e7-5d3c1b9f2a8e", "step_sequence": 2, "step_type": "transfer", "from_account_id": "a81bc1f4-7e3d-4926-b04f-3d2e8a9c5f17", "to_account_id": "44031e7e-d416-45f0-a46b-ded12b9751ca", "from_network": null, "from_amount": "1000", "from_currency": "USD", "to_network": null, "to_amount": "1000", "to_currency": "USDC", "transaction_hash": null, "fees": [], "provider_key": "circle_mint", "status": "created", "status_reasons": null, "created_at": "2024-03-01T10:00:00.000Z", "updated_at": "2024-03-01T10:00:00.000Z", "submitted_at": null, "confirmed_at": null, "finalized_at": null, "completed_at": null, "failed_at": null } ], "created_at": "2024-03-01T10:00:00.000Z", "updated_at": "2024-03-01T10:00:00.100Z", "expires_at": "2024-03-01T14:00:00.000Z" } } } ``` ## Obtain instructions from the liquidity provider The `to_account_id` field in the first step will always be populated with the Tesser identifier of the bank account of the liquidity provider. Submit a subsequent request to the Get deposit instructions endpoint with the `to_account_id` as the path parameter. The response will contain the bank account information you need to deposit funds to the liquidity provider, including the account number, bank identifier code (BIC/SWIFT/Routing number). Once you have the account information, you will initiate a push of funds to the liquidity provider from your bank account. This happens outside of Tesser's system. Tesser will track the receipt of the fiat funds to the liquidity provider and the exchange of fiat into stablecoins. The `status` of each step will reflect the step's progress, and any reasons for exception or failure will be identified in the `status_reasons` array. --- ## Document: Create a Counterparty Pre-register counterparties for payouts on the Tesser platform URL: /how-tos/create-a-counterparty # Create a Counterparty Counterparties must be pre-registered to transact on the Tesser platform. Registering counterparties in advance of submitting payouts enables OFAC (sanctions) screening and helps meet regulatory requirements. **Counterparty creation** To create a counterparty, submit a request to the [counterparty creation API](/api/counterparties#create-a-new-counterparty) and populate the appropriate fields for the individual or business. *Note: Individuals are natural persons; businesses are registered legal entities. Select a type of customer you want to create: Example: Individual counterparty creation request ```json { "classification": "individual", "individual_first_name": "John", "individual_last_name": "Doe", "individual_address_country": "US", "individual_date_of_birth": "1980-01-01", "individual_national_identification_number": "123456789", "individual_street_address1": "123 Main St", "individual_street_address2": "Apt 4B", "individual_city": "New York", "individual_state": "NY", "individual_postal_code": "10001" } ``` In the successful response you receive a unique id for the counterparty. ```json { "data": { "id": "c7d8e9f0-1a2b-3c4d-5e6f-789012345678", "workspace_id": "b53f6690-3242-4942-9907-885779632832", "classification": "individual", "tenant_id": null, "individual_first_name": "John", "individual_last_name": "Doe", "individual_address_country": "US", "individual_date_of_birth": "1980-01-01", "individual_national_identification_number": "123456789", "individual_street_address1": "123 Main St", "individual_street_address2": "Apt 4B", "individual_city": "New York", "individual_state": "NY", "individual_postal_code": "10001", "business_legal_name": null, "business_dba": null, "business_address_country": null, "business_street_address1": null, "business_street_address2": null, "business_city": null, "business_state": null, "business_legal_entity_identifier": null, "created_at": "2024-03-01T10:00:00.000Z", "updated_at": "2024-03-01T10:00:00.000Z" } } ``` Example: Business counterparty creation request ```json { "classification": "business", "business_legal_name": "Acme Corporation", "business_dba": "Acme Co", "business_address_country": "US", "business_street_address1": "456 Corp Blvd", "business_street_address2": "Suite 200", "business_city": "San Francisco", "business_state": "CA", "business_legal_entity_identifier": "1234567890" } ``` In the successful response you receive a unique id for the counterparty. ```json { "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "classification": "business", "tenant_id": "00000000-0000-0000-0000-000000000000", "individual_first_name": null, "individual_last_name": null, "individual_street_address1": null, "individual_street_address2": null, "individual_city": null, "individual_state": null, "individual_postal_code": null, "individual_address_country": null, "individual_date_of_birth": null, "individual_national_identification_number": null, "business_legal_name": "Acme Corporation", "business_dba": "Loony Tunes", "business_address_country": "US", "business_street_address1": "456 Corp Blvd", "business_street_address2": "Suite 200", "business_city": "San Francisco", "business_state": "CA", "business_legal_entity_identifier": "1234567890", "created_at": "2024-01-15T10:30:00.000Z", "updated_at": "2024-01-15T10:30:00.000Z" } } ``` --- ## Document: Resources AI-friendly resources and authentication for the Tesser API URL: /agentic/resources # Resources The Tesser API is designed for both human developers and AI agents. All endpoints are accessible via standard REST calls and via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io), allowing AI coding assistants to discover and invoke Tesser operations as tools. ## AI-Friendly Resources | Resource | URL | | --- | --- | | **llms.txt** | [https://docs.tesser.xyz/llms.txt](https://docs.tesser.xyz/llms.txt) | | **Full docs for LLMs** | [https://docs.tesser.xyz/llms-full.txt](https://docs.tesser.xyz/llms-full.txt) | | **OpenAPI Schema** | [https://docs.tesser.xyz/api/v1/schema.json](https://docs.tesser.xyz/api/v1/schema.json) | | **MCP Endpoint** | `https://sandbox.tesserx.co/v1/mcp` | ## Authentication Both REST and MCP use the same OAuth 2.0 client credentials flow. You need a `TESSER_API_KEY` and `TESSER_API_SECRET` (issued as Auth0 client credentials). ### Obtain a Token ```bash curl --request POST \ --url https://dev-awqy75wdabpsnsvu.us.auth0.com/oauth/token \ --header 'content-type: application/json' \ --data '{ "client_id": "'$TESSER_API_KEY'", "client_secret": "'$TESSER_API_SECRET'", "audience": "https://sandbox.tesserx.co", "grant_type": "client_credentials" }' ``` The response contains an `access_token` to use as a Bearer token in all subsequent requests. ### Environment Setup Create a `.env` file in your project root: ```bash TESSER_API_KEY=your-api-key TESSER_API_SECRET=your-api-secret ``` --- ## Document: MCP Integration Connect AI coding assistants to Tesser via Model Context Protocol URL: /agentic/mcp-integration # MCP Integration The Tesser MCP server exposes every public API endpoint as a tool that AI agents can discover and invoke. It uses **Streamable HTTP** transport at: ``` https://sandbox.tesserx.co/v1/mcp ``` Authentication uses the same OAuth 2.0 Bearer token as the REST API. See [Resources](/agentic/resources) for how to obtain a token. ## Claude Code **1. Set your token** in the shell before launching Claude Code: ```bash export MCP_TOKEN=$(bash scripts/mcp-token.sh) ``` **2. Add the config** to `.claude/settings.local.json` in your project root: ```jsonc { "mcpServers": { "tesser-payments": { "type": "url", "url": "https://sandbox.tesserx.co/v1/mcp", "headers": { "Authorization": "Bearer ${MCP_TOKEN}" } } } } ``` **3. Activate** by running `/mcp` in your Claude Code session to reload MCP servers. Tesser tools will appear immediately. ## Cursor **1. Set your token** in the shell before launching Cursor: ```bash export MCP_TOKEN=$(bash scripts/mcp-token.sh) ``` **2. Add the config** to `.cursor/mcp.json` in your project root: ```jsonc { "mcpServers": { "tesser-payments": { "type": "url", "url": "https://sandbox.tesserx.co/v1/mcp", "headers": { "Authorization": "Bearer ${MCP_TOKEN}" } } } } ``` **3. Activate** by restarting Cursor. Tesser tools will appear in the MCP tools panel. ## Windsurf **1. Set your token** in the shell before launching Windsurf: ```bash export MCP_TOKEN=$(bash scripts/mcp-token.sh) ``` **2. Add the config** to `.windsurf/mcp.json` in your project root: ```jsonc { "mcpServers": { "tesser-payments": { "type": "url", "url": "https://sandbox.tesserx.co/v1/mcp", "headers": { "Authorization": "Bearer ${MCP_TOKEN}" } } } } ``` **3. Activate** by restarting Windsurf. ## Token Refresh Tokens expire after approximately 24 hours. When they expire, MCP tool calls will fail with a 401 error. To refresh: 1. Run `export MCP_TOKEN=$(bash scripts/mcp-token.sh)` in your shell 2. Restart your IDE (or run `/mcp` in Claude Code) For details on the token script and manual token management, see [Manual MCP Setup](/agentic/manual-mcp). --- ## Document: Manual MCP Setup Connect to the Tesser MCP server using a manually fetched token URL: /agentic/manual-mcp # Manual MCP Setup Use this approach when `mcp-remote` is not available — for example in headless environments, CI pipelines, or custom agent frameworks. ## Fetch a Token ```bash export MCP_TOKEN=$(curl -s --request POST \ --url https://dev-awqy75wdabpsnsvu.us.auth0.com/oauth/token \ --header 'content-type: application/json' \ --data '{ "client_id": "'$TESSER_API_KEY'", "client_secret": "'$TESSER_API_SECRET'", "audience": "https://sandbox.tesserx.co", "grant_type": "client_credentials" }' | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])") ``` This requires `TESSER_API_KEY` and `TESSER_API_SECRET` set in your environment or `.env` file. ## IDE Configuration Configure your IDE with a static token. This works with any IDE that supports MCP URL-type servers: ```jsonc { "mcpServers": { "tesser-payments": { "type": "url", "url": "https://sandbox.tesserx.co/v1/mcp", "headers": { "Authorization": "Bearer $MCP_TOKEN" } } } } ``` Set `MCP_TOKEN` in your shell **before** launching the IDE. ## Token Helper Script The Tesser repo includes a helper script that reads credentials from `.env` and outputs a fresh token: ```bash export MCP_TOKEN=$(bash scripts/mcp-token.sh) ``` ## Token Expiry Tokens expire after approximately 24 hours. When a token expires, MCP tool calls will fail with a 401 error. You will need to re-run the token fetch command and restart your IDE session. For automatic token refresh, use [mcp-remote](/agentic/mcp-integration) instead. --- ## Document: AI Context File A ready-to-paste context file that gives AI assistants Tesser API knowledge URL: /agentic/ai-context # AI Context File Copy the markdown below into a `CLAUDE.md`, `.cursorrules`, or similar AI context file in your project. This gives your AI coding assistant the knowledge it needs to work with the Tesser API without re-reading the full documentation each session. ## Usage 1. Copy the content below 2. Save it as `CLAUDE.md` (for Claude Code), `.cursorrules` (for Cursor), or any context file your tool supports 3. Place it in your project root ## Context File ````markdown # Tesser Payments API ## Overview Tesser is a payments platform for stablecoin and fiat transfers. The API handles payment creation, wallet management, counterparty onboarding, compliance screening, and treasury operations. ## API Access - **Base URL**: `https://sandbox.tesserx.co/v1` - **Auth**: OAuth 2.0 client credentials → Bearer token - **Docs**: https://docs.tesser.xyz - **LLM docs**: https://docs.tesser.xyz/llms-full.txt - **OpenAPI Schema**: https://docs.tesser.xyz/api/v1/schema.json ### Authentication ```bash curl --request POST \ --url https://dev-awqy75wdabpsnsvu.us.auth0.com/oauth/token \ --header 'content-type: application/json' \ --data '{ "client_id": "'$TESSER_API_KEY'", "client_secret": "'$TESSER_API_SECRET'", "audience": "https://sandbox.tesserx.co", "grant_type": "client_credentials" }' ``` ### Environment Variables ``` TESSER_API_KEY=your-api-key TESSER_API_SECRET=your-api-secret ``` ## MCP Server All API operations are available as MCP tools at `https://sandbox.tesserx.co/v1/mcp`. ## Key Endpoints | Method | Path | Description | | --- | --- | --- | | POST | `/v1/payments` | Create a payment (payout, deposit) | | GET | `/v1/payments/{id}` | Get payment by ID | | PATCH | `/v1/payments/{id}` | Update payment with account info | | POST | `/v1/payments/{id}/risk-review` | Submit risk review decision | | GET | `/v1/accounts` | List accounts (wallets, ledgers, bank accounts) | | POST | `/v1/accounts` | Create an account | | GET | `/v1/entities/counterparties` | List counterparties | | POST | `/v1/entities/counterparties` | Create a counterparty | | GET | `/v1/currencies` | List supported currencies | | GET | `/v1/networks` | List supported blockchain networks | ## API Conventions - All request/response fields use **snake_case** - Amounts are strings (e.g. `"1000.50"`) - IDs are UUIDs - Timestamps are ISO 8601 (e.g. `"2025-12-01T09:00:00.000Z"`) - Webhook events follow the pattern `resource.action` (e.g. `payment.balance_updated`, `step.confirmed`) ```` --- ## Document: Request Supported Currencies and Networks Learn which currencies and payment networks are available URL: /how-tos/send-a-stablecoin-payout/supported-currencies-and-networks # Request Supported Currencies and Networks You can use the API to learn which currencies and payment networks are available. ### **Request available blockchain networks** Call the [available networks](/api/networks#get-available-networks) endpoint to retrieve list of all supported blockchain networks. Returns an array with network key and display name. **Shell** ```bash curl -H "Authorization: Bearer ${YOUR_API_KEY}" \ -X GET https://api.tesser.xyz/v1/networks ``` **Response** **JSON** ```json { "data": [ { "key": "ETHEREUM", "name": "Ethereum" }, { "key": "POLYGON", "name": "Polygon" }, { "key": "STELLAR", "name": "Stellar" }, { "key": "SOLANA", "name": "Solana" } ] } ``` ### **Request available currencies and networks** Call the [**available currencies**](/api/currencies#get-available-currencies) endpoint to receive a list of supported currencies (crypto and fiat) and which networks they are supported on. Returns an array with currency name, key, decimals, and network information. ```bash curl -H "Authorization: Bearer ${YOUR_API_KEY}" \ -X GET https://api.tesser.xyz/v1/currencies ``` **Response** ```json { "data": [ { "name": "US Dollar", "key": "USD", "decimals": 2, "chain": null }, { "name": "Circle USD", "key": "USDC", "decimals": 6, "chain": "ETHEREUM" }, { "name": "Tether USD", "key": "USDT", "decimals": 6, "chain": "ETHEREUM" }, { "name": "Circle USD", "key": "USDC", "decimals": 6, "chain": "POLYGON" }, { "name": "Tether USD", "key": "USDT", "decimals": 6, "chain": "POLYGON" }, { "name": "Circle USD", "key": "USDC", "decimals": 6, "chain": "STELLAR" }, { "name": "Tether USD", "key": "USDT", "decimals": 6, "chain": "STELLAR" }, { "name": "Circle USD", "key": "USDC", "decimals": 6, "chain": "SOLANA" }, { "name": "Tether USD", "key": "USDT", "decimals": 6, "chain": "SOLANA" } ] } ``` --- ## Document: Payments Workflow End-to-end payment execution flow URL: /how-tos/send-a-stablecoin-payout/payout-workflow # Payments Workflow Payments progress through a workflow that plans the payment and then executes a sequence of funds transfer steps. - **Payment Planning (prior to funds movement)** - Plans the route for the payment and obtains quote information. See [Payment planning](/overviews/payment-planning). - Screens beneficiary wallet risk - If manual risk review is required, a user with sufficient permissions can review the payment in the Tesser dashboard, or the decision can be programmatically delivered to Tesser via [API](/api/payments#submit-risk-review). - **Payment Execution (funds movement)** - Reserves available balance (if insufficient funds, will enqueue for future execution) - Uses the signing keys configured for the organization to authorize transfers (if using self-custodial model) - Requires explicit initiation/approval by the customer (or their configured signing automation) — Tesser cannot execute unilaterally - Results in funds actually moving on the specified blockchain network - If applicable, delivers fiat to the beneficiary **Example workflow for stablecoin payouts:** ![image.png](./payout-workflow1.png) **Example workflow for fiat payouts:** ![image.png](./payout-workflow2.png) **Statuses in the payment workflow** Certain components of a payment maintain their own status as the payment progresses through the workflow: - Risk review - Balance Check - Transfer steps > *Note: For transfer steps, it is possible for the next step to begin execution prior to a prior step completing. E.g. a transfer of fiat may begin prior to a transfer of crypto finalizing. **Risk statuses** Result of risk review performed on beneficiary wallet
**Status** **Terminal** **Webhook event type** **Description**
`unchecked` No

Not sent. All payments at creation have a risk status of `unchecked`

Beneficiary wallet identifier has not been supplied or risk check has not yet completed.
`awaiting_decision` No Risk.updated Beneficiary wallet has been risk screened and requires manual review to determine whether to send the payout.
`auto_approved` Yes Risk.updated Beneficiary wallet has been risk screened and automatically approved per your organization's policy.
`manually_approved` Yes Risk.updated Beneficiary wallet has been risk screened and has been manually reviewed and approved.
`auto_rejected` Yes Risk.updated Beneficiary wallet has been risk screened and automatically rejected per your organization's policy.
`manually_rejected` Yes Risk.updated Beneficiary wallet has been risk screened and has been manually reviewed and rejected.
**Balance statuses** Result of balance check for source wallet
**Status** **Terminal** **Webhook event type** **Description**
`unreserved` No

Not sent. All payments at creation have a balance status of `unreserved`

Source wallet id has not been supplied or the reserve operation has not yet completed.
`awaiting_funds` No Balance.updated The balance of the source wallet was checked and there are insufficient funds to process the payout. The payment is queued and awaiting funds from a deposit.
`reserved` Yes Balance.updated The balance of the source wallet was checked and funds were reserved to process the payout.
**Payment Steps** Each payment consists of multiple steps that track the money movement through the system: - **On-Network Transfer**: Transfer stablecoins on the underlying network - **Cross-Network Bridge**: Move assets between different networks (when needed) - **Token Swap**: Convert between different stablecoins or tokens (when needed) - **Fiat Conversion**: Convert stablecoins to fiat currency (when needed for off-ramped payments) Steps are tracked individually, allowing you to monitor the exact progress of each money movement operation. **Payment steps statuses**
**Status** **Terminal** **Webhook event type** **Description**
`created` No

Not sent. All steps at creation have a status of `created`

Tesser has created a record for this step.
`submitted` No step.updated Tesser submitted the step information to the blockchain or fiat payment network
`confirmed` No step.updated The step was accepted by the operator of the payment network
`finalized` No step.updated For crypto transfer steps, the block containing the transfer step has been finalized. The transfer step is now permanent and irreversible. How long it takes to finalize a transfer depends on the blockchain.
`completed` No step.updated

For fiat transfer steps, indicates the local payment network has delivered funds to the beneficiary.

*Note, some fiat payment networks may not provide formal confirmation of funds delivery, in which case funds are assumed to be delivered unless a `failed` status is indicated

`failed` Yes step.updated The transfer step was not successful; funds were not transferred from the `from_account` to the `to_account`
--- ## Document: Create a Payout (via Custodian) Create and execute payouts using third-party custodian accounts URL: /how-tos/send-a-stablecoin-payout/create-a-stablecoin-payout # Create a Payout (via Custodian) This guide is for payout creation when funds are custodied via a third-party custodian (e.g. Circle). To create a payout, send a POST request to the [Payments API](/api/payments#create-payment). > For payouts, you can supply all the required information about the payout in the creation API call, or if desired, only supply the minimally necessary information for payment creation and then [update the payment](/api/payments#update-payment) with account information. ## Payout creation At a minimum, supply the following information to create the payout record: - Currencies: `from_currency` and `to_currency` - Amounts: One of the `from_amount` or `to_amount`. - Networks: For stablecoin payouts, specify the blockchain networks that should be involved (`from_network` and `to_network`). For fiat payouts, leave these fields blank. Example request for stablecoin payout creation: ```json { "from_currency": "USDC", "to_currency": "USDC", "from_amount": "1000", "to_amount": null, "from_network": "ETHEREUM", "to_network": "ETHEREUM", "organization_reference_id": "ref_123" } ``` Example request for fiat payout creation: ```json { "from_currency": "USDC", "to_currency": "MXN", "from_amount": null, "to_amount": 1000, "from_network": null, "to_network": null, "organization_reference_id": "ref_123" } ``` > Only one of `from_amount` or `to_amount` is permitted to be specified in the request, but not both. In the synchronous response, you will receive an `id` for the payout that you can use for subsequent PATCH or GET calls or to track webhook updates received for this payout. Example response for stablecoin payout creation: ```json { "data": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "from_account_id": null, "funding_account_id": null, "to_account_id": null, "from_amount": "1000", "from_currency": "USDC", "from_network": "ETHEREUM", "to_amount": "1000", "to_currency": "USDC", "to_network": "ETHEREUM", "risk_status": "unchecked", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "unreserved", "balance_reserved_at": null, "steps": [], "created_at": "2025-12-01T09:00:00.000Z", "updated_at": "2025-12-01T09:00:00.000Z", "expires_at": "2025-12-01T23:59:59.999Z" } } ``` Example response for fiat payout creation: ```json { "data": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "from_account_id": null, "funding_account_id": null, "to_account_id": null, "from_amount": null, "from_currency": null, "from_network": null, "to_amount": "1000", "to_currency": "MXN", "to_network": "null", "risk_status": "unchecked", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "unreserved", "balance_reserved_at": null, "steps": [], "created_at": "2025-12-01T09:00:00.000Z", "updated_at": "2025-12-01T09:00:00.000Z", "expires_at": "2025-12-01T23:59:59.999Z" } } ``` Tesser will asynchronously source the best the exchange rate for the payout based on the `from_currency` and `to_currency` and the supplied `from_amount` or `to_amount`. Once the exchange rate is locked, Tesser will communicate this information via a webhook. The amount field that was previously null will be updated with the calculated amount of the currency required to execute the payout. In the examples in this guide, the `to_amount` will be populated for the stablecoin payout and the `from_amount` for the fiat payout. For more information on the costs, see [Payment Planning](/overviews/payment-planning). The payout will have a `balance_status` of "unreserved" and a `risk_status` of "unchecked", as these processes have not yet started. For more information on the lifecycle of a payout, see [Payments Workflow](/how-tos/send-a-stablecoin-payout/payout-workflow). Example webhook schema for stablecoin payout with exchange rate: ```json { "id": "event_111", "type": "payment.quote_created", "created_at": "2025-12-01T09:00:00.045Z", "data": { "object": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "payment_type": "payment", "from_account_id": null, "funding_account_id": null, "to_account_id": null, "from_amount": "1000", "from_currency": "USDC", "from_network": "ETHEREUM", "to_amount": "1000", "to_currency": "USDC", "to_network": "ETHEREUM", "risk_status": "unchecked", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "unreserved", "balance_reserved_at": null, "steps": [], "created_at": "2025-12-01T09:00:00.000Z", "updated_at": "2025-12-01T09:00:00.040Z", "expires_at": "2025-12-01T23:59:59.999Z" } } } ``` Example webhook schema for fiat payout with exchange rate: ```json { "id": "event_111", "type": "payment.quote_created", "created_at": "2025-12-01T09:00:00.045Z", "data": { "object": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "payment_type": "payment", "from_account_id": null, "funding_account_id": null, "to_account_id": null, "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_amount": "1000", "to_currency": "MXN", "to_network": "null", "risk_status": "unchecked", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "unreserved", "balance_reserved_at": null, "steps": [], "created_at": "2025-12-01T09:00:00.000Z", "updated_at": "2025-12-01T09:00:00.040Z", "expires_at": "2025-12-01T23:59:59.999Z" } } } ``` ## Update payout with account information If you did not already supply the account information in the creation step, then submit a PATCH request to the [Payments API](/api/payments#update-payment). Now you will supply identifiers for: - `from_account_id`: Ledger on the Tesser platform that funds will come from. As this is a payout using a third-party custodian, ensure `from_account_id` has a `type` = "ledger". - `to_account_id`: Wallet or bank account of the beneficiary that funds will be delivered to - `funding_account_id`: Fiat bank account of the ultimate originator of the payout > Because the Tesser platform serves financial institutions, the `from_account_id` may belong to a counterparty, tenant, or the workspace. Thus, `funding_account_id` is required to determine the ultimate originating entity (individual or business) of the payout to fulfill Travel Rule obligations. For more information, see [Travel Rule](/overviews/compliance-and-risk#travel-rule). Example request for stablecoin payout updated with accounts: ```json { "funding_account_id": "550e8400-e29b-41d4-a716-446655440011", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "to_account_id": "550e8400-e29b-41d4-a716-446655440012" } ``` Example request for fiat payout updated with accounts: ```json { "funding_account_id": "550e8400-e29b-41d4-a716-446655440011", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "to_account_id": "a3f7c891-bd42-4e19-9c5a-2d8b6f3e1047" } ``` In the synchronous response, the payout will now contain the submitted account identifiers. Tesser will asynchronously plan the best route for the payout to minimize costs and maximize speed of funds delivery. Via a webhook, you will receive route planning information, including all of the steps needed to send funds from the originator to beneficiary, as well as the payout's risk review status. Example webhook schema for stablecoin payout with planned steps: ```json { "id": "event_222", "type": "payment.steps_created", "created_at": "2025-12-01T09:00:00.055Z", "data": { "object": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "funding_account_id": "550e8400-e29b-41d4-a716-446655440011", "to_account_id": "550e8400-e29b-41d4-a716-446655440012", "from_amount": "1000", "from_currency": "USDC", "from_network": "ETHEREUM", "to_amount": "1000", "to_currency": "USDC", "to_network": "ETHEREUM", "risk_status": "auto_approved", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "unreserved", "balance_reserved_at": null, "steps": [ { "id": "550e8400-e29b-41d4-a716-446655440100", "transfer_id": "550e8400-e29b-41d4-a716-446655440020", "step_sequence": 1, "step_type": "transfer", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "from_amount": "1000", "from_currency": "USDC", "from_network": "ETHEREUM", "to_account_id": "550e8400-e29b-41d4-a716-446655440012", "to_amount": "1000", "to_currency": "USDC", "to_network": "ETHEREUM", "transaction_hash": null, "fees": [], "provider_key": "circle_mint", "status": "created", "status_reasons": [], "created_at": "2025-12-01T09:00:00.050Z", "updated_at": "2025-12-01T09:00:00.050Z", "submitted_at": null, "confirmed_at": null, "finalized_at": null, "failed_at": null } ], "created_at": "2024-03-01T10:00:00.000Z", "updated_at": "2024-03-01T10:02:00.000Z", "expires_at": "2024-03-02T10:00:00.000Z" } } } ``` Example webhook schema for fiat payout with planned steps: ```json { "id": "event_222", "type": "payment.steps_created", "created_at": "2025-12-01T09:00:00.055Z", "data": { "object": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "funding_account_id": "550e8400-e29b-41d4-a716-446655440011", "to_account_id": "a3f7c891-bd42-4e19-9c5a-2d8b6f3e1047", "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_amount": "1000", "to_currency": "MXN", "to_network": "null", "risk_status": "auto_approved", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "unreserved", "balance_reserved_at": null, "steps": [ { "id": "550e8400-e29b-41d4-a716-446655440100", "transfer_id": "550e8400-e29b-41d4-a716-446655440020", "step_sequence": 1, "step_type": "transfer", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_account_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "to_amount": "55.85", "to_currency": "USDC", "to_network": null, "transaction_hash": null, "fees": [], "provider_key": "circle_mint", "status": "created", "status_reasons": [], "created_at": "2025-12-01T09:00:00.050Z", "updated_at": "2025-12-01T09:00:00.050Z", "submitted_at": null, "confirmed_at": null, "finalized_at": null, "failed_at": null }, { "id": "a7b3d912-5f8e-4c23-9d6a-1e4f7b2c8a5d", "transfer_id": "550e8400-e29b-41d4-a716-446655440020", "step_sequence": 2, "step_type": "transfer", "from_account_id": "f3a8b2c1-7d4e-4f9a-b6e5-2c8d9a1f0e3b", "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_account_id": "a3f7c891-bd42-4e19-9c5a-2d8b6f3e1047", "to_amount": "1000", "to_currency": "MXN", "to_currency": null, "transaction_hash": null, "fees": [], "provider_key": "alfred", "status": "created", "status_reasons": [], "created_at": "2025-12-01T09:00:00.050Z", "updated_at": "2025-12-01T09:00:00.050Z", "submitted_at": null, "confirmed_at": null, "completed_at": null, "failed_at": null } ], "created_at": "2025-12-01T09:00:00.000Z", "updated_at": "2025-12-01T09:00:00.050Z", "expires_at": "2025-12-01T23:59:59.999Z" } } } ``` ## Payout risk review Once you have inputted the `to_account_id`, Tesser will conduct risk screening on the beneficiary's wallet or intermediate wallets in the flow. Based on how your organization's risk policy is configured, manual review may be required (`awaiting_decision`), or the payout may be automatically approved (`auto_approved`) or automatically rejected (`auto_rejected`). If there are risk factors identified for the beneficiary, these risk reasons will be updated on the payout, included in the webhook, and available to view in the Tesser dashboard. If manual review is required (risk status = `awaiting_decision`), you can submit the decision by calling the [risk review decision API](/api/payments#submit-risk-review) or via the dashboard. Once you have decisioned the payout, the risk status will transition to `manually_approved` or `manually_rejected`. Example response with risk reasons: ```json { "data": { "risk_status": "awaiting_decision", "risk_status_reasons": [ { "risk_status_reason_type": "indirect", "risk_status_reason_category": "malware", "risk_status_reason_severity": "High" } ], "risk_reviewed_by": null, "risk_reviewed_at": null } } ``` ## Payout execution If the payout is approved, the payout will begin execution. ### Balance check Tesser will check the balance of the ledger supplied as `from_account_id` and update the payout's `balance_status` to "reserved" if there are sufficient funds for the payout, or "awaiting-funds" if there are insufficient funds. A webhook will also be published with event type payment.balance_updated indicating the outcome of the balance check. Example webhook schema for stablecoin payout after balance check: ```json { "id": "event_333", "type": "payment.balance_updated", "created_at": "2025-12-01T09:00:00.055Z", "data": { "object": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "funding_account_id": "550e8400-e29b-41d4-a716-446655440011", "to_account_id": "550e8400-e29b-41d4-a716-446655440012", "from_amount": "1000", "from_currency": "USDC", "from_network": "ETHEREUM", "to_amount": "1000", "to_currency": "USDC", "to_network": "ETHEREUM", "risk_status": "auto_approved", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "reserved", "balance_reserved_at": "2025-12-01T09:00:00.060Z", "steps": [ { "id": "550e8400-e29b-41d4-a716-446655440100", "transfer_id": "550e8400-e29b-41d4-a716-446655440020", "step_sequence": 1, "step_type": "transfer", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "from_amount": "1000", "from_currency": "USDC", "from_network": "ETHEREUM", "to_account_id": "550e8400-e29b-41d4-a716-446655440012", "to_amount": "1000", "to_currency": "USDC", "to_network": "ETHEREUM", "transaction_hash": null, "fees": [], "provider_key": "circle_mint", "status": "created", "status_reasons": [], "created_at": "2025-12-01T09:00:00.050Z", "updated_at": "2025-12-01T09:00:00.050Z", "submitted_at": null, "confirmed_at": null, "finalized_at": null, "failed_at": null } ], "created_at": "2025-12-01T09:00:00.000Z", "updated_at": "2025-12-01T09:00:00.060Z", "expires_at": "2025-12-01T23:59:59.999Z" } } } ``` Example webhook schema for fiat payout after balance check: ```json { "id": "event_333", "type": "payment.balance_updated", "created_at": "2025-12-01T09:00:00.055Z", "data": { "object": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "funding_account_id": "550e8400-e29b-41d4-a716-446655440011", "to_account_id": "a3f7c891-bd42-4e19-9c5a-2d8b6f3e1047", "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_amount": "1000", "to_currency": "MXN", "to_network": "null", "risk_status": "auto_approved", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "reserved", "balance_reserved_at": "2025-12-01T09:00:00.060Z", "steps": [ { "id": "550e8400-e29b-41d4-a716-446655440100", "transfer_id": "550e8400-e29b-41d4-a716-446655440020", "step_sequence": 1, "step_type": "transfer", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_account_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "to_amount": "55.85", "to_currency": "USDC", "to_network": null, "transaction_hash": null, "fees": [], "provider_key": "circle_mint", "status": "created", "status_reasons": [], "created_at": "2025-12-01T09:00:00.050Z", "updated_at": "2025-12-01T09:00:00.050Z", "submitted_at": null, "confirmed_at": null, "finalized_at": null, "failed_at": null }, { "id": "a7b3d912-5f8e-4c23-9d6a-1e4f7b2c8a5d", "transfer_id": "550e8400-e29b-41d4-a716-446655440020", "step_sequence": 2, "step_type": "transfer", "from_account_id": "f3a8b2c1-7d4e-4f9a-b6e5-2c8d9a1f0e3b", "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_account_id": "a3f7c891-bd42-4e19-9c5a-2d8b6f3e1047", "to_amount": "1000", "to_currency": "MXN", "to_network": null, "transaction_hash": null, "fees": [], "provider_key": "alfred", "status": "created", "status_reasons": [], "created_at": "2025-12-01T09:00:00.050Z", "updated_at": "2025-12-01T09:00:00.050Z", "submitted_at": null, "confirmed_at": null, "completed_at": null, "failed_at": null } ], "created_at": "2025-12-01T09:00:00.000Z", "updated_at": "2025-12-01T09:00:00.060Z", "expires_at": "2025-12-01T23:59:59.999Z" } } } ``` ### Crypto transfer step(s) processing Once there are enough funds, Tesser will instruct the custodian where to transfer funds to the next participant in the flow. In the examples in this guide, for the stablecoin payout, Tesser will instruct the custodian Circle to transfer funds on-chain to the beneficiary wallet using Ethereum as the network, with no currency swaps or network bridging needed. For the fiat payout, Tesser will instruct Circle to transfer funds on-chain to Alfred, the provider for the fiat off-ramp. After the transfer has been submitted to the applicable blockchain network, the payment will be updated with the blockchain transaction hash (`transaction_hash`), and the `status` of the crypto-step will be updated to "submitted". After the on-chain step(s) have progressed to a `status` of "confirmed", network (e.g. gas) fee information will be available on the payment via webhook notification, by polling the [GET payment API](/api/payments#get-payment-by-id), and via the Tesser dashboard. Tesser sponsors gas fees for your organization, so on-chain transfers will not fail due to lack of balance in the ledger account to pay gas or other network fees. Your organization will be billed at month end for accrued gas fees. Example webhook schema for stablecoin payout - submission to blockchain network: ```json { "data": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "funding_account_id": "550e8400-e29b-41d4-a716-446655440011", "to_account_id": "550e8400-e29b-41d4-a716-446655440012", "from_amount": "1000", "from_currency": "USDC", "from_network": "ETHEREUM", "to_amount": "1000", "to_currency": "USDC", "to_network": "ETHEREUM", "risk_status": "auto_approved", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "reserved", "balance_reserved_at": "2025-12-01T09:00:00.060Z", "steps": [ { "id": "550e8400-e29b-41d4-a716-446655440100", "transfer_id": "550e8400-e29b-41d4-a716-446655440020", "step_sequence": 1, "step_type": "transfer", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "from_amount": "1000", "from_currency": "USDC", "from_network": "ETHEREUM", "to_account_id": "550e8400-e29b-41d4-a716-446655440012", "to_amount": "1000", "to_currency": "USDC", "to_network": "ETHEREUM", "transaction_hash": "0xd65dc6bf6dcc111237f9acfbfa6003ea4a4d88f2e071f4307d3af81ae877f7be", "fees": [ { "fee_amount": "0.01", "fee_currency": "USDC", "fee_type": "gas", "fee_metadata": {} } ], "provider_key": "circle_mint", "status": "confirmed", "status_reasons": [], "created_at": "2025-12-01T09:00:00.050Z", "updated_at": "2025-12-01T09:00:00.070Z", "submitted_at": "2025-12-01T09:00:00.070Z", "confirmed_at": null, "finalized_at": null, "failed_at": null } ], "created_at": "2025-12-01T09:00:00.000Z", "updated_at": "2025-12-01T09:00:00.070Z", "expires_at": "2025-12-01T23:59:59.999Z" } } ``` Example webhook schema for fiat payout - submission to blockchain network: ```json { "data": { "id": "550e8400-e29b-41d4-a716-446655440020", "workspace_id": "550e8400-e29b-41d4-a716-446655440001", "organization_reference_id": "ref_123", "direction": "outbound", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "funding_account_id": "550e8400-e29b-41d4-a716-446655440011", "to_account_id": "a3f7c891-bd42-4e19-9c5a-2d8b6f3e1047", "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_amount": "1000", "to_currency": "MXN", "to_network": "null", "risk_status": "auto_approved", "risk_status_reasons": [], "risk_reviewed_by": null, "risk_reviewed_at": null, "balance_status": "reserved", "balance_reserved_at": "2025-12-01T09:00:00.060Z", "steps": [ { "id": "550e8400-e29b-41d4-a716-446655440100", "transfer_id": "550e8400-e29b-41d4-a716-446655440020", "step_sequence": 1, "step_type": "transfer", "from_account_id": "550e8400-e29b-41d4-a716-446655440010", "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_account_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "to_amount": "55.85", "to_currency": "USDC", "to_network": null, "transaction_hash": "0x1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7a8b9c0d1e2f", "fees": [ { "fee_amount": "0.01", "fee_currency": "USDC", "fee_type": "gas", "fee_metadata": {} } ], "provider_key": "circle_mint", "status": "confirmed", "status_reasons": [], "created_at": "2025-12-01T09:00:00.050Z", "updated_at": "2025-12-01T09:00:00.070Z", "submitted_at": "2025-12-01T09:00:00.070Z", "confirmed_at": null, "finalized_at": null, "failed_at": null }, { "id": "a7b3d912-5f8e-4c23-9d6a-1e4f7b2c8a5d", "transfer_id": "550e8400-e29b-41d4-a716-446655440020", "step_sequence": 2, "step_type": "transfer", "from_account_id": "f3a8b2c1-7d4e-4f9a-b6e5-2c8d9a1f0e3b", "from_amount": "55.85", "from_currency": "USDC", "from_network": null, "to_account_id": "a3f7c891-bd42-4e19-9c5a-2d8b6f3e1047", "to_amount": "1000", "to_currency": "MXN", "to_network": null, "transaction_hash": null, "fees": [], "provider_key": "alfred", "status": "created", "status_reasons": [], "created_at": "2025-12-01T09:00:00.050Z", "updated_at": "2025-12-01T09:00:00.050Z", "submitted_at": null, "confirmed_at": null, "completed_at": null, "failed_at": null } ], "created_at": "2025-12-01T09:00:00.000Z", "updated_at": "2025-12-01T09:00:00.070Z", "expires_at": "2025-12-01T23:59:59.999Z" } } ``` ### Fiat step processing Once the stablecoin funds have reached the off-ramp provider, Tesser will instruct the provider to payout the funds to the beneficiary at the account specified by the `to_account_id`. ### Payout completion As each step progresses, the status for the step will be updated and available via webhook notification, by polling the [GET payment API](/api/payments#get-payment-by-id), and via the Tesser dashboard. If a step fails, the reasons for the failure will be available via the `status_reasons` array. For more information on the `balance_status` and statuses of the transfer steps, see [Payout workflow](/how-tos/send-a-stablecoin-payout/payout-workflow). Payouts can be considered complete when the last transfer step has a `status` of "finalized" for a stablecoin payout or "completed" for a fiat payout. For blockchain networks, finality refers to the point where a transaction is considered permanent and irreversible. Finalization usually takes a few second to about 15 minutes depending on the blockchain network(s) used. ## Payment fields | **Parameter** | **Type** | **Description** | | --- | --- | --- | | **id** | string (uuid) | Unique Tesser identifier of the payment. | | **workspace_id** | string (uuid) | Unique Tesser identifier of the workspace the payment belongs to. | | **organization_reference_id** | string | Optional external reference ID for the organization. | | **direction** | string | The direction of the payment (e.g., 'outbound'). | | **from_account_id** | string (uuid) | The ledger account on the Tesser platform that funds come from. | | **funding_account_id** | string (uuid) | Fiat bank account of the ultimate originator of the payout. | | **to_account_id** | string (uuid) | Wallet or bank account of the beneficiary that funds will be delivered to. | | **from_amount** | string | Amount to send in source currency units. | | **from_currency** | string | Source currency code (e.g., 'USDC'). | | **from_network** | string | Blockchain network for source currency (e.g., 'POLYGON'). Only applicable for stablecoin payments; null for fiat payments. | | **to_amount** | string | Amount to receive in destination currency units. | | **to_currency** | string | Destination currency code (e.g., 'USD'). | | **to_network** | string | Blockchain network for destination currency. Only applicable for stablecoin payments; null for fiat payments. | | **risk_status** | string (enum) | The current risk review status of the payment. (Enum values: `unchecked`, `awaiting_decision`, `auto_approved`, `manually_approved`, `auto_rejected`, `manually_rejected`). See [Risk statuses](/how-tos/send-a-stablecoin-payout/payout-workflow#risk-statuses) for more information. | | **risk_status_reasons** | array | List of reasons associated with the risk status. | | **risk_reviewed_by** | string (nullable) | The user or system identifier that performed the risk review, if applicable. | | **risk_reviewed_at** | string (date-time, nullable) | The timestamp when the risk review was completed, if applicable. | | **balance_status** | string (enum) | Status of the balance reservation (Enum values: `unreserved`, `awaiting_funds`, `reserved`). See [Balance statuses](/how-tos/send-a-stablecoin-payout/payout-workflow#balance-statuses) for more information. | | **balance_reserved_at** | string (date-time) | The timestamp when the balance was reserved. | | **steps** | array | A list of execution steps (transfers, fees, etc.) associated with processing the payment. | | **created_at** | string (date-time) | The ISO 8601 date and time when the payment was created. | | **updated_at** | string (date-time) | The ISO 8601 date and time when the payment was last updated. | | **expires_at** | string (date-time) | The ISO 8601 date and time when the payment will expire. After this time, a new payment must be created. | ### Risk status reason array fields | **Parameter** | **Type** | **Description** | | --- | --- | --- | | **risk_status_reason_type** | string (enum) | Type of risk, based on who the wallet is likely owned by (ownership), with whom the wallet has direct interaction (counterparty), the wallet's own pattern of activity (behavioral), and wallet activity 2 or more degrees removed (indirect). Can be used programmatically (enum values: `ownership`, `counterparty`, `indirect`, or `behavioral`) | | **risk_status_reason_category** | string | The category of risk within a type e.g. community complaint, high-risk exchange, peer-to-peer crypto marketplace, gambling service. Can be used programmatically. See [Wallet Risk Categories](/overviews/compliance-and-risk#wallet-risk-categories) for more information. | | **risk_status_reason_severity** | string (enum) | The severity level of the risk reason identified for the screened wallet (enum values: `low`, `medium`, `high`, `severe`) | ### Steps array fields | **Parameter** | **Type** | **Description** | | --- | --- | --- | | **id** | string (uuid) | Unique identifier for the specific step. | | **transfer_id** | string (uuid) | The unique identifier of the parent payment or transfer this step belongs to. | | **step_sequence** | integer | The numerical order of this step in the overall payment execution flow. | | **step_type** | string (enum) | The type of operation being performed in this step (enum values: `onramp`, `offramp`, `crypto_transfer`, `fiat_transfer`) | | **from_account_id** | string (uuid) | The ID of the specific account asset (wallet) funds are moving from. | | **from_amount** | string | The amount of funds being sent in this step. | | **from_currency** | string | The currency code of the funds being sent (e.g., 'USDC'). | | **to_account_id** | string (uuid) | The ID of the specific account asset (wallet) funds are moving to. | | **to_amount** | string | The amount of funds expected to be received in this step. | | **to_currency** | string | The currency code of the funds being received. | | **transaction_hash** | string (nullable) | The blockchain transaction hash associated with this step, if applicable. | | **fees** | array | A list of fees that may be incurred for each step. | | **provider_key** | string (enum) (nullable) | The identifier or key of the external provider used for this step (enum values: `alfred`, `circle-mint`) | | **status** | string (enum) | The current status of this specific step (enum values: `created`, `submitted`, `confirmed`, `finalized`, `completed`, `failed`). See [Payment step statuses](/how-tos/send-a-stablecoin-payout/payout-workflow#payment-step-statuses) for more information. | | **status_reasons** | array | A list of reasons associated with the current status. | | **created_at** | string (date-time) | ISO 8601 timestamp when the step was created. | | **updated_at** | string (date-time) | ISO 8601 timestamp when the step was last updated. | | **submitted_at** | string (date-time, nullable) | ISO 8601 timestamp when the step was submitted to the network or provider. | | **confirmed_at** | string (date-time, nullable) | ISO 8601 timestamp when the step was confirmed on-chain or by the provider. | | **completed_at** | string (date-time, nullable) | ISO 8601 timestamp when the step was completed by the provider. | | **finalized_at** | string (date-time, nullable) | ISO 8601 timestamp when the step was finalized on-chain. | | **failed_at** | string (date-time, nullable) | ISO 8601 timestamp when the step failed, if applicable. | ### Fees array fields | **Parameter** | **Type** | **Description** | | --- | --- | --- | | **fee_amount** | string | The amount of the fee. | | **fee_currency** | string | The currency of the fee. | | **fee_type** | string | The type of fee (e.g., 'gas', 'provider'). | | **fee_metadata** | object | Additional metadata about the fee. |