Tous les fournisseurs
Smile ID
identité·🇨🇮🇸🇳🇬🇳🇰🇪🇳🇬🇿🇦·Sandbox disponible
Smile ID est un fournisseur de vérification d’identité dont l’API V3 contrôle les numéros d’identité auprès des autorités émettrices, vérifie les pièces d’identité avec un selfie et filtre les personnes au regard des listes de lutte contre le blanchiment (AML).
À utiliser avec des agents IA
Après avoir installé le plugin ou ajouté le serveur MCP, donnez cette consigne à votre agent :
« Filtre le nom complet d’une personne au regard des listes de sanctions, de personnes politiquement exposées (PEP) et de médias défavorables, et obtiens le résultat One-Time AML dans la même réponse HTTP, sans héberger de webhook. »
Installer le plugin →Capacités
| Capacité | Type | StatutiNon vérifiée — générée à partir de la doc publique, pas encore relue.Disponible — écrite à partir de la doc du fournisseur, pas encore testée : peut contenir des erreurs.Vérifiée — a correspondu une fois à l’API réelle (test en direct, app qui fonctionne ou rapport accepté), en sandbox ou en production. | Méthode | Exemple |
|---|---|---|---|---|
| aml_check_sync | synchrone | Vérifiée | POST | Exemple |
| biometric_kyc | asynchrone | Disponible | POST | Exemple |
| create_smile_link | synchrone | Vérifiée | POST | Exemple |
| document_verification | asynchrone | Disponible | POST | Exemple |
| enhanced_kyc | asynchrone | Vérifiée | POST | Exemple |
| generate_token | synchrone | Vérifiée | POST | Exemple |
| get_smile_link | synchrone | Vérifiée | GET | Exemple |
| get_verification_status | synchrone | Vérifiée | GET | Exemple |
| list_supported_documents | synchrone | Vérifiée | GET | Exemple |
| replay_verification_webhook | asynchrone | Disponible | POST | Exemple |
| webhook_verification_result | webhook | Disponible | POST | Exemple |
Gotchas
Les gotchas sont affichés tels qu’ils figurent dans les specs, dans leur langue d’origine.
aml_check_sync
- ⚠Auth: mint a token with POST /v3/token, then send SmileID-Partner-ID and SmileID-Token on this request (auth.token_exchange / auth.apply). Docs (Authentication): "Access tokens expire **15 minutes** after issuance. We recommend generating a new token for every verification request rather than reusing tokens across multiple requests." Mint tokens on your backend only: the API key never goes to the browser. The endpoint's OpenAPI declares only SmileID-Token; the Authentication page requires both headers — send both.
- ⚠The body must be multipart/form-data, not JSON (415 otherwise). countries and aliases (per this endpoint's docs), and consent, user_details and partner_params (as on the other V3 endpoints) are sent as JSON-serialised strings in their form part — e.g. form.append('consent', JSON.stringify({...})).
- ⚠consent is mandatory in V3: granted must be true, granted_at an ISO 8601 timestamp, notice_language an uppercase ISO 639-1 code (e.g. 'FR'), notice_privacy_policy_url an https URL.
- ⚠countries is required and sent as a JSON-encoded array string (e.g. '["CI","SN"]'); full_name is the name actually screened — user_details is still required (given_names, last_name and email or phone_number).
- ⚠Send a SmileID-Idempotency-Key (16-128 chars of A-Z a-z 0-9 - _) whenever you might retry: a retry without a key starts a new, separately billed screening. Reuse the same key only when you got no response at all (network failure, gateway timeout): it resolves to the same job and returns the original result instead of screening again.
- ⚠Slower than the async /v3/aml: screening runs inline under a request deadline. 408 means the screening provider did not answer in time — the job exists and is terminal in 'error', nothing is billed, and GET /v3/status/{jobId} will only ever return that error: resubmit (with a new idempotency key) rather than poll. A screening that fails internally is a 500, not a 200 with status 'error'.
- ⚠GET /v3/status/{jobId} (SmileID-Job-ID response header) only returns the status, not people[] — keep the 200 body, or store a callback_url and use replay_verification_webhook to get the full result again.
- ⚠A 200 response carries Response-Signature and Response-Timestamp headers computed like the webhooks' — verify them the same way.
- ⚠status 'attention' with reason 'news_media_match' means only adverse-media hits were found; the raw article list is never included, only people[].news_summary.
- ⚠402 Insufficient wallet balance — top up the Smile ID wallet from the Dashboard before retrying.
- ⚠Keys, tokens and callback URLs are environment-specific: a sandbox token returns 401 in production. Sandbox only accepts the documented AML test identities, matched on full_name alone — user_details play no part in matching; production rejects test identities with 400.
biometric_kyc
- ⚠Auth: mint a token with POST /v3/token, then send SmileID-Partner-ID and SmileID-Token on this request (auth.token_exchange / auth.apply). Docs (Authentication): "Access tokens expire **15 minutes** after issuance. We recommend generating a new token for every verification request rather than reusing tokens across multiple requests." Mint tokens on your backend only: the API key never goes to the browser. The endpoint's OpenAPI declares only SmileID-Token; the Authentication page requires both headers — send both.
- ⚠Countries: Biometric KYC needs an ID authority with a photo on file. ID Coverage lists it only for Kenya (NATIONAL_ID, ALIEN_CARD, PASSPORT), Nigeria (BVN, NIN_V2, NIN_SLIP, V_NIN, VOTER_ID) and South Africa (NATIONAL_ID). Côte d'Ivoire's ID types are "Basic KYC, Enhanced KYC" only; Senegal and Guinea have no ID-number product — use document_verification there.
- ⚠Returning users: the token request's use_enrolled_image "Grants the session a Biometric KYC job that verifies against the user's enrolled selfie instead of a fresh capture, so selfie_image and liveness_images may be omitted on that job" — only /v3/token can grant it. Without an enrolled selfie the result is "no enrolled selfie found for this user".
- ⚠The body must be multipart/form-data (415 otherwise). Images are file parts; user_details, consent, partner_params and metadata are JSON-serialised strings in their part. Do not set Content-Type yourself: fetch adds the multipart boundary.
- ⚠liveness_images: 6 to 8 JPEG frames, "or exactly the count set by sdk_config.livenessImageCount when the session token carries one". Append every frame under the exact name liveness_images — the docs' Common issues: "Only one liveness frame arrives" when frames are "appended under indexed names (liveness_images[0])".
- ⚠Capture the selfie and liveness frames with a Smile ID SDK: in the browser, the <smart-camera-web> component publishes frames by image_type_id (2 = selfie_image, 6 = liveness_images, 3 = document, 7 = document_back). An encrypted_package from an SDK is forwarded unchanged with package_nonce, package_tag and the SmileID-Source-SDK and SmileID-Source-SDK-Version headers (422 otherwise).
- ⚠Asynchronous: the response is 202 with status 'accepted' and a job_id, not the verdict. The result (status clear | attention | block | error, reason, message) arrives on your callback_url — see webhook_verification_result; get_verification_status returns "processing" until it is final.
- ⚠consent is mandatory: granted true, granted_at ISO 8601, notice_language uppercase ISO 639-1 (e.g. 'FR'), notice_privacy_policy_url https. user_details needs given_names, last_name and at least one of email or phone_number (E.164).
- ⚠402 Payment Required: insufficient wallet balance. 403: partner not authorized for this product, ID type or IP. 413: an uploaded file exceeds the size limit. 429: rate limit exceeded.
- ⚠Keys, tokens and callback URLs are environment-specific: a sandbox token returns 401 in production. Sandbox only accepts the documented test identities (matched on last_name + given_names + email); production rejects them with 400 'Test identities are not allowed in production'.
- ⚠When the ID authority validates the number but has no photo, the result is error image_unavailable_or_invalid "ID authority photo not available" — sandbox identity Facelessby: "In production, retrying with the same ID number will not succeed."
- ⚠Sandbox: test identities are matched on last_name + given_names + email; Clearwater / Amina Fatou / amina.clearwater@example.com returns clear. sandbox_result is "Only effective when the partner account is in sandbox mode."
create_smile_link
- ⚠Auth: mint a token with POST /v3/token, then send SmileID-Partner-ID and SmileID-Token on this request (auth.token_exchange / auth.apply). Docs (Authentication): "Access tokens expire **15 minutes** after issuance. We recommend generating a new token for every verification request rather than reusing tokens across multiple requests." Mint tokens on your backend only: the API key never goes to the browser. The endpoint's OpenAPI declares only SmileID-Token; the Authentication page requires both headers — send both.
- ⚠A product-scoped token is rejected here with 401 ('missing, invalid, or product-scoped token') — mint the token without `product` for this route.
- ⚠The body must be multipart/form-data, not JSON (415 otherwise). id_types and partner_params are sent as JSON-serialised strings in their form part — e.g. form.append('consent', JSON.stringify({...})).
- ⚠Each id_types entry pairs one country + id_type with exactly one verification_method. The docs do not enumerate verification_method values; the products listed for Smile Links are Enhanced KYC, Biometric KYC, Document Verification and Enhanced Document Verification. An unsupported combination returns 400 (e.g. 'NG PASSPORT is not supported for the enhanced_document_verification product').
- ⚠The response is a creation acknowledgment (link, message, ref_id, user_id), not the full link resource — call get_smile_link with ref_id for it.
- ⚠A payload bound into the SmileID-Token (at generate_token) is copied onto the link only for single-use links; is_single_use false with a payload-bearing token returns 400. The token's callback_url claim is never used for the link.
- ⚠notice_privacy_policy_url, callback_url, logo_url and redirect_url must be public https URLs; private, loopback, link-local and internal addresses are rejected.
- ⚠The redirect and its query parameters can be forged by the end user — decide the outcome from the webhook on callback_url, never from the redirect.
- ⚠Single-use links expire 90 days after creation by default (expires_at). 409 means the user_id is already used by another link.
- ⚠Keys, tokens and callback URLs are environment-specific: a sandbox token returns 401 in production.
document_verification
- ⚠Auth: mint a token with POST /v3/token, then send SmileID-Partner-ID and SmileID-Token on this request (auth.token_exchange / auth.apply). Docs (Authentication): "Access tokens expire **15 minutes** after issuance. We recommend generating a new token for every verification request rather than reusing tokens across multiple requests." Mint tokens on your backend only: the API key never goes to the browser. The endpoint's OpenAPI declares only SmileID-Token; the Authentication page requires both headers — send both.
- ⚠Countries: "Verification by document is available globally." It is the biometric check for countries without an ID-number product (Senegal, Guinea). id_type is optional: "the document type is auto-classified if not provided"; list_supported_documents gives the documents per country.
- ⚠document is the front of the ID (JPEG or PNG); document_back is optional — "Provide when the document has relevant information on the back (e.g., barcodes, MRZ on some document types)". There is no id_number field: identity comes from the document images.
- ⚠This spec is the REST endpoint. The hosted Web SDK flow is an alternative, but its docs conflict on the product identifier: the Web SDK pages use 'doc_verification', while the v12 & v3 troubleshooting FAQ says "Passing a legacy v11 identifier e.g `smart_selfie, doc_verification` to the v12 SDKs will cause initialization errors" and gives `document_verification` — check in sandbox before relying on it.
- ⚠The body must be multipart/form-data (415 otherwise). Images are file parts; user_details, consent, partner_params and metadata are JSON-serialised strings in their part. Do not set Content-Type yourself: fetch adds the multipart boundary.
- ⚠liveness_images: 6 to 8 JPEG frames, "or exactly the count set by sdk_config.livenessImageCount when the session token carries one". Append every frame under the exact name liveness_images — the docs' Common issues: "Only one liveness frame arrives" when frames are "appended under indexed names (liveness_images[0])".
- ⚠Capture the selfie and liveness frames with a Smile ID SDK: in the browser, the <smart-camera-web> component publishes frames by image_type_id (2 = selfie_image, 6 = liveness_images, 3 = document, 7 = document_back). An encrypted_package from an SDK is forwarded unchanged with package_nonce, package_tag and the SmileID-Source-SDK and SmileID-Source-SDK-Version headers (422 otherwise).
- ⚠Asynchronous: the response is 202 with status 'accepted' and a job_id, not the verdict. The result (status clear | attention | block | error, reason, message) arrives on your callback_url — see webhook_verification_result; get_verification_status returns "processing" until it is final.
- ⚠consent is mandatory: granted true, granted_at ISO 8601, notice_language uppercase ISO 639-1 (e.g. 'FR'), notice_privacy_policy_url https. user_details needs given_names, last_name and at least one of email or phone_number (E.164).
- ⚠402 Payment Required: insufficient wallet balance. 403: partner not authorized for this product or IP. 413: an uploaded file exceeds the size limit. 429: rate limit exceeded.
- ⚠Keys, tokens and callback URLs are environment-specific: a sandbox token returns 401 in production. Sandbox only accepts the documented test identities (matched on last_name + given_names + email); production rejects them with 400 'Test identities are not allowed in production'.
- ⚠Sandbox: test identities are matched on last_name + given_names + email; Clearwater / Amina Fatou / amina.clearwater@example.com returns clear, Forgeman block document_check_failed, Xeroxley attention document_copy_detected, Oldfield attention document_expired.
enhanced_kyc
- ⚠Auth: mint a token with POST /v3/token, then send SmileID-Partner-ID and SmileID-Token on this request (auth.token_exchange / auth.apply). Docs (Authentication): "Access tokens expire **15 minutes** after issuance. We recommend generating a new token for every verification request rather than reusing tokens across multiple requests." Mint tokens on your backend only: the API key never goes to the browser. The endpoint's OpenAPI declares only SmileID-Token; the Authentication page requires both headers — send both.
- ⚠The 202 body's status is 'accepted' in the OpenAPI but 'Accepted' in the migration guide and the Web SDK page — compare case-insensitively.
- ⚠V3 Enhanced KYC is always asynchronous: the response is 202 with status 'accepted' and a job_id — not the identity data. The verdict and id_fields arrive on your callback_url (see webhook_verification_result); get_verification_status only returns the status.
- ⚠The body must be multipart/form-data, not JSON (415 otherwise). user_details, consent and partner_params are sent as JSON-serialised strings in their form part — e.g. form.append('consent', JSON.stringify({...})).
- ⚠consent is mandatory in V3: granted must be true, granted_at an ISO 8601 timestamp, notice_language an uppercase ISO 639-1 code (e.g. 'FR'), notice_privacy_policy_url an https URL.
- ⚠user_details requires given_names and last_name plus at least one of email or phone_number (E.164, starting with +).
- ⚠Côte d'Ivoire supports id_type NATIONAL_ID_NO_PHOTO and RESIDENT_ID_NO_PHOTO; id_number is either the 11-digit NNI (/^[0-9]{11}$/) or the alphanumeric document number (/^[A-Za-z]\d{10}$/). Senegal and Guinea have no ID-number product in the docs — use document_verification there.
- ⚠callback_url must be https and on the partner's allowed callback domains list; omit it to use the partner default from the Dashboard.
- ⚠Any job_id you put in partner_params is overwritten by the Smile ID job_id — use another key name for your own reference.
- ⚠402 Insufficient wallet balance — top up the Smile ID wallet from the Dashboard before retrying.
- ⚠429 means the rate limit for this ID number was exceeded — back off before retrying.
- ⚠Keys, tokens and callback URLs are environment-specific: a sandbox token returns 401 in production. Sandbox only accepts the documented test identities (matched on last_name + given_names + email); production rejects them with 400 'Test identities are not allowed in production'.
generate_token
- ⚠Credentials go in headers, not in the body: SmileID-Partner-ID (env SMILEID_PARTNER_ID — numeric, no leading zeros) and SmileID-API-Key (env SMILEID_API_KEY).
- ⚠The returned token is a JWT valid for 15 minutes. Mint a new one per verification request; pass it as SmileID-Token on every other V3 call.
- ⚠The body is optional, but when present it must be multipart/form-data (415 otherwise).
- ⚠Fields bound in payload (country, id_type, id_number, names, email, phone_number, callback_url, consent) are injected server-side into downstream V3 calls and override the request body there; PII is replaced by opaque pii_-prefixed references in the JWT. If you send consent, all four of its fields are required (400 otherwise).
- ⚠product scopes the token to one product: the token then only works for that product, and the Smile Links routes reject a product-scoped token (401).
- ⚠The docs don't say how the object fields (partner_params, payload) are encoded in this multipart body; the canonical example sends them as JSON strings, as documented for the other V3 endpoints — verify in sandbox.
- ⚠Keys, tokens and callback URLs are environment-specific: a sandbox token returns 401 in production.
get_smile_link
- ⚠Auth: mint a token with POST /v3/token, then send SmileID-Partner-ID and SmileID-Token on this request (auth.token_exchange / auth.apply). Docs (Authentication): "Access tokens expire **15 minutes** after issuance. We recommend generating a new token for every verification request rather than reusing tokens across multiple requests." Mint tokens on your backend only: the API key never goes to the browser. The endpoint's OpenAPI declares only SmileID-Token; the Authentication page requires both headers — send both.
- ⚠refId is the ref_id (a uuid) returned by create_smile_link; a non-uuid value returns 400, an unknown one 404.
- ⚠disabled_at is set while the link is disabled and null when active. token_provided_values never contains PII — only country, id_type and consent are returned in the clear.
- ⚠A product-scoped token is rejected here with 401 ('missing, invalid, or product-scoped token') — mint the token without `product` for this route.
- ⚠Keys, tokens and callback URLs are environment-specific: a sandbox token returns 401 in production.
get_verification_status
- ⚠Auth: mint a token with POST /v3/token, then send SmileID-Partner-ID and SmileID-Token on this request (auth.token_exchange / auth.apply). Docs (Authentication): "Access tokens expire **15 minutes** after issuance. We recommend generating a new token for every verification request rather than reusing tokens across multiple requests." Mint tokens on your backend only: the API key never goes to the browser. The endpoint's OpenAPI declares only SmileID-Token; the Authentication page requires both headers — send both.
- ⚠Returns only status, job_id, user_id, message and created_at — not id_fields or the full result. The full result is delivered to your callback_url; use replay_verification_webhook to have it re-sent.
- ⚠The HTTP code carries the state: 200 for a terminal status (clear, block, attention, error), 202 while processing, 404 when the job is not found or not yours. Don't treat 202 as a failure.
- ⚠Observed in the sandbox (live test, 2026-10-24) — not in the docs: called right after enhanced_kyc returned 202, this endpoint answered 404 with status 'not_found', message 'Job not found' and user_id 'unknown' — the job's own created_at, as reported later in the webhook, was a few seconds after that 404. The same job_id answered 200 'clear' ('Job completed') two minutes later. A 404 right after submission does not mean the job doesn't exist: wait and retry, or rely on the callback.
- ⚠jobId is the TypeID returned at submission, with the 'job_' prefix.
- ⚠Keys, tokens and callback URLs are environment-specific: a sandbox token returns 401 in production.
list_supported_documents
- ⚠No authentication required: this endpoint is public.
- ⚠Errors use a different shape from the rest of the V3 API: { error, code } instead of { status, message }.
- ⚠Filter with country_code (ISO 3166-1 alpha-2, uppercase) or continent; locale (en-GB, fr-FR, ar-EG) only changes the document names. has_back tells you whether to capture the back of the document.
- ⚠Enhanced Document Verification only offers the ID types enabled on your account, not this full public catalog.
replay_verification_webhook
- ⚠Auth: mint a token with POST /v3/token, then send SmileID-Partner-ID and SmileID-Token on this request (auth.token_exchange / auth.apply). Docs (Authentication): "Access tokens expire **15 minutes** after issuance. We recommend generating a new token for every verification request rather than reusing tokens across multiple requests." Mint tokens on your backend only: the API key never goes to the browser. The endpoint's OpenAPI declares only SmileID-Token; the Authentication page requires both headers — send both.
- ⚠This is the way to get the full verification result again: Smile ID retries a failed webhook 3 times (4 attempts in total), then stops. The replay is queued (202) and the payload arrives on the callback URL, not in this response.
- ⚠The job must be in a terminal state (clear, block, attention, error) — otherwise 409. Poll get_verification_status first.
- ⚠An optional callback_url overrides the stored one but must be on the partner's callback domain allowlist (403 otherwise). If a body is sent it must be multipart/form-data (415).
- ⚠The 202 body's status is 'accepted' in the OpenAPI; other pages spell the acceptance status 'Accepted' — compare case-insensitively.
- ⚠Keys, tokens and callback URLs are environment-specific: a sandbox token returns 401 in production.
webhook_verification_result
- ⚠Verify every webhook before trusting it: compute HMAC-SHA256 over Response-Timestamp + your partner ID + the literal string 'sid_request', keyed with the API key used to mint the original request's token, base64-encode it and compare with the Response-Signature header. Use the raw Response-Timestamp header value — do not reformat it.
- ⚠Return a 2xx within 35 seconds. Otherwise Smile ID retries immediately, up to 3 times (4 attempts in total), then stops — recover a lost result with replay_verification_webhook.
- ⚠Delivery is at-least-once and unordered: deduplicate and correlate on the smileid-job-id header and the user-id field, not on arrival order.
- ⚠This webhook is the only authoritative verdict. The Web SDK's onResult 'success' only means the job was submitted; a Smile Link redirect fires on submit or cancel and can be forged by the end user.
- ⚠Branch on status (clear, attention, block, error) and reason. id_fields is null when status is block or error; antifraud is null when status is error. The shape of id_fields depends on product, country and ID type — every field is nullable.
- ⚠photo_url, document_link, image_links.* and kyc_receipt are signed URLs that expire after 15 minutes — download what you need to keep immediately.
- ⚠Callback URLs are set per environment in the Dashboard (Developer > Security Settings > Callback URLs) or per request with callback_url. If you filter inbound traffic by IP, allow Smile ID's callback IPs (production: 13.51.0.119, 34.240.137.52, 51.20.27.3, 52.213.46.74; sandbox: 13.48.228.158, 16.170.104.93, 54.246.37.255, 99.81.237.141).
Détails
- Catégorie
- identité
- Sandbox
- Oui