> For the complete documentation index, see [llms.txt](https://docs.ur.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ur.app/api-reference/kyc-and-kyb/retry-kyc.md).

# Retry KYC

This page documents retry KYC (also called additional KYC): the flow UR uses when an already-onboarded user must resubmit some or all of their KYC data. Typical triggers are a compliance re-check on a live account, remediation after Fiat24 rejects an account, and an onboarding session that expired before it completed.

Retry KYC reuses the endpoints you already integrated for onboarding. What changes is the entry point: instead of calling `/create-account`, you claim a session that UR created for you, then run only the steps UR asks for.

{% hint style="info" %}
Only UR operations staff can start a retry. Neither your platform nor the user can start one. `POST /api/fma/v1/kyc/session/create` fails with `30034` when no retry directive is pending for the user.
{% endhint %}

{% hint style="warning" %}
**"Retry" means two different things across these pages.** They are separate mechanisms and do not share endpoints.

The onboarding restart path is documented on [Managed Custody SDK KYC](/api-reference/kyc-and-kyb/managed-custody-sdk-kyc.md) and [Shared-token KYC reuse](/api-reference/kyc-and-kyb/shared-token-kyc-reuse.md). Do not call `/create-account` to service a retry directive, and do not wait for a retry directive to let a rejected user try onboarding again.
{% endhint %}

|               | Retry KYC (this page)                                                      | Onboarding restart                                                          |
| ------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| Who starts it | UR operations only                                                         | Your platform                                                               |
| When          | The user is already onboarded, and compliance wants data resubmitted       | Onboarding failed, for example Sumsub returned `RED`                        |
| How you enter | `POST /api/fma/v1/kyc/session/create`, after `fma.additional_kyc.required` | `POST /api/fma/v1/create-account` again, with the same `X-External-User-Id` |
| Scope         | Only the steps `taskType` names                                            | The whole onboarding flow                                                   |

## 1. Where this fits

Retry KYC works with the onboarding path your `partnerId` already uses. The `dataChannel` field in the webhook payload tells you which path applies to the user, and the steps you run come from that path:

| `dataChannel`  | Your onboarding path                                                             | Retry entry point for the user data                                         |
| -------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `push`         | Data push to UR                                                                  | `POST /api/fma/v1/kyc/sync-data`                                            |
| `sdk`          | [Managed Custody SDK KYC](/api-reference/kyc-and-kyb/managed-custody-sdk-kyc.md) | `POST /api/fma/v1/kyc/sumsub-access-token`, then the Sumsub SDK             |
| `shared-token` | [Shared-token KYC reuse](/api-reference/kyc-and-kyb/shared-token-kyc-reuse.md)   | `POST /api/fma/v1/kyc/reuse-share-token`, then `POST /api/fma/v1/kyc/check` |

{% hint style="warning" %}
Partners on the pull integration (`dataChannel` returns `pull`) are not covered by the current retry catalogue. If you receive a retry webhook with `dataChannel: "pull"`, use your dedicated integration channel before you act on it.
{% endhint %}

Two payload fields drive everything you do:

* `taskType` tells you what the user must redo. Treat this field as authoritative.
* `fiat24Mode` tells you how the session finishes, and specifically whether you call `/kyc/submit`.

### What to read for your channel

Every section applies to every channel except the per-channel walkthroughs in section 5, which you can read selectively:

| Your `dataChannel` | Read in section 5    | Skip                                                                                                                         |
| ------------------ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `push`             | Push channel         | SDK channel, shared-token channel, and the two SDK-only notes about the access-token timeout and the SDK closing immediately |
| `sdk`              | SDK channel          | Push channel, shared-token channel                                                                                           |
| `shared-token`     | Shared-token channel | Push channel, SDK channel                                                                                                    |

Read [Webhooks](https://docs.ur.app/developer-resources/webhook) alongside this page for the envelope, signature verification, and delivery contract that apply to both retry events.

## 2. Lifecycle

The diagram below traces one user end to end: first-time onboarding, registration with the banking partner, going live, and then a retry that UR operations issue later. Part A is onboarding, covered in depth on your channel's own page; part B is what this page documents.

Pick your channel. The retry phases are structurally identical across channels, and only the data collection step differs.

{% tabs %}
{% tab title="SDK channel" %}

```mermaid
sequenceDiagram
    autonumber
    participant U as End user
    participant PA as Partner app
    participant PB as Partner backend
    participant UR as UR OpenAPI
    participant SS as UR Sumsub tenant
    participant OPS as UR operations

    rect rgb(240,250,255)
    note over PB,SS: Part A1. First-time onboarding
    PB->>UR: POST /api/fma/v1/create-account
    UR-->>PB: 200 sessionId, urId, state ConfirmYourCountryOfResidence
    PB->>UR: POST /api/fma/v1/kyc/sumsub-access-token
    UR-->>PB: 200 token
    PB->>PA: Relay the token
    PA->>SS: Launch the Sumsub SDK
    U->>SS: Complete every level
    SS->>UR: applicantWorkflowCompleted GREEN
    note over UR: UR stores the applicant snapshot<br/>and advances state to SignFormA
    end

    rect rgb(245,255,245)
    note over PB,UR: Part A2. Form A, submit, register
    PB->>UR: GET /api/fma/v1/kyc/form-a-info
    PB->>U: Display Form A, obtain consent
    PB->>UR: POST /api/fma/v1/kyc/sign-form
    PB->>UR: POST /api/fma/v1/kyc/submit
    note over UR: UR registers the user with the banking partner<br/>and mints the URID to Live. This happens once per user.
    UR->>PB: Webhook fma.account.result status activated
    end

    rect rgb(255,250,235)
    note over OPS,PB: Part B1. Operations issue a retry
    OPS->>UR: Create retry directive
    note over UR: UR seals the user current session,<br/>so any sessionId you hold stops working
    UR->>PB: Webhook fma.additional_kyc.required
    note over PB: Branch on taskType and fiat24Mode
    end

    rect rgb(240,250,255)
    note over PB,UR: Part B2. Claim the retry session
    PB->>UR: POST /api/fma/v1/kyc/session/create
    UR-->>PB: 200 sessionId
    end

    rect rgb(245,255,245)
    note over PB,SS: Part B3. The user redoes only the targeted steps
    PB->>UR: POST /api/fma/v1/kyc/sumsub-access-token
    note over UR,SS: UR resets the targeted Sumsub steps and<br/>verifies each reset before issuing the token.<br/>Allow 60s or more on this call.
    UR-->>PB: 200 token
    PB->>PA: Relay the token
    PA->>SS: Launch the Sumsub SDK
    U->>SS: Redo the targeted step only
    SS->>UR: Verdict for the redone step
    end

    rect rgb(250,245,255)
    note over PB,UR: Part B4. Re-sign Form A and finish
    PB->>UR: GET /api/fma/v1/kyc/form-a-info
    PB->>UR: POST /api/fma/v1/kyc/sign-form
    alt fiat24Mode ops_offline
        note over UR: Already registered, so no submit.<br/>The session completes on its own.
    else fiat24Mode auto_register
        PB->>UR: POST /api/fma/v1/kyc/submit
        UR->>PB: Webhook fma.account.result status activated
    end
    UR->>PB: Webhook fma.additional_kyc.completed
    end
```

Part A is documented in full on [Managed Custody SDK KYC](/api-reference/kyc-and-kyb/managed-custody-sdk-kyc.md).
{% endtab %}

{% tab title="Push channel" %}

```mermaid
sequenceDiagram
    autonumber
    participant U as End user
    participant PA as Partner app
    participant PB as Partner backend
    participant UR as UR OpenAPI
    participant OPS as UR operations

    rect rgb(240,250,255)
    note over PB,UR: Part A1. First-time onboarding
    PB->>UR: POST /api/fma/v1/create-account
    UR-->>PB: 200 sessionId, urId, state PartnerDataIngestion
    U->>PA: Provide KYC data in your own UI
    PA-->>PB: Collected data
    PB->>UR: POST /api/fma/v1/kyc/sync-data
    PB->>UR: Identity verification, penny transfer or NFC read
    note over UR: state advances to SignFormA
    end

    rect rgb(245,255,245)
    note over PB,UR: Part A2. Form A, submit, register
    PB->>UR: GET /api/fma/v1/kyc/form-a-info
    PB->>U: Display Form A, obtain consent
    PB->>UR: POST /api/fma/v1/kyc/sign-form
    PB->>UR: POST /api/fma/v1/kyc/submit
    note over UR: UR registers the user with the banking partner<br/>and mints the URID to Live. This happens once per user.
    UR->>PB: Webhook fma.account.result status activated
    end

    rect rgb(255,250,235)
    note over OPS,PB: Part B1. Operations issue a retry
    OPS->>UR: Create retry directive
    note over UR: UR seals the user current session,<br/>so any sessionId you hold stops working
    UR->>PB: Webhook fma.additional_kyc.required
    note over PB: Branch on taskType.<br/>requiredFields names the exact paths to fix.
    end

    rect rgb(240,250,255)
    note over PB,UR: Part B2. Claim the retry session
    PB->>UR: POST /api/fma/v1/kyc/session/create
    UR-->>PB: 200 sessionId
    end

    rect rgb(245,255,245)
    note over PB,U: Part B3. You recollect and push the data
    PB->>PA: Ask the user for the data named by taskType
    PA->>U: Collect it in your own UI
    U-->>PB: Corrected data
    PB->>UR: POST /api/fma/v1/kyc/sync-data
    note over PB,UR: requiredFields non-empty: send only those paths.<br/>taskType full: send the complete payload,<br/>because UR starts the snapshot empty.
    opt taskType full only
        PB->>UR: Identity verification, penny transfer or NFC read
    end
    end

    rect rgb(250,245,255)
    note over PB,UR: Part B4. Re-sign Form A and finish
    PB->>UR: GET /api/fma/v1/kyc/form-a-info
    PB->>UR: POST /api/fma/v1/kyc/sign-form
    alt fiat24Mode ops_offline
        note over UR: Already registered, so no submit.<br/>The session completes on its own.
    else fiat24Mode auto_register
        PB->>UR: POST /api/fma/v1/kyc/submit
        UR->>PB: Webhook fma.account.result status activated
    end
    UR->>PB: Webhook fma.additional_kyc.completed
    end
```

No Sumsub SDK is involved on this channel. All data collection happens in your own UI, during onboarding and during a retry alike.
{% endtab %}

{% tab title="Shared-token channel" %}

```mermaid
sequenceDiagram
    autonumber
    participant U as End user
    participant PS as Partner Sumsub tenant
    participant PB as Partner backend
    participant UR as UR OpenAPI
    participant US as UR Sumsub tenant
    participant OPS as UR operations

    rect rgb(240,250,255)
    note over U,US: Part A1. First-time onboarding
    U->>PS: Complete KYC in your cloned UR workflow
    PS-->>PB: applicantReviewed GREEN
    PB->>UR: POST /api/fma/v1/create-account
    UR-->>PB: 200 sessionId, urId, state PartnerDataIngestion
    PB->>PS: Mint a single-use share token for UR clientId
    PB->>UR: POST /api/fma/v1/kyc/reuse-share-token
    UR->>US: Copy Applicant and validate
    UR->>PB: Webhook fma.kyc.reuse_check.result passed
    end

    rect rgb(245,255,245)
    note over PB,UR: Part A2. Form A, submit, register
    PB->>UR: GET /api/fma/v1/kyc/form-a-info
    PB->>U: Display Form A, obtain consent
    PB->>UR: POST /api/fma/v1/kyc/sign-form
    PB->>UR: POST /api/fma/v1/kyc/submit
    note over UR: UR registers the user with the banking partner<br/>and mints the URID to Live. This happens once per user.
    UR->>PB: Webhook fma.account.result status activated
    end

    rect rgb(255,250,235)
    note over OPS,PB: Part B1. Operations issue a retry
    OPS->>UR: Create retry directive
    note over UR: UR seals the user current session,<br/>so any sessionId you hold stops working
    UR->>PB: Webhook fma.additional_kyc.required
    note over PB: Branch on taskType and fiat24Mode
    end

    rect rgb(240,250,255)
    note over PB,UR: Part B2. Claim the retry session
    PB->>UR: POST /api/fma/v1/kyc/session/create
    UR-->>PB: 200 sessionId
    end

    rect rgb(245,255,245)
    note over U,US: Part B3. The user redoes the steps in your tenant
    U->>PS: Redo the steps named by taskType
    PB->>PS: Mint a fresh single-use share token
    note over PB: A token minted for the earlier session<br/>is not valid for the retry session
    PB->>UR: POST /api/fma/v1/kyc/reuse-share-token
    UR->>US: Copy Applicant and validate
    PB->>UR: POST /api/fma/v1/kyc/check
    UR-->>PB: 200 verdict
    end

    rect rgb(250,245,255)
    note over PB,UR: Part B4. Re-sign Form A and finish
    PB->>UR: GET /api/fma/v1/kyc/form-a-info
    PB->>UR: POST /api/fma/v1/kyc/sign-form
    alt fiat24Mode ops_offline
        note over UR: Already registered, so no submit.<br/>The session completes on its own.
    else fiat24Mode auto_register
        PB->>UR: POST /api/fma/v1/kyc/submit
        UR->>PB: Webhook fma.account.result status activated
    end
    UR->>PB: Webhook fma.additional_kyc.completed
    end
```

Part A is documented in full on [Shared-token KYC reuse](/api-reference/kyc-and-kyb/shared-token-kyc-reuse.md).
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Registration with the banking partner happens **once per user**, in part A2. That is why most retries carry `fiat24Mode: "ops_offline"` and need no `/kyc/submit`. You see `auto_register` on a retry only when the user never completed that registration, for example when their first onboarding session expired before it reached submit. In that case the retry finishes registration and you receive `fma.account.result` with `status: "activated"` in addition to `fma.additional_kyc.completed`.
{% endhint %}

## 3. Webhooks

Retry KYC uses two events. Both belong to the partner-managed (FMA) event family and are sent only to partners on an FMA integration. Subscribe to both:

| Event                          | UR sends it when                                     | You act by                                        |
| ------------------------------ | ---------------------------------------------------- | ------------------------------------------------- |
| `fma.additional_kyc.required`  | UR operations creates the directive                  | Claiming the session and guiding the user         |
| `fma.additional_kyc.completed` | The user finishes the last step of the retry session | Recording completion; no further call is required |

{% hint style="danger" %}
Subscribe to `fma.additional_kyc.required` **and** `fma.additional_kyc.completed`. UR drops an event that has no subscriber, and your platform receives nothing. Confirm both subscriptions through your dedicated integration channel before production traffic starts.
{% endhint %}

### fma.additional\_kyc.required

UR sends the following when the directive is created. Like every UR webhook, the retry events arrive in the standard `{event, data, timestamp}` envelope described in [Webhooks](https://docs.ur.app/developer-resources/webhook):

```json
{
  "event": "fma.additional_kyc.required",
  "timestamp": 1785392900,
  "data": {
    "directiveId": "62fb1d29-e584-448f-a770-9454c94dbe24",
    "type": "retry",
    "taskType": "passport",
    "retryLevel": 6,
    "fiat24Mode": "ops_offline",
    "dataChannel": "sdk",
    "partnerId": "8509",
    "externalUserId": "your-user-id",
    "urId": 5139803526,
    "retryOfSessionId": "a67efa78-da9b-4404-a77d-97f93b8085a9",
    "retryReason": "Compliance review: document expired",
    "requiredFields": [],
    "deadlineAt": 0,
    "createdAt": 1785392900
  }
}
```

The `data` fields carry the following meaning:

| Field              | Type   | Meaning                                                                                                                                                                                                                                                                                      |
| ------------------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `directiveId`      | string | Identifies this retry request. Use it to correlate the `completed` event and for support tickets.                                                                                                                                                                                            |
| `type`             | string | Always `retry` for this flow. Other values are reserved.                                                                                                                                                                                                                                     |
| `taskType`         | string | What the user must redo: `full`, `passport`, `address_recheck`, or `redo_form_a`. See section 5.                                                                                                                                                                                             |
| `retryLevel`       | number | The retry category UR operations selected. Informational; `taskType` is the field you act on.                                                                                                                                                                                                |
| `fiat24Mode`       | string | `auto_register` or `ops_offline`. Decides whether you call `/kyc/submit`. See section 6.                                                                                                                                                                                                     |
| `dataChannel`      | string | `push`, `sdk`, or `shared-token`. Matches your integration path.                                                                                                                                                                                                                             |
| `externalUserId`   | string | Your user identifier, the same value you send in `X-External-User-Id`.                                                                                                                                                                                                                       |
| `urId`             | number | The user URID, as a 64-bit integer.                                                                                                                                                                                                                                                          |
| `retryOfSessionId` | string | The session this retry replaces. That session is already sealed.                                                                                                                                                                                                                             |
| `retryReason`      | string | Free text from UR operations. Safe to show to your support staff, not to the user.                                                                                                                                                                                                           |
| `requiredFields`   | array  | Push channel only: the exact field paths to correct, for example `registerRequest.address.street`. Empty for other channels.                                                                                                                                                                 |
| `deadlineAt`       | number | Unix seconds, or `0` when no deadline is set. Informational only: UR does not expire the directive or the session when it passes, and no event fires at the deadline. Use it to prioritize your outreach to the user. The consequences of missing it are applied off-platform by compliance. |
| `createdAt`        | number | Unix seconds when UR created the directive.                                                                                                                                                                                                                                                  |

### fma.additional\_kyc.completed

UR sends the following when the retry session completes:

```json
{
  "event": "fma.additional_kyc.completed",
  "timestamp": 1785396060,
  "data": {
    "directiveId": "62fb1d29-e584-448f-a770-9454c94dbe24",
    "type": "retry",
    "taskType": "passport",
    "retryLevel": 6,
    "fiat24Mode": "ops_offline",
    "dataChannel": "sdk",
    "partnerId": "8509",
    "externalUserId": "your-user-id",
    "urId": 5139803526,
    "sessionId": "777b8122-c1d8-439d-8ca3-c8f977214bc1",
    "retryOfSessionId": "a67efa78-da9b-4404-a77d-97f93b8085a9",
    "completedAt": 1785396060
  }
}
```

Two `data` fields differ from the `required` payload:

* `sessionId` is the retry session that just completed, the same value `/kyc/session/create` returned to you.
* `retryOfSessionId` points at the session that the completed session replaced, so the two events carry different values in this field. That difference is expected.

`directiveId`, `taskType`, `retryLevel`, and `fiat24Mode` carry the same values in both events, so you can match them without extra lookups.

### Delivery and idempotency

Both events follow the standard delivery contract in [Webhooks](https://docs.ur.app/developer-resources/webhook): at-least-once delivery, signed with EIP-191, retried with jittered exponential backoff over roughly 48 hours until your endpoint returns 2xx.

Two points specific to retries:

* **Dedupe on `X-Webhook-Request-Id`**, as you do for every other UR event. That header is stable across the first delivery and every retry of the same message. Return 2xx only after you persist the event.
* **A resent directive does not produce a duplicate event.** UR keys outbound emission on a business key derived from the `directiveId` for `required` and from the `sessionId` for `completed`, so if UR operations resend a directive after a delivery incident, you receive the original message rather than a second one. This is UR-side suppression; it is not a substitute for your own idempotency on `X-Webhook-Request-Id`.

## 4. Claim the new session

Call `POST /api/fma/v1/kyc/session/create` after you receive `fma.additional_kyc.required`. UR consumes the pending directive and creates the session that carries the reduced step list:

{% tabs %}
{% tab title="Request" %}

```http
POST /api/fma/v1/kyc/session/create
X-External-User-Id: your-user-id
X-Ur-Id: 5139803526
Content-Type: application/json

{}
```

Send the partner signature headers you already use for every FMA endpoint. The body is optional: pass `{"externalUserId": "your-user-id"}` only when you cannot set the `X-External-User-Id` header.
{% endtab %}

{% tab title="Response" %}

```json
{
  "code": 0,
  "message": "",
  "data": { "sessionId": "777b8122-c1d8-439d-8ca3-c8f977214bc1" }
}
```

{% endtab %}
{% endtabs %}

Keep the following behaviors in mind:

* **Retrying the call is safe.** If your first call succeeded but you lost the response, calling again returns the same `sessionId` as long as that session is still active. UR does not create a second session.
* **The previous session is gone.** UR sealed it when operations created the directive. Calls that carry `retryOfSessionId` fail with `30006`.
* **One pending directive per user.** UR allows at most one pending directive for a user at a time.
* **Poll the state if you need it.** `GET /api/fma/v1/kyc/session/current` returns `sessionId`, `state`, and `dataChannel` for the active session.

## 5. What your users must do

The `taskType` field maps to the following user actions:

| `taskType`        | The user redoes                                           |
| ----------------- | --------------------------------------------------------- |
| `full`            | Every data collection step, as in first-time onboarding   |
| `address_recheck` | Address and location proof, then Form A                   |
| `passport`        | Identity document scan **and** face liveness, then Form A |
| `redo_form_a`     | Form A only; no data is recollected                       |

{% hint style="warning" %}
For `taskType: "passport"`, the user must complete the document scan **and** a fresh face liveness capture. UR resets both steps, because a new identity document paired with an earlier face capture would defeat the identity binding that the liveness step exists to prove. Tell your support staff to expect two steps, so they do not treat the liveness prompt as a defect.
{% endhint %}

### The state values a retry session reports

`GET /api/fma/v1/kyc/session/current` reports the step the user is on. A retry session runs a reduced step list, so it reports step names that never appear during first-time onboarding:

| Channel and `taskType`                   | `state` sequence                                                                                                                                       |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| SDK, `passport`                          | `IdOrPassportOrOtherIdInformationScan`, `IdAndLiveness`, `SignFormA`                                                                                   |
| SDK, `address_recheck`                   | `AddressProof`, `SignFormA`                                                                                                                            |
| SDK, `full`                              | `ConfirmYourCountryOfResidence`, `AddressProof`, `IdOrPassportOrOtherIdInformationScan`, `IdAndLiveness`, `SignFormA` (questionnaire steps interleave) |
| SDK or shared-token, `redo_form_a`       | `SignFormA` only                                                                                                                                       |
| Push, `full`                             | `PartnerDataIngestion`, `IdentityVerification`, `SignFormA`, plus `AwaitingPenny` when the user takes the penny transfer path                          |
| Push, `address_recheck` or `redo_form_a` | `SignFormA` only. The session starts at `SignFormA`; you patch the data with `/kyc/sync-data` while the state stays there                              |

{% hint style="danger" %}
Do not exhaustively branch on `state`. If your onboarding code treats the onboarding state set as closed, or fails on an unrecognized value, a retry session will break it. Treat any unrecognized `state` as "the user has a step left to do", and drive your integration from `taskType` and from the endpoint responses instead. `Completed` and `Failed` remain the only terminal values.
{% endhint %}

### Push channel

{% stepper %}
{% step %}
**Claim the session**

Call `POST /api/fma/v1/kyc/session/create` and store the returned `sessionId`.
{% endstep %}

{% step %}
**Resubmit the data**

Call `POST /api/fma/v1/kyc/sync-data`. When `requiredFields` is non-empty, send only those paths; UR merges them into the stored snapshot. When `requiredFields` is empty and `taskType` is `full`, send the complete payload, because UR starts the snapshot empty for a full retry.
{% endstep %}

{% step %}
**Complete identity verification**

Run the identity verification step your integration uses, either the penny transfer or the NFC document read. Only `taskType: "full"` includes this step on the push channel. When `state` goes straight to `SignFormA`, skip it.
{% endstep %}

{% step %}
**Sign Form A**

Call `GET /api/fma/v1/kyc/form-a-info` with the `sessionId`, present the text to the user, then call `POST /api/fma/v1/kyc/sign-form` with the `sessionId` and `textHash`.
{% endstep %}

{% step %}
**Finish the session**

Follow section 6: call `POST /api/fma/v1/kyc/submit` only when `fiat24Mode` is `auto_register`.
{% endstep %}
{% endstepper %}

### SDK channel

{% stepper %}
{% step %}
**Claim the session**

Call `POST /api/fma/v1/kyc/session/create` and store the returned `sessionId`.
{% endstep %}

{% step %}
**Request a Sumsub access token**

Call `POST /api/fma/v1/kyc/sumsub-access-token` with an empty body. Set your client timeout to **60 seconds or more**: before UR issues the token, UR resets the specific Sumsub steps the retry targets and verifies that each reset took effect, which can take up to 30 seconds. If your call still times out, the server side usually finished; call again to get the token.
{% endstep %}

{% step %}
**Launch the Sumsub SDK**

Relay the token to your app and launch the SDK. The SDK stops at the step or steps the retry targets, not the whole workflow. The user submits that data and the SDK finishes.
{% endstep %}

{% step %}
**Sign Form A**

Call `GET /api/fma/v1/kyc/form-a-info` with the `sessionId`, then `POST /api/fma/v1/kyc/sign-form` with the `sessionId` and `textHash`. Poll `GET /api/fma/v1/kyc/session/current` until `state` is `SignFormA` if you need a trigger.
{% endstep %}

{% step %}
**Finish the session**

Follow section 6: call `POST /api/fma/v1/kyc/submit` only when `fiat24Mode` is `auto_register`.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
If the SDK opens and closes immediately without asking the user for anything, stop and report it through your dedicated integration channel with the `directiveId`. A retry session must always ask the user for the targeted step. An immediate completion means the data was not recollected, and the result is not valid for the compliance review that triggered the retry.
{% endhint %}

### Shared-token channel

{% stepper %}
{% step %}
**Claim the session**

Call `POST /api/fma/v1/kyc/session/create` and store the returned `sessionId`.
{% endstep %}

{% step %}
**Have the user redo KYC in your Sumsub tenant**

Run the steps that `taskType` names in your own workflow, then mint a fresh single-use share token scoped to UR's `clientId`. A token you minted for the earlier session is not valid for the retry session.
{% endstep %}

{% step %}
**Hand off the share token**

Call `POST /api/fma/v1/kyc/reuse-share-token` with the new `sessionId` and the fresh token, then read the verdict with `POST /api/fma/v1/kyc/check`.
{% endstep %}

{% step %}
**Sign Form A**

Call `GET /api/fma/v1/kyc/form-a-info`, then `POST /api/fma/v1/kyc/sign-form`.
{% endstep %}

{% step %}
**Finish the session**

Follow section 6: call `POST /api/fma/v1/kyc/submit` only when `fiat24Mode` is `auto_register`.
{% endstep %}
{% endstepper %}

## 6. How the session finishes: fiat24Mode

`fiat24Mode` reflects whether the retry session includes the Fiat24 registration step. A user can register with Fiat24 exactly once in their lifetime, so UR includes that step only for a user who never completed it:

| `fiat24Mode`    | Registration step | Your last call                   | How the session ends                                                                                                                              |
| --------------- | ----------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `auto_register` | Included          | `POST /api/fma/v1/kyc/submit`    | UR runs the registration, then sends `fma.additional_kyc.completed`                                                                               |
| `ops_offline`   | Not included      | `POST /api/fma/v1/kyc/sign-form` | The session completes on its own after the last step, then UR sends `fma.additional_kyc.completed`. UR operations handles the Fiat24 side offline |

{% hint style="warning" %}
Do not call `POST /api/fma/v1/kyc/submit` when `fiat24Mode` is `ops_offline`. The call fails with `30007`, and the session needs no submit: it completes after the last step. Branch on `fiat24Mode` rather than always calling submit.
{% endhint %}

## 7. Two fields named retryLevel

The webhook payload and `GET /api/fma/v1/kyc/session/current` both return a field named `retryLevel`, and the two values mean different things:

| Source                                                 | Meaning                                                               | Example                        |
| ------------------------------------------------------ | --------------------------------------------------------------------- | ------------------------------ |
| `fma.additional_kyc.required` and `.completed` payload | The retry category UR operations selected                             | `6` for a document rescan      |
| `GET /api/fma/v1/kyc/session/current` response         | How many sessions the user has had, where `0` is the first onboarding | `2` for the user third session |

Read the retry category from the webhook payload, and read `taskType` when you need to know what the user must do. Do not derive either one from `session/current`.

## 8. Integration checklist

Confirm the following before you handle production retries:

* Your webhook endpoint subscribes to `fma.additional_kyc.required` and `fma.additional_kyc.completed`.
* Your webhook handler is idempotent on `X-Webhook-Request-Id` and returns 2xx only after it persists the event.
* Your client timeout for `POST /api/fma/v1/kyc/sumsub-access-token` is 60 seconds or more, on the SDK channel.
* Your code branches on `fiat24Mode` and calls `/kyc/submit` only for `auto_register`.
* Your code branches on `taskType`, and your support flow expects a liveness capture whenever `taskType` is `passport`.
* Your code drops any `sessionId` you cached for the user when a retry directive arrives, and uses the `sessionId` from `/kyc/session/create`.
* Your code treats `deadlineAt` as informational and does not block the user after it passes.

## 9. Error reference

The endpoints in this flow return HTTP 200 with a business code. The following codes are specific to retry KYC:

| Code    | Meaning                                                | What to do                                                                                                                                                                                               |
| ------- | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `30034` | No pending retry directive for this user               | No retry is pending. Do not create a session speculatively; wait for `fma.additional_kyc.required`. Check that your signature headers identify the same `partnerId` and `externalUserId` as the webhook. |
| `30006` | `sessionId` not found                                  | The session is sealed, or it belongs to another user or partner. Claim the retry session and use its `sessionId`.                                                                                        |
| `30031` | No active KYC session for this user                    | The user has no active session. Claim the retry session first.                                                                                                                                           |
| `30007` | Session state does not allow this call                 | For `/kyc/submit`, this means the retry flow has no registration step, so the mode is `ops_offline`. Skip the submit; the session completes on its own.                                                  |
| `20007` | Form A cannot render because stored data is incomplete | On the push channel, resubmit the missing paths with `/kyc/sync-data`. On other channels, report the `directiveId` through your dedicated integration channel.                                           |
| `40003` | A UR dependency is momentarily unavailable             | Retry the call after a few seconds.                                                                                                                                                                      |

## 10. Glossary

| Term            | Definition                                                                                                     |
| --------------- | -------------------------------------------------------------------------------------------------------------- |
| Retry directive | The record UR operations creates to request a retry. Identified by `directiveId`.                              |
| Retry session   | The session UR creates when you call `/kyc/session/create` for a pending directive. Identified by `sessionId`. |
| `taskType`      | The authoritative description of what the user must redo in this retry.                                        |
| `fiat24Mode`    | Whether the retry session includes Fiat24 registration, and therefore whether you call `/kyc/submit`.          |
| Form A          | The declaration text the user signs before UR can act on the KYC data.                                         |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ur.app/api-reference/kyc-and-kyb/retry-kyc.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
