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

# Create and submit a template

> Create the template and submit it to Meta for approval in one call.

Returns 201 with `status: "PENDING"`; Meta's review then flips it to
APPROVED or REJECTED asynchronously (poll `GET /v1/templates/{id}`). Nothing
persists if Meta rejects the payload outright — that is a 422 `meta_rejected`
carrying Meta's own reason, not a stranded draft.



## OpenAPI

````yaml /api-reference/openapi.json post /v1/templates
openapi: 3.1.0
info:
  title: Ciarem API
  version: v1
  description: >
    The Ciarem public API. Authenticate every request with an org-bound API key

    (created in Settings → API keys; Scale plan or free trial) sent as a bearer
    token:

    `Authorization: Bearer oak_…`.


    Compatibility: this is an early, fast-moving API. Most changes are

    additive (new endpoints, new optional params, new response fields, new

    enum/string values) — clients must tolerate unknown fields and unknown

    string values. Every contract change is listed in the changelog at

    help.ciarem.ai.
servers:
  - url: https://api.ciarem.ai
security:
  - apiKey: []
tags:
  - name: Account
    description: The organization behind the API key.
  - name: Contacts
    description: People in the CRM — create, read, update, delete.
  - name: CRM
    description: 'The shape of the CRM: custom properties and funnel stages.'
  - name: Conversations
    description: Read the message history of a conversation.
  - name: WhatsApp numbers
    description: The connected numbers a send can go out from.
  - name: WhatsApp templates
    description: Message templates, and what each one needs filled before it can be sent.
  - name: Broadcasts
    description: Send a template, and follow what happened to every recipient.
paths:
  /v1/templates:
    post:
      tags:
        - WhatsApp templates
      summary: Create and submit a template
      description: >-
        Create the template and submit it to Meta for approval in one call.


        Returns 201 with `status: "PENDING"`; Meta's review then flips it to

        APPROVED or REJECTED asynchronously (poll `GET /v1/templates/{id}`).
        Nothing

        persists if Meta rejects the payload outright — that is a 422
        `meta_rejected`

        carrying Meta's own reason, not a stranded draft.
      operationId: create_endpoint_v1_templates_post
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicTemplateCreate'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicTemplate'
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicTemplateError'
          description: Bad Request
        '401':
          description: >-
            No usable credential: `missing_bearer_token` (no `Authorization:
            Bearer`) or `invalid_api_key` (unknown or revoked key).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicError'
        '403':
          description: >-
            The credential is real but not allowed here: `api_key_required` (a
            session token rather than an `oak_` key), `scale_plan_required` (a
            live plan below Scale — upgrade to Scale), `trial_expired` (the free
            trial ended without a card — subscribe to keep the key working), or
            `subscription_required` (the subscription is canceled or suspended).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicError'
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicTemplateError'
          description: Conflict
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicTemplateError'
          description: Unprocessable Content
        '429':
          description: >-
            Over the organization's request budget (`rate_limited`).
            `Retry-After` says how many seconds to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicError'
          headers:
            Retry-After:
              description: Seconds until the window resets.
              schema:
                type: integer
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
components:
  schemas:
    PublicTemplateCreate:
      properties:
        name:
          type: string
          pattern: ^[a-z0-9_]{1,512}$
          title: Name
        language:
          type: string
          pattern: ^[a-zA-Z]{2,3}(_[A-Za-z]{2})?$
          title: Language
        category:
          $ref: '#/components/schemas/TemplateCategory'
        components:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Components
        catalog_send_defaults:
          anyOf:
            - additionalProperties:
                type: string
              type: object
            - type: 'null'
          title: Catalog Send Defaults
      additionalProperties: false
      type: object
      required:
        - name
        - language
        - category
        - components
      title: PublicTemplateCreate
      description: >-
        Create + submit for approval in one call.


        Patterns mirror the internal `TemplateCreate` so the public contract
        cannot

        accept what the service would reject. There is no `waba_id`: the org's

        connected WhatsApp account is resolved server-side.
    PublicTemplate:
      properties:
        id:
          type: string
          title: Id
        waba_id:
          type: string
          title: Waba Id
        meta_template_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Meta Template Id
        name:
          type: string
          title: Name
        language:
          type: string
          title: Language
        category:
          $ref: '#/components/schemas/TemplateCategory'
        status:
          $ref: '#/components/schemas/TemplateStatus'
        components:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Components
        catalog_send_defaults:
          anyOf:
            - additionalProperties:
                type: string
              type: object
            - type: 'null'
          title: Catalog Send Defaults
        rejected_reason:
          anyOf:
            - type: string
            - type: 'null'
          title: Rejected Reason
        quality_rating:
          anyOf:
            - type: string
            - type: 'null'
          title: Quality Rating
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
      type: object
      required:
        - id
        - waba_id
        - meta_template_id
        - name
        - language
        - category
        - status
        - components
        - catalog_send_defaults
        - rejected_reason
        - quality_rating
        - created_at
        - updated_at
      title: PublicTemplate
    PublicTemplateError:
      properties:
        code:
          type: string
          title: Code
        detail:
          anyOf:
            - type: string
            - type: 'null'
          title: Detail
      type: object
      required:
        - code
      title: PublicTemplateError
      description: Parameterized error detail for the create/delete paths.
    PublicError:
      description: An error whose `detail` is a stable, machine-readable code.
      properties:
        detail:
          title: Detail
          type: string
      required:
        - detail
      title: PublicError
      type: object
    TemplateCategory:
      type: string
      enum:
        - MARKETING
        - UTILITY
        - AUTHENTICATION
      title: TemplateCategory
      description: |-
        WhatsApp message-template category. Mirrors Meta's template categories
        and the Postgres `template_category_enum`. Meta may auto-recategorize a
        template after review; the webhook handler reconciles ours to match.
    TemplateStatus:
      type: string
      enum:
        - DRAFT
        - PENDING
        - APPROVED
        - REJECTED
        - PAUSED
        - DISABLED
        - IN_APPEAL
        - PENDING_DELETION
      title: TemplateStatus
      description: >-
        Lifecycle status of a WhatsApp message template. `DRAFT` is local-only

        (authored but never submitted to Meta); every other value mirrors a Meta

        review state. A template starts `DRAFT`, moves to `PENDING` on submit,
        then

        Meta drives it to `APPROVED` / `REJECTED` and later `PAUSED` /
        `DISABLED`

        via the template-status webhook.
  headers:
    X-RateLimit-Limit:
      description: Requests allowed per window, shared across the org's keys.
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests left in the current window.
      schema:
        type: integer
    X-RateLimit-Reset:
      description: When the window resets, as a Unix timestamp in seconds.
      schema:
        type: integer
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: 'An org API key: `Authorization: Bearer oak_…`.'

````