Transfer Lifecycle
Covalent tracks each Travel Rule transfer with separate fields for lifecycle, counterparty status, and compliance verdict. These fields answer different questions and should not be collapsed into one status.
Transfer States
Section titled “Transfer States”state is the primary lifecycle field on a transfer.
| State | Meaning |
|---|---|
created |
Transfer record has been created before background processing starts. |
queued |
Transfer has been queued for the worker. |
processing |
Worker is preparing IVMS, provider routing, screening, or protocol work. |
exchanging |
Protocol data has been sent and Covalent is exchanging IVMS data with the peer/provider. |
awaiting_counterparty |
Both sides have enough data for a decision and Covalent is waiting on peer acceptance or rejection. |
accepted |
The required Travel Rule exchange has been accepted. |
rejected |
The transfer was rejected by policy, officer action, provider status, or counterparty status. |
cancelled |
The transfer was cancelled before completion. |
completed |
The workflow is complete. Below-threshold transfers also finish here. |
failed |
Processing failed and can be retried. |
held |
Automatic progression stopped for review, blocking, or retry handling. |
Valid Transitions
Section titled “Valid Transitions”The transfer state machine only allows these transitions:
| From | To |
|---|---|
created |
queued |
queued |
processing, cancelled |
processing |
exchanging, failed, held |
exchanging |
awaiting_counterparty, held, rejected, failed |
awaiting_counterparty |
accepted, rejected, held |
accepted |
completed, failed, held |
failed |
queued |
held |
queued, awaiting_counterparty, rejected |
Terminal states are:
| State | Terminal Meaning |
|---|---|
rejected |
No further Travel Rule progression. |
cancelled |
Caller or operator stopped the workflow. |
completed |
Workflow is complete. |
Outgoing Flow
Section titled “Outgoing Flow”For an outgoing transfer, Covalent receives the originator IVMS in POST /api/v2/transfers, encrypts it at rest, then queues the provider workflow.
created -> queued -> processing -> exchanging -> awaiting_counterparty -> accepted -> completedImportant outgoing behavior:
queuedmeans the API call succeeded and the worker owns the next step.exchangingmeans the provider/protocol has enough data to contact the beneficiary side and exchange IVMS.awaiting_counterpartymeans Covalent is waiting for the peer/provider accept or reject decision.completedusually happens after acceptance and transaction confirmation.- Through Notabene, Global Travel Rule and Sygna Bridge, the originator data sent to the counterparty is the customer's verified Travel Rule identity.
Incoming Flow
Section titled “Incoming Flow”An incoming transfer arrives through one of your Travel Rule providers, for one of your registered wallets: by the provider's callback, or by a sync (Veriscope creates it when it discovers an attestation for a registered beneficiary wallet).
created -> queued -> processing -> exchanging -> awaiting_counterparty -> accepted -> completedImportant incoming behavior:
- The incoming transfer is created by the provider integration, not by a public create-transfer API call.
- Covalent links it to the registered beneficiary wallet and that wallet's customer.
- Originator IVMS is received through the provider exchange and stored encrypted at rest.
- Beneficiary IVMS comes from the customer's verified Travel Rule identity. Without one, Covalent does not send beneficiary data to the originator VASP.
Party Status Fields
Section titled “Party Status Fields”Transfer detail responses expose party status under:
{ "status": { "ours": "pending", "theirs": "accepted" }}The persisted party status fields are:
| Field | Meaning |
|---|---|
originatorStatus |
Originator-side Travel Rule status. |
beneficiaryStatus |
Beneficiary-side Travel Rule status. |
Known values used by the model are:
| Status | Meaning |
|---|---|
pending |
No final party decision yet. |
accepted |
That party accepted or completed its side of the exchange. |
rejected |
That party rejected the exchange. |
Compliance Status
Section titled “Compliance Status”complianceStatus is the compliance verdict, not the transfer lifecycle. A transfer's detail shows it as compliance.status, a list row as status, and webhook payloads as complianceStatus. List transfers by it with ?status= or ?complianceStatus=.
| Status | Meaning |
|---|---|
pending |
Screening has not produced a final verdict, or a human review is still open. |
approved |
Screening passed, or Travel Rule processing was not required. |
rejected |
Screening or review produced a no-go decision. |
When a transfer is in the officer queue, use the combination:
state = heldcomplianceStatus = pendingBelow-Threshold Transfers
Section titled “Below-Threshold Transfers”When the amount is below the Travel Rule threshold of the originator's and the beneficiary's jurisdictions, POST /api/v2/transfers completes the transfer at once and answers 201, with compliance: "approved", routing: "skipped" and the thresholdInfo it was checked against. No provider exchange takes place. Read back, the transfer has:
| Field | Value |
|---|---|
state |
completed |
beneficiary.vaspId |
not_required |
status.ours |
accepted |
compliance.status |
approved |
Rejection Reasons
Section titled “Rejection Reasons”Rejecting a transfer accepts these reason values:
| Reason | Meaning |
|---|---|
BENE_NOT_FOUND |
Beneficiary could not be found. |
BENE_NAME_MISMATCH |
Beneficiary identity did not match expected data. |
SANCTIONS_MATCH |
Sanctions screening produced a match. |
HIGH_RISK |
Risk score or policy threshold was too high. |
COMPLIANCE_POLICY |
Internal compliance policy rejected the transfer. |
INVALID_DATA |
Required transfer or IVMS data was invalid. |
EXPIRED |
Transfer or protocol workflow expired. |
OTHER |
Rejection did not fit a predefined reason. |
A reject request through the API carries both action and status:
{ "action": "reject", "status": "rejected", "reason": "COMPLIANCE_POLICY", "details": "Internal policy decision"}