API/Verification
Flows
Verification (KYC / ID)
Veriff and BankID are used to verify the contractor's identity. The flow runs from an approved return URL, via one session per user, to a terminal status.
The end-to-end flow
Register a return URL
POST /verification-return-urlswith the URL the user should be sent back to. The response containsrequested_urlandstatus. The approval is done manually by EasyFreelance and may take time –201means registered, not approved. UseGET /verification-return-urlsto see the status.Start a session
POST /users/{id}/verification/flowswithproviderandpartner_return_url. The URL must be allowed for your partner, matched against a approvedrequested_url. If it is not, you get422.Send the user to verification_url
The response contains
verification_idandverification_url. Open the URL in the end user's browser. It always points to the EasyFreelance verification page, which then forwards the user on to Veriff or BankID.The user completes and returns
After Veriff or BankID, the user is sent back to EasyFreelance, and from there on to
partner_return_url.Poll until the status is terminal
GET /verification/status/{verificationSession}withverification_idas the ID. Poll every 2–5 seconds. Alternatively, or in addition, you can listen foremployee.verified-webhook and fetchGET /users/{id}for the final result.
Providers
| provider | id_type | Use |
|---|---|---|
veriff | local | The Veriff integration for Norwegian ID documents. |
veriff | international | The Veriff integration that only accepts foreign documents. |
bankid | — | BankID. id_type may be omitted, and is returned as null. |
id_type is required when provider is veriff. The two Veriff integrations are mutually exclusive: local does not accept foreign documents, and international does not accept Norwegian ones. Choose the right variant before you send the user on their way.
The return URL
When a session is terminal, EasyFreelance sends the user to partner_return_url with these query parameters appended. Your page must tolerate – and preferably read – them.
| Parameter | Example |
|---|---|
verification_id | 550e8400-e29b-41d4-a716-446655440000 |
provider | bankid or veriff |
status | approved, incomplete, error … |
The fields normalized_host, normalized_scheme and normalized_path_prefix in the return URL response is for display, allowlisting and uniqueness in the database. The actual matching when a flow is started is done against the stored requested_url – normalized_path_prefix is not its own “path template”.
Status values
| status | Terminal | Meaning |
|---|---|---|
pending | No | The session has been created, the user is not finished. |
approved | Yes | The provider is OK and the identity is complete. |
incomplete | Yes | The provider is OK, but identity fields are missing. |
declined | Yes | The verification was rejected. |
error | Yes | Error during processing – for example a duplicate national identity number. |
expired | Yes | The session expired before the user finished. |
cancelled | Yes | The user cancelled. |
next_action
next_action is always set on the polling response, and tells your client what it should do next.
| next_action | When | Do this |
|---|---|---|
continue_verification | pending | Keep polling. |
redirect_to_partner | approved | Send the user onward in your own flow. |
retry_verification | incomplete | Ask the user to restart the verification. |
contact_support | error with a duplicate national identity number | Requires manual follow-up – contact EasyFreelance. |
retry | declined and other errors | Let the user try again. |
show_error | expired, cancelled | Show an error message and offer a fresh start. |
id_verification_detail
The same structure is returned for GET /users/{id}, in the user list, on lookups, on polling and in the webhook. Use reason_codes for automation and partner_instructions into text you can display to the user.
| reason_code | Meaning |
|---|---|
ssn_not_provided | The provider did not return a national identity number. |
ssn_duplicate | The national identity number already exists in the system. Requires manual follow-up – contact support. |
birthday_not_provided | The date of birth is missing. |
provider_data_incomplete | The entity is approved, but the identity data is incomplete. |
veriff_missing_id_number | Veriff did not return an ID number. |
veriff_missing_date_of_birth | Veriff did not return a date of birth. |
veriff_missing_document_country | Veriff did not return a document country. |
{
"verification_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": 123,
"provider": "bankid",
"id_type": null,
"status": "incomplete",
"verified_at": "2026-07-08T12:00:00+00:00",
"expires_at": "2026-07-08T12:30:00+00:00",
"next_action": "retry_verification",
"last_polled_at": "2026-07-08T12:00:05+00:00",
"id_verification_detail": {
"complete": false,
"entity_status": "approved",
"provider": "BankID",
"missing_fields": [
"identification"
],
"reason_codes": [
"ssn_not_provided"
],
"partner_instructions": [
{
"code": "retry_verification",
"message": "Identity verification partially completed. Missing national ID number."
}
]
}
}Duplicate national identity number
If you receive status: error with ssn_duplicate, the number is already registered in the system. This cannot be resolved via the API – contact [email protected] and provide the user ID.
On GET /users/{id} the server automatically retrieves the most recent terminal ssn_duplicate-session for your partner, so that this result appears without you having to send verification_id.
Webhook
If you enable employee.verified in the API settings, we send a POST call to your callback URL when the verification is complete. That is a good alternative to frequent polling. See Webhooks.