Skip to content

Wiremi Verify · Developers

One endpoint, one webhook.

Request a check, get a signed event when the subject answers, then pull the file. Sandbox keys are free and unlimited. Live accounts get twenty free soft checks a month.

Base URL
api.verify.wiremi.ca
Version
v1
Auth
Bearer key
Request
POST /v1/checks
Authorization: Bearer wv_live_••••
Idempotency-Key: 7c1d…

{
  "credit_id": "CC-9K10-3B85",
  "depth": "soft",
  "purpose": "lending_decision",
  "requester_region": "US-TX"
}
Response
201 Created

{
  "id": "chk_8Fk2",
  "object": "check",
  "status": "awaiting_consent",
  "depth": "soft",
  "purpose": "lending_decision",
  "expires_at": "2026-08-22T10:19:04Z"
}

Quickstart

Your first check, in your language.

Point the same call at the sandbox host with a sandbox key and it returns fixture files without waiting for a person. Swap the host and the key to go live. Nothing else changes.

Sandbox host
sandbox.verify.wiremi.ca
Sandbox keys
wv_test_…
Live keys
wv_live_…
Idempotency
Same key, same response, for 24 hours
Idempotency-Key header
curl https://api.verify.wiremi.ca/v1/checks \
  -H "Authorization: Bearer $WIREMI_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "credit_id": "CC-9K10-3B85",
    "depth": "soft",
    "purpose": "lending_decision",
    "requester_region": "CA-ON"
  }'

The flow

Three calls, and a wait for a human.

The wait is the product. Nothing is released until the file holder approves it in their Wiremi account, and that approval is the event you build against.

  1. 01

    POST /v1/checks

    Credit ID, depth, permitted purpose and your region. You get back a check id with status awaiting_consent.

  2. 02

    Wait for the webhook

    check.consented, check.declined or check.expired. Signed, and retried with backoff for 24 hours.

  3. 03

    GET the report

    Pull the scoped file. What comes back is exactly what the subject agreed to release, and nothing else.

  4. 04

    Access closes

    The scope expires after 30 days without you doing anything. Ask again and they approve again.

Reference

Eight endpoints. You will use three.

POST/v1/checks

Request a check. Returns awaiting_consent.

GET/v1/checks/{id}

Read a check and its status.

GET/v1/checks/{id}/report

Pull the scoped file once status is ready.

POST/v1/checks/{id}/cancel

Withdraw a request before the subject answers.

GET/v1/checks

List your checks, filterable by status and date.

GET/v1/checks/{id}/consent

The signed consent artefact, for your audit file.

POST/v1/webhooks

Register an endpoint and the events it receives.

POST/v1/keys/rotate

Issue a new key. The old one keeps working for 24 hours.

Every response carries a request id in X-Request-Id. Quote it when you write to us. Breaking changes ship as a new version path; v1 is supported for at least 24 months after v2 appears.

The report
GET /v1/checks/chk_8Fk2/report

200 OK
{
  "credit_id": "CC-9K10-3B85",
  "as_of": "2026-08-22",
  "score": 712,
  "tier": "trusted",
  "circles": {
    "completed": 3,
    "on_time_rate": 0.98,
    "current": 1
  },
  "consent": {
    "granted_at": "2026-08-22T10:07:12Z",
    "scope": ["score", "tier", "circles"],
    "expires_at": "2026-09-21T10:07:12Z"
  }
}

Scope and depth

You ask for a depth. They decide the scope.

A soft check can only ever carry the first three scopes and leaves no mark on the file. A full check may carry all six, and the subject can strip any of them before consenting. The report contains the scopes they granted, never the ones you asked for.

Soft
Score, tier, circles. No mark on the file.
$0.45
Full
All six scopes, subject to consent. Logged on the file.
$1.95
score

The Community Credit score, 0 to 1000, and the date it was computed.

tier

Anchor, Trusted, Building or Emerging, which sets the ceiling on a rate.

circles

Completed circles, on-time rate and the number currently running.

