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.
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 with account information.
Payout creation
At a minimum, supply the following information to create the payout record:
- Currencies:
from_currencyandto_currency - Amounts: One of the
from_amountorto_amount. - Networks: For stablecoin payouts, specify the blockchain networks that should be involved (
from_networkandto_network). For fiat payouts, leave these fields blank.
Example request for stablecoin payout creation:
Code
Only one of
from_amountorto_amountis 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:
Code
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.
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.
Example webhook schema for stablecoin payout with exchange rate:
Code
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 and supply the additional information about the originator and beneficiary accounts.
As this is a payout using a third-party custodian, ensure for
source_account_idyou only submit the id for an account withtype= "ledger".
Example request for stablecoin payout updated with accounts:
Code
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:
Code
Payout risk review
Once you have inputted the beneficiary_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 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:
Code
Payout execution
If the payout is approved, the payout will begin execution.
Balance check
Tesser will check the balance of the ledger supplied as source_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:
Code
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, 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:
Code
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 beneficiary_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, 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.
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'). |
| source_account_id | string (uuid) | ID of the source account (e.g., wallet) funding the transfer. |
| originator_account_id | string (uuid) | ID of the account originating the payment. |
| beneficiary_account_id | string (uuid) | ID of the beneficiary account. |
| 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 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 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 for more information. |
| risk_status_reason_message | string | Human-readable message describing the risk reason |
| 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 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. |