Skip to content

Quickstart

This walk-through creates a customer, gives it an attested identity, registers its wallet, sends an outgoing transfer and follows it. Use a test key: everything it creates stays in the test environment.

In the dashboard, open Developers, API keys, and create a key for the test environment with the customers:write, wallets:write, transfers:read and transfers:write scopes. The key is shown once: store it as a secret.

Terminal window
export COVALENT_URL="https://<company>.<app-domain>"
export COVALENT_API_KEY="covalence_pk_..."

COVALENT_URL is your company's host, the address your dashboard opens at. Send the key in the x-api-key header of every request; it decides the environment of the request.

Terminal window
curl -X POST "$COVALENT_URL/api/v2/customers" \
-H "x-api-key: $COVALENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"externalId": "cust_123",
"name": "Jane Doe",
"metadata": {
"segment": "retail"
}
}'

The answer is 201 with the customer, including its ID and Veriscope public key:

{
"data": {
"id": "customer_id",
"externalId": "cust_123",
"name": "Jane Doe",
"publicKey": "02989c0b76cb563971fdc9bef31ec06c3560f3249d6ee9e5d83c57625596e05f6f",
"environment": "test",
"createdAt": "2026-10-09T12:00:00.000Z"
},
"meta": {
"apiVersion": 2,
"timestamp": "2026-10-09T12:00:00.000Z"
}
}

3. Set the Customer's Travel Rule Identity

Section titled “3. Set the Customer's Travel Rule Identity”

Providers send a customer's attested identity to counterparties, and never its display name. Store the IVMS101 data your KYC process verified:

Terminal window
curl -X PUT "$COVALENT_URL/api/v2/customers/customer_id/travel-rule-identity" \
-H "x-api-key: $COVALENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "verified",
"persons": [
{
"naturalPerson": {
"name": {
"nameIdentifier": [
{
"primaryIdentifier": "Doe",
"secondaryIdentifier": "Jane",
"nameIdentifierType": "LEGL"
}
]
},
"countryOfResidence": "US"
}
}
]
}'

The answer is { "id": "customer_id", "status": "verified" }. See Travel Rule Identity.

Terminal window
curl -X POST "$COVALENT_URL/api/v2/wallets" \
-H "x-api-key: $COVALENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"network": "ethereum",
"customerId": "customer_id",
"label": "Main wallet"
}'

The answer is 201 with the wallet. The customer must be in the same environment (404 CUSTOMER_NOT_FOUND otherwise) and not deactivated.

Send an Idempotency-Key with every create, so that a retry never creates a second transfer.

Terminal window
curl -X POST "$COVALENT_URL/api/v2/transfers" \
-H "x-api-key: $COVALENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 8c6c1d0e-7f43-4c55-9a51-4f2c3b1e2a90" \
-d '{
"asset": "ETH",
"amount": "1.25",
"network": "ethereum",
"originatorCustomerId": "customer_id",
"originatorAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"beneficiaryAddress": "0x1111111111111111111111111111111111111111",
"originator": {
"originatorPersons": [
{
"naturalPerson": {
"name": {
"nameIdentifier": [
{
"primaryIdentifier": "Doe",
"secondaryIdentifier": "Jane",
"nameIdentifierType": "LEGL"
}
]
},
"geographicAddress": [
{
"addressType": "HOME",
"country": "US"
}
]
}
}
]
},
"isUnhostedWallet": false
}'
Status Meaning
200 The Idempotency-Key was used before: the transfer it created, with meta.idempotent: true.
201 Below the Travel Rule threshold: the transfer is completed at once.
202 The transfer is queued for screening and the provider exchange.
400 VALIDATION_ERROR: error says what to fix.
503 TIMEOUT: retry after Retry-After, with the same Idempotency-Key.
Terminal window
curl "$COVALENT_URL/api/v2/transfers/transfer_id" \
-H "x-api-key: $COVALENT_API_KEY"

The answer has the transfer's lifecycle state, each side's status, its compliance checks, its provider attempts and messages, and its timestamps. See Get Transfer.

Instead of polling, create a webhook subscription: in the dashboard under Developers, Webhooks, or with POST /api/v2/webhooks and a key with webhooks:write. Covalent delivers signed JSON events to it:

X-Webhook-Signature: t=1760000000,alg=hmac-sha256,sig=<hex_hmac>
X-Webhook-Event: transfer.created
X-Webhook-Delivery-Id: delivery_id

Verify the signature against the exact raw request body. See Webhooks.