repayments

Circle Credit and facility repayments, on time and late, over 24 months.

obligations

Rent, utilities and instalments the subject has chosen to report.

history

Score trajectory by month, for the life of the file.

The webhook

The consent event is the contract.

Every event is signed with your endpoint secret, and the payload names the scope the subject agreed to. Keep it. It is the artefact that shows a regulator you had permission for exactly what you read.

Signature
HMAC-SHA256, timestamped
Tolerance
Reject older timestamps to defeat replay
Five minutes
Retries
Until your endpoint returns 2xx
Backoff, 24 hours
Events
consented · declined · expired · cancelled
Ordering
Use the event id and created time
Not guaranteed
Webhook
POST  your endpoint
X-Wiremi-Signature: t=1755857944,v1=5f2a…

{
  "id": "evt_Qm3c",
  "type": "check.consented",
  "created": "2026-08-22T10:07:12Z",
  "data": {
    "id": "chk_8Fk2",
    "status": "ready",
    "scope": ["score", "tier", "circles"],
    "report_url": "/v1/checks/chk_8Fk2/report"
  }
}
import { createHmac, timingSafeEqual } from 'node:crypto'

export function verifySignature(raw, header, secret) {
  const [t, v1] = header.split(',').map((p) => p.split('=')[1])
  const expected = createHmac('sha256', secret)
    .update(`${t}.${raw}`)
    .digest('hex')
  const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300
  return fresh && timingSafeEqual(Buffer.from(v1), Buffer.from(expected))
}

Errors

Seven codes, each with a name you can switch on.

400invalid_request

A field is missing or malformed. The message names it.

401unauthenticated

Missing, revoked or sandbox key against the live host.

403purpose_not_permitted

The purpose is not on your account’s permitted list.

404not_found

No such check, or it belongs to another account.

409already_answered

The subject has already consented, declined or let it expire.

422unknown_credit_id

The Credit ID does not resolve to a Wiremi account.

429rate_limited

Over 20 requests a second. Retry-After is set.

Sandbox fixtures

Five Credit IDs that behave on purpose.

CC-TEST-OK

Consents in two seconds with the full scope you asked for.

CC-TEST-PARTIAL

Consents, but releases only score and tier.

CC-TEST-DECLINE

Declines in two seconds. check.declined is sent.

CC-TEST-EXPIRE

Never answers. check.expired arrives after 60 seconds in sandbox.

CC-TEST-SLOW

Consents after 45 seconds, for testing your waiting state.

Any other Credit ID in sandbox returns unknown_credit_id, so a typo fails the way it would in production.

The console

Keys, volume, and every request you have ever made.

verify.wiremi.ca
The Verify developer console showing keys, call volume and the request log
Free
Sandbox

Unlimited, unmetered

20/s
Rate limit

Per live key

24 h
Key rotation

Old key overlaps the new one

7 years
Audit retention

Every request and every consent

Developer questions

How long do I wait for consent?
Up to fifteen minutes. After that the request expires and you get a check.expired event. Nothing is charged for an expired, declined or cancelled request.
Can I poll instead of using the webhook?
You can. GET /v1/checks/{id} returns the same status. The webhook is the intended path because it carries the signed scope, and the consent artefact is also available on its own endpoint.
What is a permitted purpose?
A declared reason, sent on every request and shown to the subject before they answer. Your account is enabled for the purposes you are lawfully allowed to check, and a request outside them returns purpose_not_permitted.
Do sandbox checks need real consent?
No. Sandbox returns fixture files on a timer so you can build the whole flow, including the declined and expired branches, before you go live.
Is there an SDK?
Node and Python today, both thin wrappers over the REST API. Anything else works with plain HTTPS and the samples on this page.
Where is the data held?
In Canada. Reports are served from Canadian infrastructure and the audit log is retained for seven years under Canadian law.

Wiremi Verify

Sandbox keys are free. Ask for them and start today.

Write to [email protected] with what you are building, and keys usually come back the same working day.