> ## Documentation Index
> Fetch the complete documentation index at: https://apidoc.easyfreelance.no/llms.txt
> Use this file to discover all available pages before exploring further.

# Start Veriff or BankID verification for an employee

> Creates a verification session for the given employee (`id`). **Intended usage:**

1. **Prerequisite:** `partner_return_url` must be **allowed** for your partner: it must match an **approved** `requested_url` from `POST /verification-return-urls` (same registered base string, or the same base plus allowed dynamic segments per server rules). Otherwise the API may return **422** (return URL not allowed).

2. **Response:** You receive `verification_id` (use this value as `{verificationSession}` when polling status), and `verification_url`. **Open `verification_url` in the end user’s browser** — on EasyFreelance the user is then routed to Veriff or BankID and later back to EasyFreelance before being **redirected to `partner_return_url`**. **`verification_url`** is always the **EasyFreelance verification bouncer** for both providers (then Veriff or BankID). For **`provider: veriff`**, you must send **`id_type`**: `local` uses the Norwegian-only Veriff integration (Norwegian ID documents); `international` uses the integration that accepts non‑Norwegian documents only.

3. **While the user is in the browser flow,** your server should **poll** `GET /verification/status/{verificationSession}` with `verification_id` until `status` is no longer `pending` (or handle completion via your own webhook integration if provided by your deployment — not part of this OpenAPI document).

`status_check_url` in the response is the URL the API associates with checking this session (typically aligned with the polling endpoint above); prefer using `verification_id` with `GET /verification/status/{verificationSession}` as documented.




## OpenAPI

````yaml /easyfreelance-partner-api-merged.yaml post /users/{id}/verification/flows
openapi: 3.0.3
info:
  title: EasyFreelance Partner API
  version: 1.0.0
  description: >
    REST API for partners under `/api/v1`.


    **Authentication:** Every request requires:

    - `Authorization: Bearer <token>` — Sanctum personal access token (created
    in partner **API settings**).

    - `API-key: <uuid>` — Partner API key (same settings).


    **Idempotency (optional):** Header `Idempotency-key` may be sent on partner
    requests.

    - If you omit it, the request behaves normally.

    - If you send it, the value must be a **valid UUID**; otherwise the API
    returns **400**.

    - If the same key has **already been stored** for this partner, the API
    returns **400** (key already used). That check runs for any route once the
    key exists in the idempotency store.

    - **Recommended especially for `POST /payouts`** (create payouts), so safe
    retries do not create duplicate payout side effects. You typically do not
    need this header on read-only calls.


    **Error responses:** Partner endpoints often return JSON with an **`error`**
    key (string or structured validation payload). Some operations documented
    here reference Laravel-style responses with a **`message`** field (e.g.
    unauthenticated). Use HTTP status codes as the primary contract; exact
    wording of messages may change with locale or small API updates.


    **Rate limiting:** Authenticated partner traffic shares **one rolling limit
    per API identity** (Sanctum token / partner user): **500 requests per
    minute** across all `/api/v1/...` routes. When exceeded, the API returns
    **429 Too Many Requests**; responses may include a **`Retry-After`** header
    (seconds). There are no separate per-route partner limits — polling, login
    links, terms updates, and everything else draw from the same budget.


    **Entity verification (Veriff / BankID)** — high-level partner flow:

    1. Register and get approval for a return URL: `POST
    /verification-return-urls` (admin approval). The response includes
    **`requested_url`** (the registered base URL string), **`status`**, and
    auxiliary fields **`normalized_host`**, **`normalized_scheme`**, and
    **`normalized_path_prefix`**. Those `normalized_*` values support display,
    allowlisting, and database uniqueness; **matching** when starting a flow is
    driven by the stored **`requested_url`** (exactly, or as an approved base
    plus allowed dynamic path segments per server rules) — not by treating
    `normalized_path_prefix` as a separate “path template”.

    2. Start a session: `POST /users/{id}/verification/flows` with `provider`
    and `partner_return_url`. The return URL must be **allowed** for your
    partner against an **approved** `requested_url` as above.

    3. Response includes `verification_id` (correlate this ID when **polling**
    `GET /verification/status/{verificationSession}`) and `verification_url` —
    open this URL in the end user’s browser.

    4. The user completes the flow on EasyFreelance-hosted pages, is redirected
    to Veriff or BankID, then returns to EasyFreelance; when finished,
    EasyFreelance redirects the user to `partner_return_url`.

    5. The partner backend should poll using `verification_id` until `status` is
    terminal, and/or consume out-of-band notifications if your deployment offers
    webhooks (not described in this OpenAPI file).


    Details and field semantics for verification are documented under the
    **VerificationFlow** and **VerificationReturnUrlRequest** tags and in the
    operation descriptions below.
servers:
  - url: https://app.easyfreelance.no/api/v1
    description: Production
  - url: https://test.easyfreelance.no/api/v1
    description: Test environment
security:
  - bearer: []
    ApiKeyAuth: []
tags:
  - name: PartnerTerms
    description: Terms metadata and per-user approval
  - name: User
    description: Employees linked to the partner
  - name: Payout
    description: Create and list payouts
  - name: VerificationFlow
    description: >
      **Veriff / BankID** verification for employees: register an allowed
      partner return URL, start a session per user, send the user to
      `verification_url`, poll with `verification_id`, and finally the user is
      redirected to your `partner_return_url`.


      End-to-end: partner return URL approval → `POST …/verification/flows` →
      browser opens **`verification_url`** (verification bouncer on
      EasyFreelance) → user is sent to Veriff or BankID → user returns to
      EasyFreelance → redirect to partner. **`verification_url`** is the same
      style of bouncer URL for both providers (Veriff then redirects out to the
      hosted flow; BankID continues in-app). Use `verification_id` as the
      correlation ID for polling `GET
      /verification/status/{verificationSession}`.
  - name: VerificationReturnUrlRequest
    description: >-
      Register and track approval of partner return URLs used after
      verification.
