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

# Start a verification

> Sends a one-time code to a destination and returns an id to check it against.



## OpenAPI

````yaml https://tawked.com/openapi.json post /v1/verify/start
openapi: 3.1.0
info:
  title: Tawked Verify API
  version: 2026-09
  summary: >-
    OTP verification for Saudi mobile numbers over SMS or WhatsApp, in two
    calls.
  description: >-
    Tawked is a Saudi OTP verification API: one request sends a code by SMS or
    WhatsApp to a Saudi mobile number, one request checks it. Built in Jeddah,
    billed only per delivered code. SAR 0.09 per delivered SMS code, prepaid;
    failed sends are not charged. Authenticate with a Bearer API key from the
    dashboard (tk_live_ for production, tk_test_ for the sandbox, tk_partner_
    for partners). Both /v1/... and /api/v1/... answer identically. Rate limit:
    120 requests per minute per key.
  termsOfService: https://tawked.com/en/terms
  license:
    name: Proprietary (Tawked terms of service)
    url: https://tawked.com/en/terms
  contact:
    name: Tawked support
    email: support@tawked.com
    url: https://tawked.com/en/contact
servers:
  - url: https://tawked.com
    description: Production (the sandbox is a tk_test_ key on the same host)
  - url: https://tawked.com/api
    description: The same API under /api/v1/..., kept for older integrations
security:
  - bearerKey: []
  - headerKey: []
tags:
  - name: Verify
    description: Send and check one-time codes.
  - name: WhatsApp
    description: >-
      Send approved WhatsApp templates through the number connected to an
      application; any approved application connects its own number from the
      dashboard.
externalDocs:
  description: Developer docs, with code samples
  url: https://tawked.com/en/docs
