Developers

One API for identity, ownership, screening and monitoring

Everything the eterfaceID console does is available over HTTP. Authenticate with an API key, page through results, retry safely with idempotency keys, and receive signed webhooks when something changes.

Quick start

Create your first case in one request.

  1. 1. In the console, open Settings and create an API key. Test keys start eid_test_, live keys eid_live_. The secret is shown once.
  2. 2. Send it on every request as Authorization: Bearer eid_….
  3. 3. Check it works with GET /api/public/v1/ping.
  4. 4. Add a webhook endpoint in Settings so results reach you without polling.
curl https://eterfaceid.com/api/public/v1/cases \
  -H "Authorization: Bearer eid_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: efin-10231" \
  -d '{
    "case_type": "person",
    "subject_name": "Amelia Okonkwo",
    "country": "CA",
    "reference": "customer_8842"
  }'

Conventions

The same rules apply to every endpoint, so there are no surprises per resource.

Base URL

All paths below are relative to https://eterfaceid.com/api/public/v1.

Scoping

A key only ever reads and writes records belonging to its own company. Nothing else is visible.

Paging

List endpoints accept ?limit= (up to 200) and ?offset=, newest first.

Idempotency

Send an Idempotency-Key header on creates. A repeat of the same key returns the first response instead of creating a duplicate.

Sandbox and live keys

Build against sandbox for free; live keys are issued once your business is verified and the agreement is signed.

Sandbox — eid_test_…

Available the moment you create an account, unlimited and never billed. Sandbox keys never query the real sanctions and watchlists and never open a real bank connection: results are simulated so you can test every branch of your code. Use these names to drive the outcome:

  • test-sanctioned — Screening returns a high-confidence sanctions match and a high risk score.
  • test-pep — Screening returns a politically exposed person match and a medium risk score.
  • test-review — Bank-confirmed identity comes back as a close, not exact, match.
  • test-fail — Bank-confirmed identity and The KYB registry lookup come back as different / dissolved.
  • any other name — Clean result, no matches.

Live — eid_live_…

Live keys reach the real lists, real bank connections and your billable usage. Before they can be created, an administrator completes Go live in the console: business details and beneficial owners are submitted and verified, the commercial agreement is signed, and an eterfaceID reviewer confirms.

A live call is refused with a clear error code when access is not approved, the agreement is missing, the account is suspended, or the month's included volume is used up. Each key is also limited to 120 calls a minute.

Getting started

Check a key and see which company and environment it belongs to.

GET/api/public/v1/pingCheck your key

Confirms the key works and returns the company and environment it belongs to.

Response

{
  "data": {
    "ok": true,
    "api_version": "v1",
    "environment": "live",
    "organization": {
      "id": "…",
      "name": "eFinMoney"
    }
  }
}

Cases

A case is one person or one business being checked.

GET/api/public/v1/casesList cases

Newest first. Filter with ?status= and ?case_type=, page with ?limit= and ?offset=.

Response

{
  "data": [
    {
      "id": "…",
      "reference": "API-XYZ",
      "case_type": "person",
      "status": "in_review",
      "risk_level": "low"
    }
  ]
}
POST/api/public/v1/casesCreate a case

Send an Idempotency-Key header so a retry never creates a second case.

Request

{
  "case_type": "person",
  "subject_name": "Jane Doe",
  "country": "CA",
  "reference": "EFIN-10231"
}

Response

{
  "data": {
    "id": "…",
    "reference": "EFIN-10231",
    "status": "pending"
  }
}
GET/api/public/v1/cases/{case_id}Read a case

The case with its checks, screening matches, beneficial owners and recent transactions.

POST/api/public/v1/cases/{case_id}/decisionApprove or reject

Records the decision, writes the audit entry and emails the reviewer and case owner.

Request

{
  "status": "approved",
  "note": "Document and bank details matched."
}

Identity verification

Either send us the data yourself, or hand the customer a secure link.

POST/api/public/v1/cases/{case_id}/verification-sessionsCreate a hosted link

