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. In the console, open Settings and create an API key. Test keys start
eid_test_, live keyseid_live_. The secret is shown once. - 2. Send it on every request as
Authorization: Bearer eid_…. - 3. Check it works with
GET /api/public/v1/ping. - 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.
/api/public/v1/pingCheck your keyConfirms 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.
/api/public/v1/casesList casesNewest 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"
}
]
}/api/public/v1/casesCreate a caseSend 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"
}
}/api/public/v1/cases/{case_id}Read a caseThe case with its checks, screening matches, beneficial owners and recent transactions.
/api/public/v1/cases/{case_id}/decisionApprove or rejectRecords 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.
/api/public/v1/cases/{case_id}/verification-sessionsCreate a hosted linkReturns 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": "…"
}
}/api/public/v1/cases/{case_id}/documentsSubmit a documentServer-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
}
]
}
}/api/public/v1/cases/{case_id}/selfiesSubmit a liveness checkScores 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
}
}/api/public/v1/cases/{case_id}/addressesVerify an address and ageChecks 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"
}/api/public/v1/cases/{case_id}/riskScore fraud and device riskEmail, 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.
/api/public/v1/cases/{case_id}/ownersList ownersEveryone recorded against the business, with effective percentages.
/api/public/v1/cases/{case_id}/ownersAdd an ownerLayered holdings are supported through parent_owner_id.
Request
{
"name": "Holdco Ltd",
"entity_type": "business",
"ownership_pct": 60,
"country": "CA"
}/api/public/v1/cases/{case_id}/ownershipWork out the beneficial ownersMultiplies 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
}
}
}/api/public/v1/cases/{case_id}/registryRead The KYB registry lookupsOfficial-registry results already saved on the case.
/api/public/v1/cases/{case_id}/registryLook up the company in The KYBSearches 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.
/api/public/v1/screeningScreen a nameAd-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
}/api/public/v1/cases/{case_id}/screenScreen or re-screen a caseRecords new matches against the case and updates its risk score.
Request
{
"threshold": 0.72
}/api/public/v1/cases/{case_id}/hitsList matchesScreening matches recorded on the case.
/api/public/v1/hits/{hit_id}Clear or confirm a matchMark a match as a true or false positive, with a note.
Request
{
"disposition": "false_positive",
"note": "Different date of birth."
}/api/public/v1/transactionsRecord a paymentRuns 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"
}
]
}
}/api/public/v1/transactionsList paymentsFilter with ?case_id=.
/api/public/v1/alertsList alertsFilter with ?status= and ?case_id=.
/api/public/v1/alerts/{alert_id}Acknowledge or close an alertMoves 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.
/api/public/v1/cases/{case_id}/bankStart or finish a bank linkCalled 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-…"
}/api/public/v1/cases/{case_id}/bankRead bank resultsLinked banks and the field-by-field identity comparison.
Regulatory reports
Draft, list and mark filed the reports your regulator expects.
/api/public/v1/reportsDraft a reportBuilds 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": "…"
}/api/public/v1/reportsList reportsFilter with ?status=.
/api/public/v1/reports/{report_id}Read a reportThe full report package.
/api/public/v1/reports/{report_id}Mark a report filedRecords 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.
| Event | Sent when |
|---|---|
| case.created | A case is created through the API. |
| case.decision | A case is approved or rejected. |
| verification.completed | A document, liveness check or hosted link is finished. |
| screening.hit | Screening finds a new match on a case. |
| transaction.flagged | A payment triggers one or more rules. |
| report.filed | A 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.
| Code | HTTP | Meaning |
|---|---|---|
| missing_api_key | 401 | No key was sent in the Authorization header. |
| invalid_api_key | 401 | The key does not exist. |
| revoked_api_key | 401 | The key was revoked in the console. |
| live_access_required | 403 | Live access has not been approved for this account yet. |
| live_access_suspended | 403 | Live access for this account is suspended. |
| contract_required | 403 | The commercial agreement has not been signed. |
| account_inactive | 402 | The account is suspended or cancelled. |
| quota_exceeded | 402 | The month's included volume has been used up. Upgrade the plan. |
| rate_limited | 429 | More than 120 calls in one minute on this key. |
| invalid_request | 422 | The body failed validation; the issues are listed. |
| not_found | 404 | No such record for your company. |
| integration_disabled | 409 | That add-on is switched off. |
| query_failed | 500 | Something 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.