---
title: "Submit for verification"
method: POST
path: "/v0/customers/{id}/kyc/submit"
tags: ["Customers"]
---

# Submit for verification

`POST /v0/customers/{id}/kyc/submit`

## Request

- Base URL: `https://orchestration.seismic.systems/api`
- URL: `https://orchestration.seismic.systems/api/v0/customers/{id}/kyc/submit`
- Auth: API key in header `Api-Key`

Validate the saved profile and submit it for verification. In production, every submission is reviewed by Seismic before verification begins: the status reads `submitted` during that review and moves to `under_review` once verification starts. A submission the review declines reads `terminally_rejected` with a `rejection_reason`; that decision is final and further submissions are refused. In sandbox there is no review step. Submissions approve immediately and emit the corresponding status webhook by default; a customer created with `sandbox_auto_approve_kyc=false` instead advances through randomized asynchronous status updates. If a previous verification was rejected, correct the saved profile and submit again — Seismic re-submits the same customer with your changes rather than creating a duplicate. A repeat submit while one is already in flight returns the current state. An approved customer can be resubmitted too, but only by explicit opt-in: edit the saved profile, then submit with `?resubmit_approved=1` — the updated details are re-verified, and the status may move back to review until the re-check completes. Without the flag a submit never touches an approved verification; with the flag but no profile change it is a no-op that returns the current state.

## Path parameters

- `id` string, uuid, required

## Query parameters

- `resubmit_approved` boolean

## Request body

- SubmitRequest: Body shared by the submit endpoints that accept acceptance context.
  - `end_user` EndUserContext: Where the end user was when they accepted the terms. Supply this from a server-to-server integration, where the end user's browser never reaches us directly. All three fields are optional, and each is recorded as-is against the filing.
    - `device_fingerprint` string, nullable: An opaque identifier for the device they accepted on. Any printable encoding up to 128 characters — we record and display it, never parse it, so the identifier your own client library produces is fine.
    - `ip_address` string, nullable: The address the end user accepted the terms from, v4 or v6.
    - `user_agent` string, nullable: The user agent of the browser they accepted in: the `User-Agent` header your own servers received from it, or `navigator.userAgent`. Printable ASCII up to 512 characters.

## Response `200`

State after submission.

- union: `POST /v0/customers/:id/kyc/{submit,resync}` + `GET /v0/customers/:id/kyc/state`.
  - object
    - `state` KycState, required: Rolled-up KYC verification state for an individual customer.
      - `kyc_link` KycLink: Hosted verification link for the customer to complete KYC.
        - `expires_at` string, date-time, nullable
        - `url` string, required
      - `kyc_status` 'draft' | 'submitted' | 'under_review' | 'action_required' | 'approved' | 'rejected' | 'terminally_rejected' | 'paused' | 'unknown', required
      - `last_submitted_at` string, date-time, nullable: When the profile was last filed for verification, or `null` if it never has been. Moves on every submission that reaches verification, so a resubmission is visible even though the status it lands in is the same one it left.
      - `last_synced_at` string, date-time, required
      - `missing_fields` string[], required
      - `pending_rfi` boolean: `true` while an open request for information is outstanding on this verification. Raised by Seismic compliance and independent of the status, so it can be `true` at any status; answering every open item clears it. Resubmitting the profile does not.
      - `rejection_reason` string, nullable
      - `resubmit_available` boolean: Whether submitting again would re-file part of this verification for review. `false` before the first submission.
    - `type` 'individual', required
  - object
    - `state` KybState, required: Rolled-up KYB verification state for a business customer.
      - `kyb_link` KybLink: Hosted verification link for the business to complete KYB.
        - `expires_at` string, date-time, nullable
        - `url` string, required
      - `kyb_status` 'draft' | 'submitted' | 'under_review' | 'action_required' | 'approved' | 'rejected' | 'terminally_rejected' | 'paused' | 'unknown', required
      - `last_submitted_at` string, date-time, nullable: When the profile was last filed for verification, or `null` if it never has been. Moves on every submission that reaches verification, so a resubmission is visible even though the status it lands in is the same one it left.
      - `last_synced_at` string, date-time, required
      - `missing_fields` string[], required
      - `pending_rfi` boolean: `true` while an open request for information is outstanding on this verification. Raised by Seismic compliance and independent of the status, so it can be `true` at any status; answering every open item clears it. Resubmitting the profile does not.
      - `rejection_reason` string, nullable
      - `resubmit_available` boolean: Whether submitting again would re-file part of this verification for review. `false` before the first submission.
    - `type` 'business', required

## Other responses

- `400`: The supplied terms-acceptance context is unusable.
- `401`: Missing or invalid API key.
- `403`: The organization's KYB verification is not approved, so customers cannot be registered yet.
- `404`: Customer not found.
- `409`: Verification is paused by a compliance hold, or a resubmission carried no changes.
- `422`: Profile incomplete — the error carries the missing field paths.

---

[API](https://skmtc.dev/seismic/apis/seismic-orchestration-api.md) - [All operations](https://skmtc.dev/seismic/apis/seismic-orchestration-api/llms.txt) - [OpenAPI document](https://skmtc.dev/seismic/apis/seismic-orchestration-api/revisions/08ada1f159fa?raw)