Returns a one-time link the customer opens to submit their ID and liveness check. The result arrives on your webhook as verification.completed.

Request

{
  "expires_in_minutes": 1440,
  "redirect_url": "https://app.efinmoney.com/kyc/done"
}

Response

{
  "data": {
    "id": "…",
    "url": "https://eterfaceid.com/verify/…",
    "expires_at": "…"
  }
}
POST/api/public/v1/cases/{case_id}/documentsSubmit a document

Server-to-server document check: machine-readable lines are parsed and validated, dates and ID number formats are checked, and the name is compared with the case.

Request

{
  "doc_type": "passport",
  "mrz": "P<CANDOE<<JANE<<<<…",
  "document_number": "AB123456",
  "birth_date": "1990-04-12"
}

Response

{
  "data": {
    "document_id": "…",
    "result": "pass",
    "checks": [
      {
        "name": "MRZ check digits",
        "ok": true
      }
    ]
  }
}
POST/api/public/v1/cases/{case_id}/selfiesSubmit a liveness check

Scores liveness from the capture signals. Face-to-document matching is confirmed by a reviewer.

Request

{
  "challenge": "Blink twice",
  "signals": {
    "frames_captured": 16,
    "challenge_passed": true,
    "motion_variance": 0.18,
    "brightness_range": 0.12,
    "blur_score": 0.22,
    "face_stable": true
  }
}
POST/api/public/v1/cases/{case_id}/addressesVerify an address and age

Checks address structure, postal code and province, and validates date of birth when supplied.

Request

{
  "line1": "120 King St W",
  "city": "Toronto",
  "region": "ON",
  "postal_code": "M5H 1A1",
  "country": "CA",
  "birth_date": "1990-04-12"
}
POST/api/public/v1/cases/{case_id}/riskScore fraud and device risk

Email, phone, device and network signals combined into one score with every factor listed.

Request

{
  "email": "jane@example.com",
  "phone": "+14165550123",
  "ip_address": "203.0.113.4",
  "ip_country": "CA",
  "fingerprint": "…"
}

Business verification

Beneficial ownership under FATF R.24/R.25, the CTA and PCMLTFA.

GET/api/public/v1/cases/{case_id}/ownersList owners

Everyone recorded against the business, with effective percentages.

POST/api/public/v1/cases/{case_id}/ownersAdd an owner

Layered holdings are supported through parent_owner_id.

Request

{
  "name": "Holdco Ltd",
  "entity_type": "business",
  "ownership_pct": 60,
  "country": "CA"
}
POST/api/public/v1/cases/{case_id}/ownershipWork out the beneficial owners

Multiplies ownership down the chain, flags owners at or above 25%, and applies the OFAC 50 percent rule.

Response

{
  "data": {
    "owners": [
      {
        "name": "Jane Doe",
        "effectivePct": 42,
        "isUbo": true
      }
    ],
    "rule": {
      "blocked": false
    }
  }
}
GET/api/public/v1/cases/{case_id}/registryRead The KYB registry lookups

Official-registry results already saved on the case.

POST/api/public/v1/cases/{case_id}/registryLook up the company in The KYB

Searches official registries through The KYB and attaches the best match (or a chosen kyb_response_id) as an entity check.

Request

{
  "name": "Acme Ltd",
  "registration_number": "1234567",
  "country": "CA"
}

Screening and monitoring

Sanctions, PEP and watchlist screening, plus transaction rules and alerts.

POST/api/public/v1/screeningScreen a name

Ad-hoc screening with no case attached. Returns every match above the threshold with its reasons.

Request

{
  "name": "Vladimir Putin",
  "entity_type": "person",
  "country": "RU",
  "threshold": 0.72
}
POST/api/public/v1/cases/{case_id}/screenScreen or re-screen a case

Records new matches against the case and updates its risk score.

Request

{
  "threshold": 0.72
}
GET/api/public/v1/cases/{case_id}/hitsList matches

Screening matches recorded on the case.

PATCH/api/public/v1/hits/{hit_id}Clear or confirm a match

