HTTP 500 response, you cannot know with certainty whether the server processed the request before the error occurred. Retrying without a safeguard risks submitting the same withdrawal twice — a scenario no custody platform should tolerate. The sequence_id field solves this problem by making transaction requests idempotent.
What Idempotency Means for Transactions
An idempotent request is one that produces the same outcome no matter how many times you send it. In the context of Finrock transactions, idempotency means: if you submit a withdrawal with a givensequence_id, and then submit the exact same request again (with the same sequence_id), the platform will not execute a second transfer. Instead, it returns the original response from the first attempt. The funds leave your wallet exactly once.
The sequence_id Field
sequence_id is an optional string field available on the Create Transaction endpoint (POST /dac/v1/transaction). You supply the value yourself — it can be any arbitrary string that is unique within your wallet.
While
sequence_id is optional, Finrock strongly recommends using it for every outgoing transfer. The risk of accidental double-spending without it is not worth the small implementation overhead.sequence_id:
- You define it. Use a value that ties back to a unique record in your own system — an order ID, a payout ID, or a UUID you generate at payout creation time.
- Scoped to your wallet. The
sequence_idis only visible to users with access to your wallet. It is never broadcast on-chain or shared with recipients. - One send per ID. The platform confirms at most one outgoing transfer per
sequence_id. All subsequent requests carrying the same ID return the original response without triggering a new transfer.
How It Works
1
Generate a unique sequence_id
Before submitting a withdrawal, create a
sequence_id derived from a unique identifier in your system — such as your database’s primary key for the payout record.2
Submit the transaction
Include the
sequence_id in the request body when calling POST /dac/v1/transaction.3
Handle the response
If you receive a successful
200 or 201 response, record the returned transaction ID alongside the sequence_id in your database. The transfer is now in progress.4
Retry safely on failure
If you receive a timeout, connection error, or
HTTP 500, retry the request with the same sequence_id and same payload. The platform will deduplicate the request and return the outcome of the first attempt — whether it succeeded or is still processing.5
Poll for final status
Use the returned transaction ID to poll
GET /dac/v1/transaction/{id} until the status reaches a terminal state. See the Transaction Statuses reference for the full list.Code Example
The following example shows how to generate a robustsequence_id from an existing database record and use it when submitting a withdrawal.
Choosing a Good sequence_id
A goodsequence_id is:
- Unique per intended transfer. It should correspond to exactly one payout event in your system.
- Stable across retries. You must be able to reproduce the exact same value when retrying, so derive it from a persistent record rather than generating a random UUID at request time.
- Human-readable. Including a prefix (e.g.,
payout-,withdrawal-) makes it easier to trace in logs and customer support queries.
Supported Endpoints
sequence_id is currently supported on the following endpoint:
Create Transaction
POST /dac/v1/transaction — Submit an outgoing transfer with an idempotency key.