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

# Send an email

> Sends one message to one recipient from an address on a verified domain of the key's application, and answers `202` with an id to track it. The price is charged at the send and refunded once if the message bounces or fails; a complaint keeps it.

Guide: [Sending email](/email/messages)


## OpenAPI

````yaml https://tawked.com/openapi.json post /v1/email/messages
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. 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 one transactional message per call from an address on a
      verified domain of the application, and read its status. Live keys only.
  - 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/email/messages:
    post:
      tags:
        - Email
      summary: Send an email
      description: >-
        Sends one message to one recipient from an address on a verified domain
        of the key's application, and answers `202` with an id to track it. The
        price is charged at the send and refunded once if the message bounces or
        fails; a complaint keeps it.
      operationId: email_send
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            A 1 to 128 printable-ASCII-character key you generate, scoped to
            your API key, as on WhatsApp messages. Replaying the same key
            returns the original `202` unchanged, with the response header
            `Idempotent-Replayed: true`: nothing is sent or charged again. A
            send that fails with `502` releases the key.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                from:
                  type: object
                  description: >-
                    `{ "name": "…", "address": "…" }`. `address` must be on a
                    verified domain of this application, any local part.
                    Omitted, `name` is the domain's default from name and
                    `address` its default local part (`no-reply` unless changed)
                    on the application's verified domain.
                to:
                  type: string
                  description: >-
                    One recipient: a syntactically valid e-mail address. One
                    recipient per call.
                subject:
                  type: string
                  description: The subject line, 1 to 255 characters.
                html:
                  type: string
                  description: >-
                    The HTML body. Give `html`, `text` or both; together they
                    are at most 512 KiB.
                text:
                  type: string
                  description: >-
                    The plain-text body, shown by clients that do not render
                    HTML. Give `html`, `text` or both.
                reply_to:
                  type: string
                  description: 'Where replies go: any valid address, on your domain or not.'
                reference:
                  type: string
                  description: >-
                    Your own reference (order id, event id), 1 to 64 printable
                    characters. Echoed back, carried by the webhooks, and
                    searchable on **Email → Messages** in the console.
              required:
                - to
                - subject
      responses:
        '202':
          description: Accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  status:
                    type: string
                  from:
                    type: object
                    properties:
                      name:
                        type: string
                      address:
                        type: string
                  to:
                    type: string
                  subject:
                    type: string
                  reference:
                    type: string
                  price_halalas:
                    type: integer
                  created_at:
                    type: string
                    format: date-time
              examples:
                accepted:
                  summary: Accepted
                  value:
                    id: 3d9a7f2e-1c4b-4e8a-9f6d-2b5c8e1a7d40
                    status: accepted
                    from:
                      name: متجر أكمي
                      address: orders@acme.sa
                    to: customer@example.com
                    subject: طلبك رقم 1042 قيد التجهيز
                    reference: order-1042
                    price_halalas: 1
                    created_at: '2026-10-09T12:00:00+03:00'
        '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 / `insufficient_credits`: The account's prepaid
            balance is below the price of a message. The body adds
            `balance_halalas` and `price_halalas`; nothing was sent or recorded.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - insufficient_credits
              examples:
                insufficient_credits:
                  summary: Insufficient credits
                  value:
                    error: insufficient_credits
                    message: Insufficient credits
                    balance_halalas: 0
                    price_halalas: 1
        '403':
          description: >-
            `live_key_required`: A test (tk_test_) key. There is no e-mail
            sandbox; use the application's live key.; `email_early_access`:
            Tawked Email is early access; apply from the console. The account
            has not been granted access yet: apply from the application's Email
            area, and Tawked's team answers on WhatsApp, in the console and by
            e-mail.; `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`: The key was not
            granted this call: a custom key without this product, or with a
            level below the call, such as a key that checks where the call
            sends. The response header `WWW-Authenticate` names the scope the
            call needs. Judged right after the key is recognised, before
            `account_not_active` and the request's shape. This operation needs
            `email:send`.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - live_key_required
                          - email_early_access
                          - account_not_active
                          - ip_not_allowed
                          - insufficient_scope
          headers:
            WWW-Authenticate:
              description: >-
                Sent with `insufficient_scope` only: the scope this operation
                needs, which the key was not granted.
              schema:
                type: string
              example: Bearer error="insufficient_scope", scope="email:send"
        '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
        '409':
          description: >-
            `no_verified_domain`: The application has no verified sender domain
            yet (or does not have Tawked Email). Add one in the application's
            **Email** area and add its three CNAME records.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - no_verified_domain
        '413':
          description: >-
            `message_too_large`: `html` and `text` together are larger than 512
            KiB.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - message_too_large
        '422':
          description: >-
            Sender not verified / `sender_not_verified`: `from.address` is not
            on a verified domain of this application: another domain, a domain
            still pending, or one whose records are gone.;
            `invalid_destination`: `to` is not one syntactically valid e-mail
            address.; `recipient_suppressed`: The address is on the account's
            suppression list: it bounced permanently, complained, or was added
            by hand. Nothing was recorded or charged.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - sender_not_verified
                          - invalid_destination
                          - recipient_suppressed
              examples:
                sender_not_verified:
                  summary: Sender not verified
                  value:
                    error: sender_not_verified
        '429':
          description: >-
            `daily_cap_reached`: The account sent its messages for the day
            (Riyadh time). Nothing was recorded or charged; the cap resets at
            midnight, and Tawked can raise it for the account.;
            `too_many_requests`: Per-key rate limit exceeded (default 120
            requests/minute, fixed 60s window). Checked before authentication.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - daily_cap_reached
                          - 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
        '502':
          description: >-
            `send_failed`: The send could not be completed. The body adds
            `provider_code` and `message`; the price is refunded, the message is
            recorded as failed, and the Idempotency-Key is released, so retry
            with the same key.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - send_failed
        '503':
          description: >-
            `email_paused`: Sending is paused for the account, after a high
            bounce or complaint rate or by Tawked's team. Nothing was sent or
            charged; contact support.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - properties:
                      error:
                        enum:
                          - email_paused
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            curl -X POST https://tawked.com/v1/email/messages \
              -H "Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxx" \
              -H "Content-Type: application/json" \
              -H "Idempotency-Key: order-1042-confirmation" \
              -d '{
                "from": {
                    "name": "متجر أكمي",
                    "address": "orders@acme.sa"
                },
                "to": "customer@example.com",
                "subject": "طلبك رقم 1042 قيد التجهيز",
                "html": "<p>مرحبًا سارة،</p><p>استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.</p>",
                "text": "مرحبًا سارة،\nاستلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.",
                "reply_to": "support@acme.sa",
                "reference": "order-1042"
            }'
        - lang: javascript
          label: Node.js
          source: |-
            const res = await fetch("https://tawked.com/v1/email/messages", {
              method: "POST",
              headers: {
                Authorization: "Bearer tk_live_xxxxxxxxxxxxxxxxxxxx",
                "Content-Type": "application/json",
                "Idempotency-Key": "order-1042-confirmation",
              },
              body: JSON.stringify({
                  "from": {
                      "name": "متجر أكمي",
                      "address": "orders@acme.sa"
                  },
                  "to": "customer@example.com",
                  "subject": "طلبك رقم 1042 قيد التجهيز",
                  "html": "<p>مرحبًا سارة،</p><p>استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.</p>",
                  "text": "مرحبًا سارة،\nاستلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.",
                  "reply_to": "support@acme.sa",
                  "reference": "order-1042"
              }),
            });
            const data = await res.json();
        - lang: python
          label: Python
          source: |-
            import requests

            res = requests.post(
                "https://tawked.com/v1/email/messages",
                headers={"Authorization": "Bearer tk_live_xxxxxxxxxxxxxxxxxxxx", "Idempotency-Key": "order-1042-confirmation"},
                json={
                    "from": {
                        "name": "متجر أكمي",
                        "address": "orders@acme.sa"
                    },
                    "to": "customer@example.com",
                    "subject": "طلبك رقم 1042 قيد التجهيز",
                    "html": "<p>مرحبًا سارة،</p><p>استلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.</p>",
                    "text": "مرحبًا سارة،\nاستلمنا طلبك رقم 1042 وهو قيد التجهيز الآن.",
                    "reply_to": "support@acme.sa",
                    "reference": "order-1042"
                },
            )
            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`), `notifications:templates` (includes
        `notifications:read`). 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. 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.