Mark a match as a true or false positive, with a note.

Request

{
  "disposition": "false_positive",
  "note": "Different date of birth."
}
POST/api/public/v1/transactionsRecord a payment

Runs FINTRAC, FinCEN and FATF rules (cash and cross-border thresholds, structuring, travel rule, velocity, deviation) and screens the counterparty.

Request

{
  "case_id": "…",
  "direction": "inbound",
  "method": "cash",
  "amount": 9800,
  "currency": "CAD",
  "counterparty_name": "Acme Ltd"
}

Response

{
  "data": {
    "id": "…",
    "risk_score": 72,
    "status": "review",
    "alerts": [
      {
        "code": "STRUCTURING"
      }
    ]
  }
}
GET/api/public/v1/transactionsList payments

Filter with ?case_id=.

GET/api/public/v1/alertsList alerts

Filter with ?status= and ?case_id=.

PATCH/api/public/v1/alerts/{alert_id}Acknowledge or close an alert

Moves an alert to acknowledged or closed.

Request

{
  "status": "closed",
  "detail": "Reviewed, expected activity."
}

Bank-confirmed identity

Available when bank connections are switched on for the platform.

POST/api/public/v1/cases/{case_id}/bankStart or finish a bank link

Called with no body it returns a link token your front-end passes to the bank sign-in window. Called with public_token it completes the link.

Request

{
  "public_token": "public-sandbox-…"
}
GET/api/public/v1/cases/{case_id}/bankRead bank results

Linked banks and the field-by-field identity comparison.

Regulatory reports

Draft, list and mark filed the reports your regulator expects.

POST/api/public/v1/reportsDraft a report

Builds an STR, LCTR, EFTR, SAR, CTR or FIU package from the case, its matches and its payments.

Request

{
  "case_id": "…",
  "report_type": "str",
  "jurisdiction": "CA",
  "authority": "FINTRAC",
  "narrative": "…"
}
GET/api/public/v1/reportsList reports

Filter with ?status=.

GET/api/public/v1/reports/{report_id}Read a report

The full report package.

PATCH/api/public/v1/reports/{report_id}Mark a report filed

Records the authority's reference and fires the report.filed webhook.

Request

{
  "status": "submitted",
  "reference": "FINTRAC-2026-0091"
}

Webhooks

Signed with your endpoint secret so you can prove we sent them.

EventSent when
case.createdA case is created through the API.
case.decisionA case is approved or rejected.
verification.completedA document, liveness check or hosted link is finished.
screening.hitScreening finds a new match on a case.
transaction.flaggedA payment triggers one or more rules.
report.filedA regulatory report is marked as filed.

Each delivery carries an x-eterfaceid-signature header — a SHA-256 HMAC of the raw body using the signing secret shown once when you add the endpoint. Compare it before trusting the payload. Deliveries and their responses are logged in Settings.

const expected = crypto
  .createHmac("sha256", process.env.ETERFACEID_WEBHOOK_SECRET)
  .update(rawBody)
  .digest("hex");

if (req.headers["x-eterfaceid-signature"] !== expected) {
  return res.status(401).end();
}

Errors

Every failure returns JSON with an error code and a plain message.

CodeHTTPMeaning
missing_api_key401No key was sent in the Authorization header.
invalid_api_key401The key does not exist.
revoked_api_key401The key was revoked in the console.
live_access_required403Live access has not been approved for this account yet.
live_access_suspended403Live access for this account is suspended.
contract_required403The commercial agreement has not been signed.
account_inactive402The account is suspended or cancelled.
quota_exceeded402The month's included volume has been used up. Upgrade the plan.
rate_limited429More than 120 calls in one minute on this key.
invalid_request422The body failed validation; the issues are listed.
not_found404No such record for your company.
integration_disabled409That add-on is switched off.
query_failed500Something went wrong on our side.

OpenAPI

Import the machine-readable spec into Postman, or generate a client in your language.

Integrating eterfaceID?

Tell us what you are building and we will help you scope the first calls.