Sygna Bridge
Sygna Bridge is one of Covalent's Travel Rule providers. VASPs registered with Sygna exchange signed, encrypted IVMS101 data through its Bridge API, version 2.
On this platform Sygna Bridge sends transfers to the beneficiary VASPs its search finds, receives transfers from originator VASPs, answers address checks for your wallets, and exchanges information requests on the transfers it carries.
Provider Config
Section titled “Provider Config”| Field | Value |
|---|---|
| Name | sygna |
| Display name | Sygna Bridge |
| Protocol | sygna |
| Active | true |
| Discovery | Signed address validation against registered Sygna VASPs |
| Transport | HTTPS, secp256k1 signatures and ECIES encryption |
The test environment calls https://test-api.sygna.io/v2, and the live environment https://api.sygna.io/v2, each with its own credentials. A request to Sygna Bridge follows no redirect and times out after 15 seconds.
Credentials
Section titled “Credentials”Save the credentials for each environment with PUT /api/v2/providers/sygna, or in the dashboard: a test key saves the test credentials, and a live key the live ones. Enabling is one switch for both environments, and takes a live key. See Providers and Integrations.
| Field | Required | Description |
|---|---|---|
apiKey |
Yes | Secret. Your Sygna API key, sent as x-api-key with every request. |
vaspCode |
Yes | Your registered Sygna VASP code: 8 to 64 letters, digits, _ or -. |
privateKey |
Yes | Secret. Your secp256k1 private key, 64 hexadecimal characters. It signs what you send and decrypts what you receive. The Sygna directory must list its public key for your vaspCode. |
bridgePublicKey |
Yes | Sygna Bridge's verification key for the environment: 130 hexadecimal characters starting with 04. |
callbackBaseUrl |
Yes | Your company's host as an HTTPS origin, such as https://covalent.example.com: no path, query, fragment or credentials. |
discoveryVaspCodes |
No | The VASP codes discovery may ask, separated by commas or spaces: at most 500. *, or no value, means the whole directory. |
curl -X PUT "$COVALENT_URL/api/v2/providers/sygna" \ -H "x-api-key: $COVALENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "credentials": { "apiKey": "...", "vaspCode": "...", "privateKey": "...", "bridgePublicKey": "04...", "callbackBaseUrl": "https://covalent.example.com", "discoveryVaspCodes": "*" } }'A value that is not valid is 422 INVALID_FIELDS, with the fields in details.fields. An empty value keeps the saved one: to search the whole directory again after saving a list, save *.
Callbacks
Section titled “Callbacks”Sygna Bridge calls your company's host on one path for each event:
POST /api/system/trp/sygna/<environment>/<providerId>/<event>Once the provider is saved, callbackPaths lists the paths for permission-request, address-validation, txid, cancel and cdd, in the key's environment. Register them with Sygna, under the origin you save as callbackBaseUrl: Covalent does not register them. permission, for decisions on transfers you send, is not listed: its URL goes, with a token for the transfer, in each permission request Covalent sends. <environment> is test or live: an event is checked with that environment's credentials, and its transfer belongs to that environment.
| Event | What arrives | Signature checked with |
|---|---|---|
permission-request |
An originator VASP's transfer to your customer | The originator VASP's key in the signed Sygna directory |
address-validation |
A question: are these addresses your customers' wallets? | bridgePublicKey |
txid |
The originator's transaction ID for an incoming transfer | The originator VASP's key, kept with the transfer |
cancel |
The originator's cancellation of an incoming transfer | The originator VASP's key, kept with the transfer |
cdd |
An information request, an answer, or information sent unasked | The counterparty's key, kept with the transfer |
permission |
The beneficiary VASP's decision on a transfer you sent | The beneficiary VASP's key, kept with the transfer |
Every event but address-validation is also checked against the transfer's status, which Covalent reads from Sygna Bridge, signed with bridgePublicKey. Covalent answers address-validation with a response signed with your privateKey: is_valid is true only when every address asked about is a verified wallet, on the currency's network, of an active customer with a verified Travel Rule identity.
A repeated event gets the same answer and changes nothing: a repeated permission-request creates no second transfer, and a repeated cdd message is recorded once. A different permission-request for a Sygna transfer ID already received is refused (INCOMING_REPLAY_MISMATCH).
| Status | Body | When |
|---|---|---|
200 |
{ "status": "OK" }, or the signed address answer |
The event is accepted, or repeated |
400 |
{ "error": "Invalid callback" } |
The body is not JSON, or not the event's shape |
400 |
{ "error": "<code>" } |
The event does not fit its transfer, such as UNSUPPORTED_TRANSFER or TXID_BINDING_MISMATCH |
401 |
{ "error": "INVALID_SIGNATURE" } |
The event's signature does not verify |
404 |
{ "error": "UNKNOWN_TRANSFER" } |
No transfer has that Sygna transfer ID, for this provider and environment |
413 |
{ "error": "Body too large" } |
The body is over 2 MiB |
| Sygna Bridge's | { "error": "HTTP_<status>" } |
Sygna Bridge refused a request Covalent made to check the event |
503 |
{ "error": "Provider unavailable" } |
The provider ID is unknown or disabled, or has no credentials for the environment |
503 |
{ "error": "<code>" } |
Any other failure |
Another event is 404 { "error": "Not found", "code": "NOT_FOUND" }. An accepted callback counts toward your company's rate limit; over it, a callback is 429 RATE_LIMITED.
Outgoing Transfers
Section titled “Outgoing Transfers”Callers do not call Sygna Bridge directly: they create transfers with POST /api/v2/transfers (see Transfers). Sygna Bridge can carry a transfer that has an originatorAddress and a beneficiary with at least one person.
"preferredProtocol": "sygna" is refused with 400 VALIDATION_ERROR unless Sygna Bridge is enabled, has credentials for the key's environment, and can carry the transfer. Covalent then tries Sygna Bridge first, unless the beneficiary VASP was last reached through another provider. Another enabled provider may still carry the transfer: when Sygna's search finds no VASP (vasp_not_found in cascade.attempts), or when Sygna's attempt fails before Covalent reserves the Sygna request (error, with the reason, such as Sygna operation failed (VERIFIED_ORIGINATOR_REQUIRED)). Covalent reserves the request once every check below has passed, just before it sends it. From then on no other provider carries the transfer: a failure, such as Sygna Bridge refusing the request or not answering it, leaves the attempt submission_unknown and the transfer failed, and a retry does not send it again.
- Covalent screens the transfer, then runs VASP discovery.
- It checks, in this order:
- the transfer is outgoing, with an
originatorAddress(INVALID_OUTGOING_TRANSFER); - its asset is found on Sygna Bridge for its network, as in a search;
- the beneficiary VASP is in the Sygna VASP directory, read again as in a search, and is not you (
UNKNOWN_PEER); whendiscoveryVaspCodesis saved, it is one of them (PEER_NOT_ALLOWLISTED); - the beneficiary VASP confirms again, signed with its key from the directory, that it owns the beneficiary address and any memo (
ADDRESS_NOT_OWNED); - the originator customer has a verified Travel Rule identity (
VERIFIED_ORIGINATOR_REQUIRED); - the
beneficiaryhas at most 20 persons: one natural person, or a legal person followed only by natural persons (BENEFICIARY_IDENTITY_REQUIRED); - your company profile is complete (the error names what is missing);
- the transfer's
expiresAtis at least three minutes away (TRANSFER_EXPIRY_TOO_SOON). Covalent sets it 24 hours after the transfer is created; a transfer without one is refused.
- the transfer is outgoing, with an
- It builds the permission request, signs it with your
privateKey, and reserves it for the transfer. The request carries:- the IVMS101 data, encrypted for the beneficiary VASP's key from the directory: your customer's verified Travel Rule identity as originator, with the
originatorAddress; the request'sbeneficiarypersons, with the beneficiary address; your company profile as originating VASP. The request'soriginatoris not sent. - the transaction: your
vaspCodeand theoriginatorAddress; the beneficiary VASP's code and the beneficiary address, with any destination memo; the amount, with Sygna's currency and platform for the asset. - its date (
data_dt) and the transfer's expiry (expire_date), withneed_validate_addr: trueandforced_sending_when_VASP_is_not_healthy: false. - beside it, signed too, the
permissioncallback URL, with the transfer's ID and a token.
- the IVMS101 data, encrypted for the beneficiary VASP's key from the directory: your customer's verified Travel Rule identity as originator, with the
- It sends the request (
POST /bridge/transaction/permission-request). Sygna Bridge's answer, its transfer ID, is unsigned: Covalent takes it only once Sygna Bridge's signed status for that transfer matches the request. - The transfer moves to
exchanging. Its Sygna attempt issent, itscascade.externalIdis Sygna's transfer ID, 64 hexadecimal characters, and it names the beneficiary VASP by its Sygna VASP code.
Decision
Section titled “Decision”The beneficiary VASP's decision arrives on the permission callback, signed with its key from the directory. Covalent keeps it only when its signature and decision are those in Sygna Bridge's status for the transfer (400 PERMISSION_BINDING_MISMATCH otherwise). A decision that arrives before Sygna Bridge has answered the permission request finds its transfer by the ID and token in the callback URL.
Covalent reads the transfer's status from Sygna Bridge after each permission it accepts, after an information review, and once a minute while the transfer has been exchanging or awaiting_counterparty for five minutes without an update. A Sygna transfer is never failed for silence.
| Sygna Bridge's status | Transfer |
|---|---|
| No decision yet | No change. |
REJECTED or CANCELED |
rejected, with status.theirs rejected. |
ACCEPTED, before Covalent has received the permission |
Covalent asks Sygna Bridge to send its failed callbacks again (POST /bridge/transaction/retry); the transfer does not change. |
ACCEPTED, with the permission received |
Covalent screens each beneficiary person you sent at the postcheck checkpoint of your rules. Approved: status.ours and status.theirs are accepted, and the transfer moves to awaiting_counterparty. Pending: it is held for review (compliance pending); on a transfer already held, an approval only keeps it held for review. Rejected: Covalent cancels the transfer on Sygna Bridge (POST /bridge/transaction/cancel, signed with your key), and it is rejected. |
A transfer still open at its expiry is held (compliance pending), and its transaction can no longer be reported. An information request from the beneficiary VASP holds the transfer too: see Information Requests.
Once Sygna Bridge carries the transfer, a hold takes no accept, reject or retry on PATCH /api/v2/transfers/:id (400 INVALID_REQUEST). Resolving a case linked to the transfer as approved returns it to awaiting_counterparty, compliance approved, unless information awaits review; a case resolved as rejected leaves it held.
Transaction Report
Section titled “Transaction Report”To complete the transfer, report its blockchain transaction: PATCH /api/v2/transfers/:id with action accept and the txHash (see Accept). The transfer must be awaiting_counterparty or accepted, with status.theirs accepted and compliance approved. Covalent then checks that Sygna Bridge's status is still ACCEPTED, with the decision Covalent received, signed with the beneficiary VASP's key; that no information awaits review; and, for a first report, that neither the transfer's expiry nor one in the decision has passed. When Covalent or Sygna Bridge refuses the report, or Sygna Bridge cannot be reached, it answers 400 INVALID_REQUEST, with an error such as Sygna operation failed (APPROVAL_REQUIRED) or Sygna operation failed (PERMISSION_REQUIRED), and the transfer keeps its state.
Covalent signs the report, Sygna's transfer ID and the txHash as given, with your key, sends it to Sygna Bridge (POST /bridge/transaction/txid), and only then completes the transfer: accepted, then completed, with the txHash. Covalent keeps a report once it is signed: trying again sends the same one, and a different txHash is refused (TXID_CONFLICT), as is a report when Sygna Bridge already has another.
VASP Discovery
Section titled “VASP Discovery”While Sygna Bridge is enabled and has credentials for the environment, Covalent searches it for the beneficiary VASP of the outgoing transfers it routes, beside the other providers' searches, whichever provider then carries the transfer. Sygna Bridge sends a transfer only to the VASP its own search found. A search:
- Finds the transfer's asset on Sygna Bridge for its network: exactly one currency must match.
- Reads the Sygna VASP directory. It must be signed with
bridgePublicKey, dated within five minutes, and list yourvaspCodewith your private key's public key. - Takes as candidates the other VASPs in the directory, or only those in
discoveryVaspCodes, each of which must be in it. Without a list, more than 500 candidates fail the search (DISCOVERY_ALLOWLIST_REQUIRED). - Asks Sygna Bridge, eight candidates at a time for up to 20 seconds, whether each owns the beneficiary address, sending the address, the currency and any destination memo, signed with your key. An answer counts only when it is signed with the candidate's key from the directory and names the same VASP and address.
- Takes the one VASP that confirms the address as the beneficiary VASP. When none does, the search found no VASP. When two do, the search fails (
DISCOVERY_AMBIGUOUS).
A candidate that does not answer, or answers with an error, is asked again when the transfer job next runs, at least 11 seconds later. The search is retried the same way when Sygna Bridge does not answer the currency or directory read, or answers it with 429 or 5xx. A search still open after five minutes fails. A failed search stops routing, whichever provider would carry the transfer: no provider is tried, and the transfer fails. That includes an asset Sygna Bridge does not list for the network, any other HTTP error from Sygna Bridge, and a candidate's answer that is malformed or fails verification.
Incoming Transfers
Section titled “Incoming Transfers”- On
permission-request, Covalent decrypts the IVMS101 data with yourprivateKey, and creates an incoming transfer inexchanging(transfer.created). ItsexternalIdis Sygna's transfer ID, 64 hexadecimal characters, and it names the originator VASP by its Sygna VASP code. A request with more than one address on either side, or with extra information on the originator's address, is400 UNSUPPORTED_TRANSFER. The expiry is the request's, else Sygna Bridge's, else 30 days after the request's date; a request dated over five minutes ahead, or already expired, is400 TRANSFER_EXPIRED. - Covalent reads the transfer from Sygna Bridge again after each
permission-request,txidorcancelit accepts, after an information review, and once a minute while the transfer has beenexchangingorawaiting_counterpartyfor five minutes without an update. A Sygna transfer is never failed for silence. - The beneficiary address must be a verified wallet, on the transfer's network, of an active customer with a verified Travel Rule identity. The beneficiary persons the originator sent must match that identity's persons, by type and name, ignoring case, spaces and punctuation; a single legal person is matched with the identity's first person. Otherwise Covalent rejects the transfer on Sygna Bridge, with reject code
BVRC002for a name mismatch andBVRC001for anything else, and the transfer isrejected. - Covalent screens each of the originator's persons at the
postcheckcheckpoint of your rules. Approved: Covalent accepts the transfer on Sygna Bridge, and it moves toawaiting_counterparty. Pending: it isheldfor review. Rejected: Covalent rejects it on Sygna Bridge withBVRC999, and it isrejected. - The originator's
txidcompletes a transfer Covalent accepted: it moves toaccepted, thencompleted, with the transaction ID as itstxHash. Acancel, or a rejection or cancellation in Sygna Bridge's status, makes itrejected. A transfer still open at its expiry isheld, and can no longer be accepted.
The acceptance carries no beneficiary data: Covalent uses your customer's identity to check the names it received, and does not send it.
Accept and Reject
Section titled “Accept and Reject”An incoming Sygna transfer held for review (state: held, compliance pending) takes accept or reject on PATCH /api/v2/transfers/:id. Covalent sends the decision to Sygna Bridge first, signed with your key, and changes the transfer only once Sygna Bridge has it:
| Action | Sent to Sygna Bridge | Then |
|---|---|---|
accept |
An acceptance, with the transfer's expiry | awaiting_counterparty, compliance approved |
reject |
A rejection, with reject code BVRC999 and the message Transfer declined by receiving VASP compliance policy |
rejected |
Your reason and details stay with the transfer: they are not sent. accept is refused while information is pending review (CDD_REVIEW_REQUIRED), once the transfer has expired or been cancelled, when the beneficiary's wallet or identity no longer checks out, and when the transfer no longer matches what was screened (LOCAL_APPROVAL_REQUIRED). reject is available while information is pending review.
When Covalent or Sygna Bridge refuses the decision, or Sygna Bridge cannot be reached, the action answers 400 INVALID_REQUEST, with an error such as Sygna operation failed (CDD_REVIEW_REQUIRED), and the transfer keeps its state. Covalent keeps a decision once it is signed: trying again sends the same one, and the opposite decision is refused (DECISION_CONFLICT).
On an outgoing Sygna transfer, accept with a txHash reports its transaction: see Transaction Report.
Information Requests
Section titled “Information Requests”A transfer Sygna Bridge carries can exchange further customer due diligence (CDD) information with the counterparty, through GET and POST /api/v2/transfers/:id/information-requests; see Information Requests for the bodies. Any other transfer, or one whose Sygna Bridge provider is disabled, is 404 SYGNA_TRANSFER_NOT_FOUND.
Information goes one way: the beneficiary VASP asks, and the originator VASP answers or sends information unasked.
- On an incoming transfer you
request, and the originator VASP's answers (RESPOND_CDD) and unasked information (POST_CDD) arrive on thecddcallback, decrypted with yourprivateKey; a text answer reads as{ "additional_information": "<text>" }. - On an outgoing transfer the beneficiary VASP's requests (
REQUEST_CDD) arrive on thecddcallback, andGETshows each with adraftanswer from your customer's verified Travel Rule identity; Covalent sends only what you send. Youreplyto a request not yet reviewed, by its message ID asrequestId(404 CDD_REQUEST_NOT_FOUNDotherwise), once (409 CDD_REPLY_ALREADY_QUEUED), orpostinformation unasked. Covalent encrypts yourinformationfor the beneficiary VASP's key.
reply and post on an incoming transfer, request on an outgoing one, and a REQUEST_CDD received for an incoming transfer, or a RESPOND_CDD or POST_CDD for an outgoing one, are 400 CDD_DIRECTION_MISMATCH.
- A message received, or a
requestyou send, holds the transfer (held, compliancepending), setspending: trueand emitstransfer.held. The transfer cannot move on, be accepted or have its transaction reported until areview. - A
reviewmust list every unreviewed message, and needs every message you sent delivered and every request answered; otherwise it is409 CDD_REVIEW_CHANGED,CDD_DELIVERY_PENDINGorCDD_RESPONSE_REQUIRED. A transfer that was approved when the hold began returns toawaiting_counterparty, and Covalent screens the transfer again; any other staysheld. - A
request,replyorpostis signed with your key and sent in the background: itsstatusisqueued, thensent.retrysends one whose delivery failed again. A newrequestis refused until the last one is reviewed (409 CDD_REQUEST_ALREADY_OPEN), and must ask for something different (409 CDD_IDENTICAL_REQUEST_ALREADY_SENT), since a Sygna request carries no ID of its own. - An
idempotencyKeyused before returns its message; with other content, it is409 CDD_IDEMPOTENCY_CONFLICT. - Once the transfer is completed, rejected, cancelled, failed or expired, its transaction is reported, or Sygna Bridge reports it rejected or cancelled, every action is
409 CDD_TRANSFER_CLOSED. A message received once the transfer is completed, rejected, cancelled or failed, or its transaction is reported, is kept, and holds nothing.
GET reads what Covalent stored, without calling Sygna Bridge. Each POST first reads the transfer's status from Sygna Bridge: Sygna Bridge's own 400, 404 and 409 keep their status, and any other refusal is 503, with Sygna's status as the code, such as HTTP_401 or HTTP_502. Covalent's own refusals keep their 400, 404 or 409; a transfer busy with other work is 503 TRANSFER_BUSY: try again.
Connection Test
Section titled “Connection Test”POST /api/v2/providers/sygna/test checks the environment's saved credentials, and sends no transfer. It passes, with the message Connection successful, when the settings are valid, your company profile (Settings, Company profile) is complete, and Sygna Bridge's VASP directory answers: signed with bridgePublicKey, dated within five minutes, with each VASP code once, and listing your vaspCode with your private key's public key. A failed test answers success: false, with an error such as Sygna operation failed (LOCAL_KEY_MISMATCH). Without saved credentials for the environment, the test is 409 NOT_CONFIGURED.
Known Limitations
Section titled “Known Limitations”- A failed Sygna search stops the routing of an outgoing transfer, whichever provider would carry it: see VASP Discovery.
- Once Sygna Bridge carries an outgoing transfer, you cannot cancel or reject it: Covalent cancels it on Sygna Bridge only when its own screening of the beneficiary rejects it. A hold on it takes no
accept,rejectorretry: see Decision. - The beneficiary VASP's reject code and message are not shown: an outgoing transfer it rejects has
rejection: null. - A transfer has one originator address and one beneficiary address.
- A rejection sends
BVRC999,BVRC001orBVRC002, never yourreasonordetails; a cancellation sends no reason. - Without
discoveryVaspCodes, a directory of more than 500 other VASPs cannot be searched. - Covalent does not register your callback paths with Sygna.
- While Sygna Bridge is disabled, its callbacks answer
503, its open transfers are not read from Sygna Bridge again, their decisions and transaction reports are refused, and their information requests are404 SYGNA_TRANSFER_NOT_FOUND.