Skip to content

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.

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.

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.

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 -> completed

Important outgoing behavior:

  • queued means the API call succeeded and the worker owns the next step.
  • exchanging means the provider/protocol has enough data to contact the beneficiary side and exchange IVMS.
  • awaiting_counterparty means Covalent is waiting for the peer/provider accept or reject decision.
  • completed usually 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.

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 -> completed

Important 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.

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.

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 = held
complianceStatus = pending

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

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"
}