paths:
  /v1/verify/start:
    post:
      tags:
        - Verify
      summary: Start a verification
      description: >-
        Sends a one-time code to a destination and returns an id to check it
        against.
      operationId: start
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            A 1–128 printable-ASCII-character key you generate, scoped to your
            API key (and, for a partner key, to the named application too).
            Replaying the same key returns the original `201` response
            unchanged, with the response header `Idempotent-Replayed: true` —
            nothing is sent or charged again. A send that fails releases the key
            so a retry can go through.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                to:
                  type: string
                  description: >-
                    The destination. Any of the accepted Saudi mobile formats
                    below.
                phone:
                  type: string
                  description: >-
                    Deprecated alias for `to`, kept for pre-multichannel
                    integrations. Only used when `to` is absent or blank; `to`
                    always wins when both are present. New integrations should
                    use `to`.
                  deprecated: true
                channel:
                  type: string
                  description: >-
                    Delivery channel. Defaults to "sms" when absent or blank —
                    "sms" is the only channel live over this API today.
                lang:
                  type: string
                  description: >-
                    Message language. Only the literal value "en" selects
                    English; anything else (including missing) defaults to
                    Arabic.
                application:
                  type: string
                  description: >-
                    Partner keys only: which of your provisioned applications is
                    sending. The legacy field name `service` is accepted
                    identically.
                reference:
                  type: string
                  description: >-
                    Your own reference (order id, request id, …), up to 64
                    printable characters. Echoed back on `start` and on `GET
                    /v1/verify/{id}`, and searchable in the dashboard's
                    verifications list.
                client_ip:
                  type: string
                  description: >-
                    The end user's IP address. Enables the per-IP protection
                    guard for this application when one is configured — never
                    inferred from the request, always explicit.
                autofill:
                  type: string
                  description: >-
                    `web`, `android` or `none` — which autofill line(s) to
                    include on this send. `web` sends only the `@domain #code`
                    line, `android` only the app-hash line, `none` sends
                    neither. Omit it to send every line the application has
                    configured.
              required:
                - to
      responses:
        '201':
          description: Started
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  status:
                    type: string
                  expires_at:
                    type: string
                    format: date-time
              examples:
                started:
                  summary: Started
                  value:
                    id: b7e5c2b0-9c1a-4e2f-8f2a-3a6b0e9d1c44
                    status: pending
                    expires_at: '2026-09-01T12:34:56.789Z'
        '400':
          description: >-
            `service_required`: Partner key used with no `application` (or
            `service`) in the request body.; `invalid_json`: The request body is
            not valid JSON.; `invalid_request`: start: `to` (and `phone`) both
            missing or blank. check: `id` or `code` missing.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - service_required
                          - invalid_json
                          - invalid_request
        '401':
          description: >-
            `unauthorized`: Missing, unknown, revoked, or mode-mismatched key;
            or an unknown/suspended partner.; `key_expired`: The key's
            `expires_at` has passed. Checked right after the key is recognised,
            before the IP allowlist or scope.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - unauthorized
                          - key_expired
        '402':
          description: >-
            `insufficient_credits`: The account's prepaid balance is below the
            channel price.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - insufficient_credits
        '403':
          description: >-
            `account_not_active`: The application is not approved yet, the
            account is banned, or a partner disabled this application. All four
            causes share this one response.; `ip_not_allowed`: The caller's IP
            does not match the key's `ip_allowlist` (exact IPs and/or CIDR
            ranges, IPv4 and IPv6).; `insufficient_scope`: A `check`-scoped key
            called anything but `check` or `GET /v1/verify/{id}`.;
            `application_paused`: The application is auto-paused by the pumping
            guard (a spike in distinct new destinations within an hour). The
            owner or an admin must resume it.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - account_not_active
                          - ip_not_allowed
                          - insufficient_scope
                          - application_paused
        '404':
          description: >-
            `service_not_found`: Partner key, but `application`/`service` does
            not match any of that partner's provisioned applications.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - service_not_found
        '422':
          description: >-
            `unsupported_channel`: Unknown channel name, or a known channel that
            is not live (e.g. WhatsApp before its credentials are configured, or
            email — retired).; `sandbox_unsupported_channel`: A sandbox
            (tk_test_) key on a channel that cannot carry the [TEST] stamp
            (WhatsApp's fixed Meta template has no room for it).;
            `invalid_destination`: The destination does not match any accepted
            Saudi mobile format.; `sandbox_unverified_destination`: Sandbox key,
            and the destination is not on the account's proven-ownership
            allowlist.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - unsupported_channel
                          - sandbox_unsupported_channel
                          - invalid_destination
                          - sandbox_unverified_destination
        '429':
          description: >-
            `too_many_requests`: Per-key rate limit exceeded (default 120
            requests/minute, fixed 60s window). Checked before authentication.;
            `sandbox_quota_exceeded`: The application's lifetime sandbox send
            cap (10) is reached.; `rate_limited`: The per-destination hourly cap
            is reached. Distinct from too_many_requests above — same HTTP
            status, different `error` string.; `ip_rate_limited`: The caller
            passed `client_ip`, and that address sent more starts in the last
            hour than the application's `max_per_ip_per_hour` allows.;
            `spend_cap_reached`: Today's charges (Riyadh calendar day) plus this
            send would pass the application's `daily_spend_cap_halalas`.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - too_many_requests
                          - sandbox_quota_exceeded
                          - rate_limited
                          - ip_rate_limited
                          - spend_cap_reached
        '500':
          description: >-
            `internal_error`: An unhandled server error. Quote the X-Request-Id
            header if you report it.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - internal_error
        '502':
          description: >-
            `send_failed`: The delivery provider call threw. The charge is
            refunded automatically.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - send_failed
components:
  schemas:
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: A stable machine-readable code; the docs list every one.
      additionalProperties: true
  securitySchemes:
    bearerKey:
      type: http
      scheme: bearer
      description: 'Authorization: Bearer <api key>'
    headerKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        The same API key, as a header, for clients that cannot set
        Authorization.

````