> ## 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.

# Provision an application

> Creates an application for one of your merchants under your own id for it, screens its names, and either queues it for review or activates it at once, according to your approval mode. Idempotent on `external_id`: provisioning the same id again answers `200` with the application as it stands and applies nothing from the new body, so an install that runs twice is safe.

Guide: [Applications](https://docs.tawked.com/partners/applications.md)


## OpenAPI

````yaml https://tawked.com/openapi.json post /v1/partner/applications
openapi: 3.1.0
info:
  title: Tawked API
  version: 2026-09
  summary: >-
    Tawked Verify: OTP verification for Saudi mobile numbers over SMS, in two
    calls. Tawked Notifications: WhatsApp template messages from the
    application's own number. Tawked Email: transactional e-mail from the
    application's own verified domain. Tawked Chat: the conversation menus a
    connected app adds beside the conversations of its connection's application,
    and the auto-attendant it sets up there. The Partner API for platforms that
    run Tawked Verify for their merchants.
  description: >-
    The public API of Tawked, a Saudi messaging platform: Tawked Verify
    (one-time codes), Tawked Notifications (WhatsApp templates from the
    application's own number), Tawked Email (transactional e-mail from the
    application's own domain) and the Partner API. Tawked Verify is an OTP
    verification API for Saudi numbers. One call sends a one-time code by SMS to
    a Saudi mobile number, and a second call checks it. SAR 0.09 per SMS code
    sent, prepaid; a send the network refuses is refunded. Authenticate with a
    Bearer API key from the dashboard (tk_live_ for production, tk_test_ for the
    sandbox, tk_partner_ for partners, tk_partner_test_ for the partner
    sandbox). Partners (tk_partner_) provision a Verify application per merchant
    under /v1/partner/applications and name it as application on every Verify
    call. 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
    x-group: Verify
    description: Send and check one-time codes.
  - name: WhatsApp
    x-group: Notifications
    description: >-
      Tawked Notifications: send approved WhatsApp templates through the number
      connected to an application. An application in review or approved connects
      its own number from the dashboard.
  - name: Email
    x-group: Email
    description: >-
      Tawked Email: send transactional e-mail from an address on a verified
      domain of the application, to up to 50 recipients a message, in batches or
      scheduled, and read and list what was sent. Live keys only.
  - name: Chat
    x-group: Chat
    description: >-
      Tawked Chat: the conversation menus a connected app adds beside the
      conversations of its connection's application, and reads, changes and
      removes, with `chat:menus`; and the application's auto-attendant, which a
      connected app sets up, publishes and switches on or off, with
      `chat:attendant`. A connected app's key only; a business adds its own
      menus and builds its auto-attendant in the console.
  - name: Partner
    x-group: Partner API
    description: >-
      For platforms that run Tawked Verify for their merchants: provision a
      Verify application per merchant, keep its brand and verify settings
      current, switch it off and on, and read usage and the code log. Partner
      keys (tk_partner_) only; every Verify operation then takes `application`
      with the partner's own id for the application.
  - name: Webhooks
    x-group: Webhooks
    description: >-
      The events Tawked sends to your endpoint: an application's verification
      outcomes and message statuses, and a partner account's lifecycle, balance
      and opt-in verification events. Every delivery is signed the same way and
      retried the same way.
externalDocs:
  description: Developer docs, with code samples
  url: https://docs.tawked.com
paths:
  /v1/partner/applications:
    post:
      tags:
        - Partner
      summary: Provision an application
      description: >-
        Creates an application for one of your merchants under your own id for
        it, screens its names, and either queues it for review or activates it
        at once, according to your approval mode. Idempotent on `external_id`:
        provisioning the same id again answers `200` with the application as it
        stands and applies nothing from the new body, so an install that runs
        twice is safe.
      operationId: partner_provision
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            A 1 to 128 printable-ASCII key you generate, scoped to your API key.
            Replaying it with the same request answers the original 2xx
            unchanged, with the response header `Idempotent-Replayed: true`, and
            runs nothing again; the same key with another request answers `409
            idempotency_key_reused`, and a request still in flight `409
            idempotency_in_progress`. A refused request is never stored, so a
            corrected retry under the same key runs. Keys expire after 24 hours.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                external_id:
                  type: string
                  description: >-
                    Your own id for the merchant or store, 1 to 128 characters
                    after trimming. Every later call addresses the application
                    by it, and it is the `application` value on the Verify
                    endpoints.
                name_ar:
                  type: string
                  description: >-
                    The Arabic brand name end users see in their messages, 1 to
                    80 characters. Screened against protected brands and bait
                    words.
                name_en:
                  type: string
                  description: >-
                    The English brand name, 1 to 80 characters. Screened like
                    `name_ar`.
                website:
                  type: string
                  description: >-
                    The merchant's website, an `http` or `https` URL. The
                    autofill domain is derived from it (its registrable domain)
                    and is read-only; `website_url` is accepted as an alias.
                industry:
                  type: string
                  description: >-
                    Free text up to 64 characters, `other` when omitted. The
                    client console uses `ecommerce`, `fintech`, `healthcare`,
                    `education`, `logistics`, `saas`, `marketplace` and `other`.
                merchant:
                  type: object
                  description: >-
                    Your own record of the merchant (a registration number, a
                    contact, a KYC state), stored with the application exactly
                    as given and never validated for shape.
                verify:
                  type: object
                  description: >-
                    Initial verify settings: any subset of the fields of the
                    verify-settings endpoint, the defaults for the rest. A
                    refused value is reported in `fields` as `verify.` followed
                    by the field name. Ignored when the application already
                    exists.
                metadata:
                  type: object
                  description: >-
                    Your own tags on the application: up to 20 string values of
                    at most 200 characters under keys of 1 to 40 lowercase
                    letters, digits and underscores. Replaced whole when
                    present, unchanged when omitted, cleared by `null` or `{}`;
                    never read by Tawked and not a brand change. A refused key
                    is reported in `fields` as `metadata.` followed by the key.
                    The list filters by it.
              required:
                - external_id
                - name_ar
                - name_en
                - website
      responses:
        '200':
          description: Already provisioned
          content:
            application/json:
              schema:
                type: object
                properties:
                  service_id:
                    type: string
                  application_id:
                    type: string
                  external_id:
                    type: string
                  status:
                    type: string
                  screening:
                    type: object
                    properties:
                      result:
                        type: string
                      rules:
                        type: array
                        items:
                          type:
                            - string
                            - 'null'
                  verify:
                    type: object
                    properties:
                      code_length:
                        type: integer
                      ttl_seconds:
                        type: integer
                      max_attempts:
                        type: integer
                      max_per_hour:
                        type: integer
                      autofill_domain:
                        type: string
                      autofill_domain_enabled:
                        type: boolean
                      android_app_hash:
                        type:
                          - string
                          - 'null'
                      daily_spend_cap_halalas:
                        type:
                          - string
                          - 'null'
                      max_per_ip_per_hour:
                        type: integer
                      max_new_destinations_per_hour:
                        type: integer
                  paused:
                    type: boolean
              examples:
                already_provisioned:
                  summary: Already provisioned
                  value:
                    service_id: c2a10f3e-8b7a-4d2e-9c1a-1a2b3c4d5e6f
                    application_id: c2a10f3e-8b7a-4d2e-9c1a-1a2b3c4d5e6f
                    external_id: store_88
                    status: active
                    screening:
                      result: clean
                      rules: []
                    verify:
                      code_length: 6
                      ttl_seconds: 300
                      max_attempts: 3
                      max_per_hour: 5
                      autofill_domain: flowers.example
                      autofill_domain_enabled: true
                      android_app_hash: null
                      daily_spend_cap_halalas: null
                      max_per_ip_per_hour: 20
                      max_new_destinations_per_hour: 300
                    paused: false
        '201':
          description: Provisioned, in review / Provisioned, active at once
          content:
            application/json:
              schema:
                type: object
                properties:
                  service_id:
                    type: string
                  application_id:
                    type: string
                  external_id:
                    type: string
                  status:
                    type: string
                  screening:
                    type: object
                    properties:
                      result:
                        type: string
                      rules:
                        type: array
                        items:
                          type:
                            - string
                            - 'null'
                  verify:
                    type: object
                    properties:
                      code_length:
                        type: integer
                      ttl_seconds:
                        type: integer
                      max_attempts:
                        type: integer
                      max_per_hour:
                        type: integer
                      autofill_domain:
                        type: string
                      autofill_domain_enabled:
                        type: boolean
                      android_app_hash:
                        type:
                          - string
                          - 'null'
                      daily_spend_cap_halalas:
                        type:
                          - string
                          - 'null'
                      max_per_ip_per_hour:
                        type: integer
                      max_new_destinations_per_hour:
                        type: integer
                  paused:
                    type: boolean
              examples:
                provisioned_in_review:
                  summary: Provisioned, in review
                  value:
                    service_id: c2a10f3e-8b7a-4d2e-9c1a-1a2b3c4d5e6f
                    application_id: c2a10f3e-8b7a-4d2e-9c1a-1a2b3c4d5e6f
                    external_id: store_88
                    status: review
                    screening:
                      result: clean
                      rules: []
                    verify:
                      code_length: 6
                      ttl_seconds: 300
                      max_attempts: 3
                      max_per_hour: 5
                      autofill_domain: flowers.example
                      autofill_domain_enabled: true
                      android_app_hash: null
                      daily_spend_cap_halalas: null
                      max_per_ip_per_hour: 20
                      max_new_destinations_per_hour: 300
                    paused: false
                provisioned_active_at_once:
                  summary: Provisioned, active at once
                  value:
                    service_id: c2a10f3e-8b7a-4d2e-9c1a-1a2b3c4d5e6f
                    application_id: c2a10f3e-8b7a-4d2e-9c1a-1a2b3c4d5e6f
                    external_id: store_88
                    status: active
                    screening:
                      result: clean
                      rules: []
                    verify:
                      code_length: 6
                      ttl_seconds: 300
                      max_attempts: 3
                      max_per_hour: 5
                      autofill_domain: flowers.example
                      autofill_domain_enabled: true
                      android_app_hash: null
                      daily_spend_cap_halalas: null
                      max_per_ip_per_hour: 20
                      max_new_destinations_per_hour: 300
                    paused: false
        '400':
          description: >-
            Refused fields / `invalid_json`: The request body is not valid
            JSON.; `invalid_request`: A field is missing or refused. `fields`
            names them: bare names on the verify-settings endpoint (`verify`
            alone for an empty or unrecognised patch), `verify.` followed by the
            field name for a setting refused on provision or a brand update,
            `metadata.` followed by the key for a refused tag (`metadata` alone
            for a wrong shape, on a write or on the list filter), `logo` for a
            missing, oversized or non-image file, `events` for an unknown event
            name, `url` or `secret` on the webhook (console-only, with
            `message`), `cursor`, `since`, `event` or `status` on the feeds; on
            usage, `message` says that `from` and `to` must be ISO dates; a
            malformed `Idempotency-Key` header is refused with `message` too.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - invalid_json
                          - invalid_request
              examples:
                refused_fields:
                  summary: Refused fields
                  value:
                    error: invalid_request
                    fields:
                      - external_id
                      - website
                      - verify.code_length
        '401':
          description: >-
            `unauthorized`: Missing, unknown or revoked key; a key of another
            mode (`tk_live_` and `tk_test_` keys cannot call the partner API);
            or a partner account Tawked suspended.; `key_expired`: The key's
            `expires_at` has passed. Checked right after the key is recognised.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - unauthorized
                          - key_expired
        '403':
          description: >-
            `ip_not_allowed`: The caller's IP is outside the key's allowlist.;
            `partner_suspended`: Your partner account was suspended by Tawked
            between the key check and the write. In practice the key already
            answers `401 unauthorized`; this is defense in depth.;
            `live_key_required`: A `tk_partner_test_` key on a management write.
            The sandbox key reads every partner endpoint and sends; use your
            live key to change anything.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - ip_not_allowed
                          - partner_suspended
                          - live_key_required
        '409':
          description: >-
            `idempotency_in_progress`: A request with this `Idempotency-Key` is
            still running. Wait for its answer, or retry in a moment.;
            `idempotency_key_reused`: This `Idempotency-Key` was already used
            for a different request (another body, path or method). Use one key
            per business event.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - idempotency_in_progress
                          - idempotency_key_reused
        '429':
          description: >-
            `too_many_requests`: Per-key rate limit exceeded (120 requests per
            minute, fixed 60-second window). Checked before authentication.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - too_many_requests
        '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
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            curl -X POST https://tawked.com/v1/partner/applications \
              -H "Authorization: Bearer tk_partner_xxxxxxxxxxxxxxxxxxxx" \
              -H "Content-Type: application/json" \
              -d '{
                "external_id": "store_88",
                "name_ar": "متجر الورد",
                "name_en": "Flower Shop",
                "website": "https://flowers.example",
                "industry": "ecommerce",
                "merchant": {
                    "registration_number": "1010123456",
                    "contact_email": "owner@flowers.example"
                },
                "verify": {
                    "code_length": 6,
                    "ttl_seconds": 300
                }
            }'
        - lang: javascript
          label: Node.js
          source: >-
            const res = await
            fetch("https://tawked.com/v1/partner/applications", {
              method: "POST",
              headers: {
                Authorization: "Bearer tk_partner_xxxxxxxxxxxxxxxxxxxx",
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                  "external_id": "store_88",
                  "name_ar": "متجر الورد",
                  "name_en": "Flower Shop",
                  "website": "https://flowers.example",
                  "industry": "ecommerce",
                  "merchant": {
                      "registration_number": "1010123456",
                      "contact_email": "owner@flowers.example"
                  },
                  "verify": {
                      "code_length": 6,
                      "ttl_seconds": 300
                  }
              }),
            });

            const data = await res.json();
        - lang: python
          label: Python
          source: |-
            import requests

            res = requests.post(
                "https://tawked.com/v1/partner/applications",
                headers={"Authorization": "Bearer tk_partner_xxxxxxxxxxxxxxxxxxxx"},
                json={
                    "external_id": "store_88",
                    "name_ar": "متجر الورد",
                    "name_en": "Flower Shop",
                    "website": "https://flowers.example",
                    "industry": "ecommerce",
                    "merchant": {
                        "registration_number": "1010123456",
                        "contact_email": "owner@flowers.example"
                    },
                    "verify": {
                        "code_length": 6,
                        "ttl_seconds": 300
                    }
                },
            )
            data = res.json()
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>. An application key (tk_live_, tk_test_)
        has full access, which covers every product and any product added later,
        or custom access, chosen when the key is created: one or more of the
        scopes `verify:check`, `verify:send` (includes `verify:check`),
        `notifications:read`, `notifications:send` (includes
        `notifications:read`), `email:read`, `email:send` (includes
        `email:read`), `email:manage` (includes `email:send`),
        `webhooks:manage`, `email:inbound`, `notifications:templates` (includes
        `notifications:read`), `chat:menus`, `chat:attendant`. No key made on
        the API keys page holds `notifications:templates`, full access included:
        the three template writes answer such a key 403 `insufficient_scope`. A
        connected app's key holds it. Nor `chat:menus`: the five conversation
        menu operations answer such a key 403 `insufficient_scope`, and a
        connected app's key holds it once the client approved it. Nor
        `chat:attendant`: the five auto-attendant operations answer such a key
        403 `insufficient_scope` too, and a connected app's key holds it once
        the client approved it. `email:manage` and `webhooks:manage` are held
        only by a key someone chose them for: a full-access key, old or new,
        never holds them. `email:inbound`, which reads, deletes and forwards
        received e-mail, is opt-in on every key, full access included: a key
        holds it only when it was turned on when the key was created. A call
        outside the key's access answers 403 `insufficient_scope` and names the
        scope it needs in the `WWW-Authenticate` response header. A partner key
        (tk_partner_) always has full access. Whatever its access, a key is a
        server-side secret.
    headerKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        The same API key, with the same access, as a header, for clients that
        cannot set Authorization.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.