Skip to content

API Integration

Build custom self-hosted verification flows with the REST API

The Wallet Verification Widget is the fastest way to go live, but you can also integrate directly via the API. Use the API when you want to build your own UI, support native mobile flows, or control each verification step from your backend.

Direct API integration follows the same pattern for every verification method:

  1. Create a wallet verification request.
  2. Submit proof of ownership for the selected flow.
  3. Read the updated status from the API or your webhook notification.

1. Create a Verification

Create the wallet verification before collecting proof from the wallet owner.

curl --location 'https://api-dev.cryptoswift.eu/wallet-verification' \
--header 'x-api-key: $API_KEY' \
--header 'Content-Type: application/json' \
--data '{
  "asset": "ETH",
  "blockchain": "Ethereum",
  "address": "0x32Be343B94f860124dC4fEe278FDCBD38C102D88",
  "metadata": "customer-123",
  "allowedFlows": ["SIGNATURE_PROOF", "VISUAL_PROOF", "SELF_DECLARED"],
  "origin": "https://app.example.com"
}'
Always double-check you are using the correct environment when integrating. Using the wrong base URL or API key will result in authentication errors.

Mandatory fields:

  • asset: The virtual asset, for example ETH or BTC
  • blockchain: The blockchain name or supported EVM chain ID
  • address: Self-hosted wallet address to verify

Optional fields:

  • metadata: Your own wallet, user, or case reference
  • allowedFlows: Restrict which proof methods can be used
  • origin: Required when validating browser-origin-bound signature messages
  • satoshiFlow: Required when you allow SATOSHI_TEST; include depositAddress and optional amount
  • reuse: Reusable verification matching input and policy

Example response:

{
  "id": "9f3dc458-a2be-4a34-bcb7-f1f677a0864c",
  "token": "97857f6c-396a-4d68-a1bf-563bfb76c5b6",
  "url": "https://wallet-dev.cryptoswift.eu/?token=97857f6c-396a-4d68-a1bf-563bfb76c5b6",
  "asset": "ETH",
  "blockchain": "Ethereum",
  "address": "0x32Be343B94f860124dC4fEe278FDCBD38C102D88",
  "metadata": "customer-123",
  "status": "PENDING",
  "flow": null,
  "allowedFlows": ["SIGNATURE_PROOF", "VISUAL_PROOF", "SELF_DECLARED"],
  "reuse": null,
  "createdAt": "2026-05-15T09:00:00.000Z"
}

Use id for all later status checks, proof submissions, manual updates, and webhook reconciliation.

Reusable Verification

Reusable verification can automatically complete a new verification by matching it with a previous eligible verified wallet verification for the same address and blockchain. Reuse matching is cross-tenant.

For a full explanation of matching policies, flow, and storage, see Reusable Wallet Verification.

curl --location 'https://api-dev.cryptoswift.eu/wallet-verification' \
--header 'x-api-key: $API_KEY' \
--header 'Content-Type: application/json' \
--data '{
  "asset": "ETH",
  "blockchain": "Ethereum",
  "address": "0x32Be343B94f860124dC4fEe278FDCBD38C102D88",
  "allowedFlows": ["SIGNATURE_PROOF"],
  "reuse": {
    "subject": {
      "type": "NATURAL",
      "nameHash": "6f1c9d3d5c2f7b1e8a4f7c9b0d3a1e5f6c8b9a0d2e4f6a8b0c1d3e5f7a9b1c3"
    },
    "policy": {
      "minimumMatchLevel": "MEDIUM",
      "maxReuseAgeDays": 180
    }
  }
}'

nameHash is required for reusable verification. Hash the owner's full name after NFKC normalization, trimming, lowercasing, and collapsing repeated whitespace to one space. Send the lowercase 64-character SHA-256 hex digest, not the plain-text name.

Matching levels:

  • LOW: Address, blockchain, and subject type match
  • MEDIUM: Address, blockchain, and name hash match
  • HIGH: Address, blockchain, subject type, and name hash match

If a reusable match is found, the response has status: "VERIFIED" and reuse contains the applied match level, matched attributes, and policy. If no match is found, the response remains PENDING and you continue with proof submission.

2. Submit Proof of Ownership

Submit proof to the existing verification:

POST {{apiBaseUrl}}/wallet-verification/{id}/verification

The request body always includes verificationFlow. The rest of the payload depends on the selected flow.

Cryptographic Signature Proof

Cryptographic signature proofs verify that the user controls the wallet by signing an off-chain message with the wallet's private key.

CryptoSwift advocates open-source, industry-standard solutions for signature proofs. WalletConnect (now Reown) is the most robust option, with broad wallet compatibility. It supports 450+ wallets across networks like Bitcoin, Ethereum, Solana, Optimism, Arbitrum, Base, Polygon, BNB, Avalanche, and Cosmos. See the full list here.

Visit Reown or explore the Reown docs to get started. Also see the web-based Wallet Connect demo.

Once the user signs the message, submit the proof:

curl --location 'https://api-dev.cryptoswift.eu/wallet-verification/9f3dc458-a2be-4a34-bcb7-f1f677a0864c/verification' \
--header 'x-api-key: $API_KEY' \
--header 'Content-Type: application/json' \
--data '{
  "verificationFlow": "SIGNATURE_PROOF",
  "message": "app.example.com wants you to sign in with your blockchain account:\n0x32Be343B94f860124dC4fEe278FDCBD38C102D88\n\nURI:https://app.example.com/\nVersion: 1\nChain ID: eip155:1\nNonce: 1961\nIssued At: 2026-05-15T09:00:00Z",
  "signature": "q7XUz9XJbWjK9YO2iA8eW3OmEDCuqKDG12tzmPVNlDb9X6G6MxwGqv8J8B4gEZq43vU3D9VaGRKqB1wnyCrR7A="
}'

Mandatory fields:

  • verificationFlow: SIGNATURE_PROOF
  • message: The exact message signed by the wallet owner
  • signature: The cryptographic signature of the message

The request returns the updated verification. A successful signature proof sets status to VERIFIED.

Micro Transactions

A Satoshi Test verifies ownership by asking the wallet owner to send a specific amount of native asset from the self-hosted wallet to your deposit address.

Please ensure you set up a webhook before initiating a Satoshi Test verification.

Create the verification with SATOSHI_TEST allowed and provide satoshiFlow.depositAddress.

curl --location 'https://api-dev.cryptoswift.eu/wallet-verification' \
--header 'x-api-key: $API_KEY' \
--header 'Content-Type: application/json' \
--data '{
  "asset": "BTC",
  "blockchain": "Bitcoin",
  "address": "BsRdeZ75szhDiGN8hJs8v8PcqwBm7KsFcp",
  "metadata": "customer-123",
  "allowedFlows": ["SATOSHI_TEST"],
  "satoshiFlow": {
    "depositAddress": "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080"
  }
}'

If satoshiFlow.amount is omitted, CryptoSwift generates a random amount. Share the returned satoshiFlow.depositAddress, asset, and satoshiFlow.amount with the wallet owner.

Then start transaction monitoring:

curl --location 'https://api-dev.cryptoswift.eu/wallet-verification/9f3dc458-a2be-4a34-bcb7-f1f677a0864c/verification' \
--header 'x-api-key: $API_KEY' \
--header 'Content-Type: application/json' \
--data '{
  "verificationFlow": "SATOSHI_TEST"
}'

The verification stays PENDING until CryptoSwift detects a matching transaction. Satoshi Test verification expires 48 hours after createdAt.

Visual Proof

Visual Proof test let a user upload visual proof of wallet ownership for manual review.

curl --location 'https://api-dev.cryptoswift.eu/wallet-verification/9f3dc458-a2be-4a34-bcb7-f1f677a0864c/verification' \
--header 'x-api-key: $API_KEY' \
--form 'verificationFlow="VISUAL_PROOF"' \
--form 'files=@"../wallet-screenshot.png"'

Mandatory fields:

  • verificationFlow: VISUAL_PROOF
  • files: Up to 3 files

File limits:

  • Images and PDFs: jpeg, jpg, png, or pdf, max 5MB each
  • Videos: mp4, webm, mov, avi, wmv, mkv, mpeg, m4v, or 3gp, max 50MB each

Visual proof sets status to ACTION_REQUIRED. Review the uploaded proof and manually update the verification to VERIFIED or DECLINED.

Self-Declaration

Self-declaration lets the user declare wallet ownership without an on-chain transaction, screenshot, or signature.

curl --location 'https://api-dev.cryptoswift.eu/wallet-verification/9f3dc458-a2be-4a34-bcb7-f1f677a0864c/verification' \
--header 'x-api-key: $API_KEY' \
--header 'Content-Type: application/json' \
--data '{
  "verificationFlow": "SELF_DECLARED"
}'

Self-declaration sets status to VERIFIED.

3. Receive Notification via Webhook

Webhook header: X-Event-Type: 'wallet-verification'

Example success payload:

{
  "id": "9f3dc458-a2be-4a34-bcb7-f1f677a0864c",
  "status": "VERIFIED",
  "flow": "SIGNATURE_PROOF",
  "verifiedTransactionHash": null
}

Use the webhook event as a trigger, then retrieve the current verification by ID before making compliance decisions.

curl --location 'https://api-dev.cryptoswift.eu/wallet-verification/9f3dc458-a2be-4a34-bcb7-f1f677a0864c' \
--header 'x-api-key: $API_KEY'

4. Manual Updates

For manual review flows, update the verification after your compliance team makes a decision.

curl --location --request PATCH 'https://api-dev.cryptoswift.eu/wallet-verification/9f3dc458-a2be-4a34-bcb7-f1f677a0864c' \
--header 'x-api-key: $API_KEY' \
--header 'Content-Type: application/json' \
--data '{
  "status": "VERIFIED",
  "statusReasoning": "Manual approval",
  "metadata": "case-456"
}'

Supported statuses:

  • PENDING: Verification has been created and is waiting for proof or completion
  • VERIFIED: Ownership is verified
  • ACTION_REQUIRED: Manual VASP action is required
  • DECLINED: Manual review rejected the proof
  • FAILED: Automated verification failed
  • DELETED: Verification was deleted

Next steps