paths:
  /users/{id}/verification/flows:
    post:
      tags:
        - VerificationFlow
      summary: Start Veriff or BankID verification for an employee
      description: >
        Creates a verification session for the given employee (`id`). **Intended
        usage:**


        1. **Prerequisite:** `partner_return_url` must be **allowed** for your
        partner: it must match an **approved** `requested_url` from `POST
        /verification-return-urls` (same registered base string, or the same
        base plus allowed dynamic segments per server rules). Otherwise the API
        may return **422** (return URL not allowed).


        2. **Response:** You receive `verification_id` (use this value as
        `{verificationSession}` when polling status), and `verification_url`.
        **Open `verification_url` in the end user’s browser** — on EasyFreelance
        the user is then routed to Veriff or BankID and later back to
        EasyFreelance before being **redirected to `partner_return_url`**.
        **`verification_url`** is always the **EasyFreelance verification
        bouncer** for both providers (then Veriff or BankID). For **`provider:
        veriff`**, you must send **`id_type`**: `local` uses the Norwegian-only
        Veriff integration (Norwegian ID documents); `international` uses the
        integration that accepts non‑Norwegian documents only.


        3. **While the user is in the browser flow,** your server should
        **poll** `GET /verification/status/{verificationSession}` with
        `verification_id` until `status` is no longer `pending` (or handle
        completion via your own webhook integration if provided by your
        deployment — not part of this OpenAPI document).


        `status_check_url` in the response is the URL the API associates with
        checking this session (typically aligned with the polling endpoint
        above); prefer using `verification_id` with `GET
        /verification/status/{verificationSession}` as documented.
      operationId: verificationFlow.store
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                provider:
                  type: string
                  enum:
                    - veriff
                    - bankid
                  description: Identity provider to use for this session.
                partner_return_url:
                  type: string
                  maxLength: 2048
                  description: >
                    Where to send the user after verification completes on
                    EasyFreelance. Must match an **approved** registration: the
                    same **requested_url** you had approved (or an allowed
                    extension of that base per server rules). The `normalized_*`
                    fields on the return-URL record are auxiliary; they do not
                    define matching by themselves. Query parameters may be
                    appended by EasyFreelance when redirecting; design this URL
                    to tolerate or ignore unknown query params.
                id_type:
                  type: string
                  enum:
                    - local
                    - international
                  description: >
                    **Required when `provider` is `veriff`.** Select `local` for
                    the Norwegian ID Veriff integration, or `international` for
                    foreign ID documents. Ignored for `bankid` (may be omitted).
              required:
                - provider
                - partner_return_url
      responses:
        '201':
          description: >
            Session created. Use `verification_id` for polling; send the user to
            `verification_url` to start the browser flow.
          content:
            application/json:
              schema:
                type: object
                properties:
                  verification_id:
                    type: string
                    description: >-
                      Session ID — pass as `verificationSession` when polling
                      `GET /verification/status/{verificationSession}`.
                  provider:
                    type: string
                  status:
                    type: string
                    description: >-
                      Initial session status from the server (typically
                      `pending` until the user completes the flow).
                  id_type:
                    type: string
                    nullable: true
                    enum:
                      - local
                      - international
                    description: >-
                      Set for Veriff (`local` vs `international`); `null` for
                      BankID.
                  verification_url:
                    type: string
                    description: >
                      EasyFreelance **verification bouncer** URL for this
                      session — open in the browser; the user is then routed to
                      Veriff or BankID. Use promptly; the session deadline is
                      `expires_at`.
                  status_check_url:
                    type: string
                    description: >-
                      URL the API exposes for checking this session; integrators
                      should poll using `verification_id` on `GET
                      /verification/status/{verificationSession}` as documented.
                  expires_at:
                    type: string
                    description: >-
                      After this time the session may no longer be valid for
                      completing verification.
                required:
                  - verification_id
                  - provider
                  - status
                  - verification_url
                  - status_check_url
                  - expires_at
                  - id_type
        '401':
          $ref: '#/components/responses/AuthenticationException'
        '404':
          description: ''
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    anyOf:
                      - type: string
                      - type: array
                        items:
                          type: object
                          additionalProperties: true
                      - nullable: true
                required:
                  - error
        '422':
          $ref: '#/components/responses/ValidationException'
components:
  responses:
    AuthenticationException:
      description: Unauthenticated
      content:
        application/json:
          schema:
            type: object
            properties:
              message:
                type: string
                description: Error overview.
            required:
              - message
    ValidationException:
      description: Validation error
      content:
        application/json:
          schema:
            type: object
            properties:
              message:
                type: string
                description: Errors overview.
              errors:
                type: object
                description: A detailed description of each field that failed validation.
                additionalProperties:
                  type: array
                  items:
                    type: string
            required:
              - message
              - errors
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      description: Sanctum personal access token (`access_tokens` / partner API settings).
    ApiKeyAuth:
      type: apiKey
      in: header
      name: API-key
      description: UUID API key stored for the partner user.

````