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

# Send a WhatsApp message

> Send a message from a connected WhatsApp number. `text`, `media`, `interactive_buttons`, `interactive_list`, `location`, and `contacts` are SESSION messages - deliverable only inside the 24-hour customer window (i.e. after the user messaged you). Outside it, only `template` (an approved HSM) is deliverable. `context_message_id` (any type except `contacts`) threads the message as a reply under a prior WhatsApp message id, rendering as a quoted reply in the customer's app. Requires social:write.



## OpenAPI

````yaml /openapi.json post /whatsapp/messages
openapi: 3.1.0
info:
  title: SmartlyQ API
  version: 1.0.0
  description: >
    # SmartlyQ API


    REST API for the SmartlyQ platform: generate content, manage social posts,
    chatbots, media, and more.


    ## Quick Start


    1. Get an API key from
    [app.smartlyq.com/my/developer](https://app.smartlyq.com/my/developer).

    2. Send your first request:


    ```bash

    curl -H "Authorization: Bearer YOUR_API_KEY" https://api.smartlyq.com/v1/me

    ```


    ## Idempotency


    Every `POST`/`PUT`/`PATCH` endpoint supports safe retries: send an
    `X-Idempotency-Key` header (any unique string, e.g. a UUID). If the same key
    is replayed within 24 hours with the same request, you get the original
    response back - the action never runs twice, and you are never
    double-billed. Reusing a key with a *different* body or endpoint returns
    `409 IDEMPOTENCY_CONFLICT`.


    ```bash

    curl -X POST https://api.smartlyq.com/v1/social/posts/schedule \
      -H "Authorization: Bearer sqk_live_xxxx" \
      -H "X-Idempotency-Key: 5f0c9a4e-2b7d-4d1a-9c58-e2ff10c3a771" \
      -d '{...}'
    ```


    ## Authentication


    All requests (except health/docs) require a **Bearer token**. Use your API
    key as the token:


    - **Key types:** `sqk_live_*` (live) or `sqk_test_*` (test/sandbox).

    - **Header:** `Authorization: Bearer sqk_live_xxxx` or `Authorization:
    Bearer sqk_test_xxxx`.


    | Scope | Description |

    |-------|-------------|

    | `articles:read` | List and get articles |

    | `articles:write` | Generate, delete articles |

    | `images:read` | List and get images |

    | `images:write` | Generate, delete images |

    | `videos:read` | List and get videos |

    | `videos:write` | Generate, delete videos |

    | `presentations:read` | List and get presentations |

    | `presentations:write` | Generate presentations |

    | `social:read` | Accounts (health, follower stats, platform lookups),
    posts, queues, comments, DMs, reviews, pre-flight validation, Reddit
    research |

    | `social:write` | Create/schedule/bulk posts, recycling, unpublish, queues,
    reply to comments/DMs/reviews, account rename/move, account groups |

    | `audio:read` | Get audio resources |

    | `audio:write` | Text-to-speech, speech-to-text |

    | `urls:read` | List and get short URLs and stats |

    | `urls:write` | Shorten, delete URLs |

    | `captain:use` | AI Captain messages and conversations |

    | `chatbot:use` | Chatbots, train, messages, conversations |

    | `media:read` | List and get media |

    | `media:write` | Upload, delete media |

    | `analytics:read` | Overview, post and account analytics, derived insights
    (best-time, decay, frequency), inbox analytics |

    | `jobs:read` | List and get async jobs, cancel |

    | `seo:read` | Keyword research, SERP, rank tracking, competitors,
    backlinks, on-page audits |

    | `contacts:read` | List and get CRM contacts, tags, notes; list automations
    and their runs |

    | `contacts:write` | Create/update/delete contacts (single or bulk); tags
    and notes; enroll in, activate and trigger automations |

    | `opportunities:read` | List pipelines and deals/opportunities |

    | `opportunities:write` | Create/update deals, move stages, set status |

    | `webhooks:read` | List webhooks and delivery logs |

    | `webhooks:write` | Create, update, test and delete webhooks |

    | `workspaces:read` | List and get sub-account workspaces |

    | `workspaces:write` | Create, disable SaaS, and delete sub-account
    workspaces |

    | `workspaces:bulk` | Apply pause / resume / disable-SaaS to many
    sub-accounts at once (high-trust; requires an active SaaS plan) |


    ## Billing & Credits


    - **Prepaid wallet:** API usage is deducted from your Developer API wallet
    (credits in SQC).

    - **Pricing:** See the [pricing table](https://smartlyq.com/pricing) and
    in-app Developer dashboard for per-operation costs.

    - **How it works:** Each billable request (e.g. generate, post, chatbot
    message) consumes credits; response may include `usage` with `cost` and
    `balance_remaining`.

    - **Top up:** Add credits via
    [app.smartlyq.com/my/developer](https://app.smartlyq.com/my/developer)
    (wallet / top-up).


    ## Rate Limiting


    Limits apply per API key (and may be enforced per user or IP). Default is 60
    requests per minute per key (overridable per key).


    Response headers:


    | Header | Description |

    |--------|-------------|

    | `X-RateLimit-Limit` | Max requests per window |

    | `X-RateLimit-Remaining` | Remaining in current window |

    | `X-RateLimit-Reset` | Unix timestamp when the window resets |


    When exceeded: HTTP `429` with `Retry-After` header.


    ## Errors


    Errors are JSON with a consistent shape:


    ```json

    {
      "success": false,
      "error": {
        "code": "ERROR_CODE",
        "message": "Human-readable message",
        "details": {}
      },
      "meta": { "request_id": "...", "timestamp": "..." }
    }

    ```


    | HTTP | Code | Meaning |

    |-----|------|---------|

    | 400 | `BAD_REQUEST` | Malformed or invalid request |

    | 401 | `UNAUTHORIZED` | Missing or invalid API key |

    | 402 | `INSUFFICIENT_BALANCE` | Not enough credits |

    | 403 | `FORBIDDEN` | Valid key but insufficient scope or access |

    | 404 | `RESOURCE_NOT_FOUND` | Resource does not exist |

    | 409 | `CONFLICT` | Conflict (e.g. duplicate idempotency) |

    | 422 | `VALIDATION_ERROR` | Validation failed (fields in details) |

    | 429 | `RATE_LIMIT_EXCEEDED` | Too many requests |

    | 500 | `INTERNAL_ERROR` | Server error |


    ## Async Jobs & Polling


    Some operations (e.g. article or video generation) return **HTTP 202
    Accepted** with a `job_id`. Poll for status:


    - **Poll:** `GET /jobs/{job_id}` until `status` is `completed`, `failed`, or
    `cancelled`.

    - Response includes `result` or `error` when finished.


    ## Webhooks


    Configure webhook URLs in the Developer dashboard. We send HTTP POST to your
    URL with a signed payload.


    - **Verification:** Validate signature using your webhook secret (see
    dashboard).

    - **Events:** 25 events across posting, accounts, inbox, jobs, billing, and
    CRM - e.g. `post.published`, `comment.received`, `contact.created`. Full
    catalog with payload schemas: the `webhooks` object in this spec and the
    [Webhooks guide](https://docs.smartlyq.com/guides/webhooks).


    ## Idempotency


    For POST/PUT/PATCH, send **`X-Idempotency-Key`** (unique value per logical
    operation). Within 24 hours, the same key returns the same response without
    re-executing.


    ## Pagination


    - **Offset:** `page` (1-based) and `per_page` (default 20, max 100).

    - Response includes `pagination` with `page`, `per_page`, `total`, `pages`.


    ## Versioning


    Current version is **v1**. Base path: `https://api.smartlyq.com/v1`. Future
    versions will use new path prefixes (e.g. `/v2/`).
  contact:
    name: SmartlyQ Support
    url: https://smartlyq.com
    email: support@smartlyq.com
  license:
    name: Proprietary
    url: https://smartlyq.com/terms
servers:
  - url: https://api.smartlyq.com/v1
    description: Production
security:
  - BearerAuth: []
tags:
  - name: CRM Contacts
    description: 'CRM contacts: create, update, upsert, tags and notes'
  - name: CRM Custom Fields
    description: Custom field (custom attribute) definitions
  - name: CRM Opportunities
    description: Sales pipelines and deals/opportunities
  - name: Workspaces
    description: Create sub-account workspaces
  - name: Articles
    description: Long-form article generation and management
  - name: Images
    description: AI image generation and listing
  - name: Videos
    description: AI video generation and listing
  - name: Social
    description: Social accounts and post scheduling
  - name: Content
    description: Content rewriting
  - name: Audio
    description: Text-to-speech and speech-to-text
  - name: URLs
    description: URL shortening and analytics
  - name: AI Captain
    description: AI Captain conversations
  - name: Chatbot
    description: Chatbots, training, and conversations
  - name: Media
    description: Media library and uploads
  - name: Analytics
    description: Analytics overview and reports
  - name: Jobs
    description: Async job status and cancellation
  - name: SEO
    description: >-
      DataForSEO-backed keyword research, SERP, rank tracking, competitors,
      backlinks and on-page audits
  - name: Account
    description: Current user, usage, and balance
  - name: Comments
    description: Comments endpoints
  - name: Direct Messages
    description: Direct Messages endpoints
  - name: Webhooks
    description: Subscribe to event notifications (HMAC-signed deliveries with retries).
  - name: Shorts
    description: 'Magic Shorts: turn long videos into ranked viral clips'
  - name: Presentations
    description: AI presentation (slide deck) generation from a prompt
paths:
  /whatsapp/messages:
    post:
      tags:
        - WhatsApp
      summary: Send a WhatsApp message
      description: >-
        Send a message from a connected WhatsApp number. `text`, `media`,
        `interactive_buttons`, `interactive_list`, `location`, and `contacts`
        are SESSION messages - deliverable only inside the 24-hour customer
        window (i.e. after the user messaged you). Outside it, only `template`
        (an approved HSM) is deliverable. `context_message_id` (any type except
        `contacts`) threads the message as a reply under a prior WhatsApp
        message id, rendering as a quoted reply in the customer's app. Requires
        social:write.
      operationId: sendWhatsAppMessage
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - account_id
                - to
              properties:
                account_id:
                  type: integer
                  description: A connected WhatsApp number (social account id).
                to:
                  type: string
                  description: Recipient phone in E.164 (e.g. +14155551234).
                type:
                  type: string
                  enum:
                    - text
                    - media
                    - template
                    - interactive_buttons
                    - interactive_list
                    - location
                    - contacts
                    - reaction
                  default: text
                context_message_id:
                  type: string
                  description: >-
                    A prior WhatsApp message id (wamid) to thread this message
                    as a reply under, or (for type=reaction) the message being
                    reacted to. Renders as a quoted reply in the customer's app.
                text:
                  type: string
                  description: >-
                    Body for type=text, or the prompt text for
                    type=interactive_buttons/interactive_list.
                media:
                  type: object
                  description: For type=media.
                  properties:
                    kind:
                      type: string
                      enum:
                        - image
                        - video
                        - document
                        - audio
                    link:
                      type: string
                    caption:
                      type: string
                template:
                  type: object
                  description: For type=template.
                  properties:
                    name:
                      type: string
                    language:
                      type: string
                      default: en_US
                    components:
                      type: array
                      items:
                        type: object
                buttons:
                  type: array
                  description: >-
                    For type=interactive_buttons. Up to 3 reply buttons; the
                    customer's tap arrives as an inbound message you already
                    receive on your webhook.
                  maxItems: 3
                  items:
                    type: object
                    required:
                      - id
                      - title
                    properties:
                      id:
                        type: string
                        description: Opaque id returned in the customer's tap event.
                      title:
                        type: string
                        description: Button label, max 20 characters.
                button_text:
                  type: string
                  description: >-
                    For type=interactive_list. Label on the button that opens
                    the list, max 20 characters.
                sections:
                  type: array
                  description: >-
                    For type=interactive_list. Up to 10 rows total across all
                    sections.
                  items:
                    type: object
                    properties:
                      title:
                        type: string
                        description: Optional section heading, max 24 characters.
                      rows:
                        type: array
                        items:
                          type: object
                          required:
                            - id
                            - title
                          properties:
                            id:
                              type: string
                            title:
                              type: string
                              description: Max 24 characters.
                            description:
                              type: string
                              description: Max 72 characters.
                location:
                  type: object
                  description: For type=location.
                  required:
                    - latitude
                    - longitude
                  properties:
                    latitude:
                      type: number
                    longitude:
                      type: number
                    name:
                      type: string
                    address:
                      type: string
                contacts:
                  type: array
                  description: >-
                    For type=contacts. WhatsApp's raw contact-card array - see
                    Meta's WhatsApp Cloud API `contacts` message reference for
                    the full object shape (name, phones, emails, etc.).
                  items:
                    type: object
                emoji:
                  type: string
                  description: >-
                    For type=reaction. The emoji to react with, or an empty
                    string to remove a previously-sent reaction. Requires
                    context_message_id.
            examples:
              text:
                summary: Text (session)
                value:
                  account_id: 42
                  to: '+14155551234'
                  type: text
                  text: Thanks for reaching out!
              threaded_reply:
                summary: Text, threaded as a reply
                value:
                  account_id: 42
                  to: '+14155551234'
                  type: text
                  text: Yes, that ships tomorrow.
                  context_message_id: wamid.HBgLMTU1NTU1NTU1NTUVAgARGBI5QTM2RUQ4RkQ2QjM4RjQ4QjQA
              interactive_buttons:
                summary: Interactive buttons
                value:
                  account_id: 42
                  to: '+14155551234'
                  type: interactive_buttons
                  text: 'Your order #A1234 is ready. What would you like to do?'
                  buttons:
                    - id: confirm
                      title: Confirm
                    - id: reschedule
                      title: Reschedule
                    - id: cancel
                      title: Cancel
              interactive_list:
                summary: Interactive list
                value:
                  account_id: 42
                  to: '+14155551234'
                  type: interactive_list
                  text: Pick a time slot for your appointment.
                  button_text: View slots
                  sections:
                    - title: Tomorrow
                      rows:
                        - id: slot_10
                          title: 10:00 AM
                          description: 45 min available
                        - id: slot_14
                          title: 2:00 PM
                          description: 45 min available
              location:
                summary: Location pin
                value:
                  account_id: 42
                  to: '+14155551234'
                  type: location
                  location:
                    latitude: 37.7749
                    longitude: -122.4194
                    name: Store pickup counter
                    address: 123 Market St, San Francisco, CA
              contacts:
                summary: Contact card
                value:
                  account_id: 42
                  to: '+14155551234'
                  type: contacts
                  contacts:
                    - name:
                        formatted_name: Support Team
                        first_name: Support
                      phones:
                        - phone: '+14155550188'
                          type: WORK
              reaction:
                summary: React to a message
                value:
                  account_id: 42
                  to: '+14155551234'
                  type: reaction
                  context_message_id: wamid.HBgLMTU1NTU1NTU1NTUVAgARGBI5QTM2RUQ4RkQ2QjM4RjQ4QjQA
                  emoji: 👍
      responses:
        '201':
          description: Sent
          content:
            application/json:
              schema:
                type: object
              example:
                success: true
                data:
                  message_id: wamid.HBg...
                  status: sent
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
        '502':
          description: >-
            WhatsApp rejected the message (e.g. outside the 24h window with no
            template).
components:
  responses:
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: RESOURCE_NOT_FOUND
              message: Post not found.
              details: {}
            meta:
              request_id: req_9f3a2b1c-7d4e-4a08-b2c6-5e1f8a9d0c34
              timestamp: '2026-07-26T09:41:22Z'
    ValidationError:
      description: Validation error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: VALIDATION_ERROR
              message: 'Missing required fields: content, platforms.'
              details:
                fields:
                  - content
                  - platforms
            meta:
              request_id: req_9f3a2b1c-7d4e-4a08-b2c6-5e1f8a9d0c34
              timestamp: '2026-07-26T09:41:22Z'
  schemas:
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - false
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            details:
              type: object
        meta:
          $ref: '#/components/schemas/RequestMeta'
    RequestMeta:
      type: object
      properties:
        request_id:
          type: string
          example: req_9f3a2b1c-7d4e-4a08-b2c6-5e1f8a9d0c34
        timestamp:
          type: string
          format: date-time
          example: '2026-07-26T09:41:22Z'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: sqk_live_* or sqk_test_*
      description: API key from Developer dashboard (Bearer token).

````