Skip to content

April 1, 2026

Automating utility bill address verification for crypto exchanges: a step-by-step integration guide

Crypto exchanges face a tough balancing act. Regulators require proof of address verification as part of KYC onboarding, but users expect account creation to take minutes, not days. Manual document review creates bottlenecks, increases operational costs, and frustrates users who just want to start trading.

This guide walks through how to automate utility bill address verification end to end, from regulatory context to working API integration, so your compliance team can focus on edge cases instead of reading electricity bills.

Why crypto exchanges need proof of address

Most jurisdictions now require crypto exchanges to perform customer due diligence (CDD) that includes verifying a user's residential address. This isn't optional:

Failing to verify addresses can result in regulatory fines, license revocation, or losing banking relationships. But doing it manually doesn't scale.

The problem with manual utility bill review

Here's what manual verification typically looks like at a crypto exchange:

  1. User uploads a utility bill during onboarding
  2. A compliance analyst opens the document
  3. They manually read the name, address, and date
  4. They compare it against the name and address the user entered during registration
  5. They make a judgment call: does "J. Smith" match "John Smith"? Does "Apt 4B" match "Apartment 4B"?
  6. They record the decision and move to the next document

This process has several problems:

What to automate

An automated utility bill verification system needs to handle four checks:

  1. Document type: is this actually a utility bill (or bank statement, government letter, etc.) and not a screenshot of a website or a random PDF?
  2. Name match: does the name on the document match the user's registered name?
  3. Address match: does the address on the document match the user's declared address?
  4. Date check: was the document issued within the accepted window (typically 3–6 months)?

Each check should produce a score, not just a binary yes/no, so you can set thresholds that match your risk appetite.

Step 1: Set up your API key

Sign up at app.trusqo.com and generate an API key from your dashboard. You'll use this key in the X-API-Key header for all requests.

Step 2: Submit a verification request

When a user uploads a utility bill during onboarding, send it to the verification endpoint along with the expected name and address:

curl -X POST https://app.trusqo.com/api/verify \
  -H "X-API-Key: YOUR_API_KEY" \
  -F "name=Satoshi Nakamoto" \
  -F "address=2-1 Nagatacho, Chiyoda-ku, Tokyo 100-8968" \
  -F "files=@electricity-bill.pdf"

The API accepts PDF, JPG, and PNG files. You can also submit multiple files in a single request if your user uploads several pages.

The response includes a request ID:

{
  "id": "req_abc123",
  "status": "processing"
}

Step 3: Get the result

Poll for the result or configure a webhook to receive it automatically:

curl https://app.trusqo.com/api/verify/req_abc123 \
  -H "X-API-Key: YOUR_API_KEY"

The response contains match scores and verdicts for every check:

{
  "status": "approved",
  "extractedName": "Satoshi Nakamoto",
  "nameMatchScore": 0.98,
  "nameMatchResult": "pass",
  "extractedAddress": "2-1 Nagatacho, Chiyoda-ku, Tokyo 100-8968",
  "addressMatchScore": 0.95,
  "addressMatchResult": "pass",
  "extractedDocType": "utility-bill",
  "docTypeResult": "pass",
  "extractedDateOfIssue": "2026-02-10",
  "dateResult": "pass"
}

Step 4: Handle the verdict in your onboarding flow

Map the API response to your onboarding states:

A typical integration looks like this in your backend:

// After receiving the verification result
if (result.status === "approved") {
  await activateAccount(userId);
} else if (result.status === "declined") {
  await requestReupload(userId, result);
} else {
  await flagForManualReview(userId, result);
}

Step 5: Configure thresholds for your risk appetite

Every exchange has a different tolerance for fuzzy matches. A name score of 0.85 might be acceptable for a retail exchange but too low for an institutional platform. You can configure thresholds for:

Step 6: Set up webhooks for real-time updates

Instead of polling, configure a webhook endpoint to receive results as soon as they're ready:

curl -X POST https://app.trusqo.com/api/webhooks \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-exchange.com/webhooks/poa-verified"}'

Your webhook endpoint receives the full verification result, so you can update the user's onboarding status in real time without polling delays.

Handling multi-language documents

Crypto exchanges serve users globally, which means utility bills in dozens of languages and scripts. A user in Bulgaria submits an electricity bill in Cyrillic. A user in Japan submits a gas bill in Japanese. A user in the UAE submits a DEWA bill in Arabic.

trusqo handles this automatically. Non-Latin text is transliterated so it can be matched against the Latin-script name and address your user entered during registration. You don't need to build language-specific logic or maintain translation tables.

Audit trail and compliance reporting

Every verification produces a downloadable PDF audit report that includes:

This gives your compliance team a defensible record for regulatory audits. No more "the analyst thought it looked close enough."

What this looks like in production

Here's the end-to-end flow once integrated:

  1. User signs up and enters their name and address
  2. User uploads a utility bill (or bank statement, government letter, etc.)
  3. Your backend sends the document and expected data to the trusqo API
  4. Within seconds, a webhook delivers the result
  5. If approved, the account activates automatically
  6. If declined, the user is prompted to upload a different document
  7. If borderline, a compliance analyst reviews the flagged case with full context

Most verifications complete in under 10 seconds. For exchanges processing thousands of sign-ups daily, this eliminates the manual bottleneck entirely.

Getting started

Sign up at app.trusqo.com and get an API key. Plans start at €25/month with 50 checks included. Full API documentation is at trusqo.com/docs.