openapi: 3.0.3
info:
  title: SpotBay WhatsApp API
  description: |
    The SpotBay WhatsApp API lets you send messages, manage templates, and handle media
    for your WhatsApp Business account.

    **Getting started:**
    1. Sign in to the SpotBay Business Portal
    2. Go to **Developer → API Tokens** and generate your token
    3. Use `https://api.spotbay.in/wa-api` as the base URL
    4. Include your token in every request: `Authorization: Bearer sb_wa_<your_token>`

    Request and response payloads follow the WhatsApp Cloud API v21.0 spec.
    For full payload details, refer to the [WhatsApp Cloud API docs](https://developers.facebook.com/docs/whatsapp/cloud-api).
  version: "1.0.0"
  contact:
    name: SpotBay Developer Support
    email: dev@spotbay.in
    url: https://www.spotbay.in/developers
  license:
    name: Proprietary

servers:
  - url: https://api.spotbay.in/wa-api
    description: Production
  - url: https://staging.spotbay.in/wa-api
    description: Staging

security:
  - SpotBayToken: []

tags:
  - name: Messages
    description: Send text, media, template, interactive, and reaction messages
  - name: Templates
    description: Create, list, and delete message templates
  - name: Media
    description: Upload, retrieve, and delete media files
  - name: Phone Numbers
    description: Retrieve and update business phone number settings
  - name: WABA
    description: WhatsApp Business Account information

paths:

  # ─── Messages ───────────────────────────────────────────────────────────────

  /v21.0/{phone_number_id}/messages:
    post:
      tags: [Messages]
      summary: Send a message
      description: |
        Send any message type supported by Meta Cloud API — text, image, video, audio,
        document, sticker, location, contacts, interactive (buttons/lists), reaction,
        and template messages.
      operationId: sendMessage
      parameters:
        - $ref: '#/components/parameters/PhoneNumberId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendMessageRequest'
            examples:
              text:
                summary: Send plain text
                value:
                  messaging_product: whatsapp
                  recipient_type: individual
                  to: "919876543210"
                  type: text
                  text:
                    preview_url: false
                    body: "Hello from SpotBay! 👋"
              template:
                summary: Send a template message
                value:
                  messaging_product: whatsapp
                  to: "919876543210"
                  type: template
                  template:
                    name: hello_world
                    language:
                      code: en_US
              image:
                summary: Send image by URL
                value:
                  messaging_product: whatsapp
                  recipient_type: individual
                  to: "919876543210"
                  type: image
                  image:
                    link: "https://example.com/image.jpg"
                    caption: "Check this out!"
              interactive_buttons:
                summary: Send quick reply buttons
                value:
                  messaging_product: whatsapp
                  recipient_type: individual
                  to: "919876543210"
                  type: interactive
                  interactive:
                    type: button
                    body:
                      text: "Would you like to continue?"
                    action:
                      buttons:
                        - type: reply
                          reply:
                            id: "yes_btn"
                            title: "Yes"
                        - type: reply
                          reply:
                            id: "no_btn"
                            title: "No"
      responses:
        '200':
          description: Message accepted by WhatsApp
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendMessageResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  # ─── Templates ──────────────────────────────────────────────────────────────

  /v21.0/{waba_id}/message_templates:
    get:
      tags: [Templates]
      summary: List message templates
      operationId: listTemplates
      parameters:
        - $ref: '#/components/parameters/WabaId'
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
        - name: after
          in: query
          description: Pagination cursor
          schema:
            type: string
      responses:
        '200':
          description: List of templates
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplateListResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags: [Templates]
      summary: Create a message template
      operationId: createTemplate
      parameters:
        - $ref: '#/components/parameters/WabaId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTemplateRequest'
            examples:
              simple_text:
                summary: Simple text template
                value:
                  name: order_confirmation
                  language: en_US
                  category: UTILITY
                  components:
                    - type: HEADER
                      format: TEXT
                      text: "Order Confirmed"
                    - type: BODY
                      text: "Hi {{1}}, your order #{{2}} has been confirmed!"
                      example:
                        body_text:
                          - ["John", "ORD-12345"]
                    - type: FOOTER
                      text: "Thank you for shopping with us."
      responses:
        '200':
          description: Template created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  status:
                    type: string
                    example: PENDING
                  category:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /v21.0/{template_id}:
    delete:
      tags: [Templates]
      summary: Delete a message template
      operationId: deleteTemplate
      parameters:
        - name: template_id
          in: path
          required: true
          schema:
            type: string
        - name: name
          in: query
          required: true
          description: Template name (required by Meta)
          schema:
            type: string
      responses:
        '200':
          description: Template deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ─── Media ──────────────────────────────────────────────────────────────────

  /v21.0/{phone_number_id}/media:
    post:
      tags: [Media]
      summary: Upload media
      description: Upload image, video, audio, or document for use in messages.
      operationId: uploadMedia
      parameters:
        - $ref: '#/components/parameters/PhoneNumberId'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file, type, messaging_product]
              properties:
                file:
                  type: string
                  format: binary
                type:
                  type: string
                  example: image/jpeg
                messaging_product:
                  type: string
                  example: whatsapp
      responses:
        '200':
          description: Media uploaded
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    description: Media ID — use this in message payloads
                    example: "1234567890123456"

  /v21.0/{media_id}:
    get:
      tags: [Media]
      summary: Get media URL
      operationId: getMedia
      parameters:
        - name: media_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Media metadata and download URL
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MediaResponse'
    delete:
      tags: [Media]
      summary: Delete media
      operationId: deleteMedia
      parameters:
        - name: media_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Media deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean

  # ─── Phone Numbers ───────────────────────────────────────────────────────────

  /v21.0/{waba_id}/phone_numbers:
    get:
      tags: [Phone Numbers]
      summary: List phone numbers
      operationId: listPhoneNumbers
      parameters:
        - $ref: '#/components/parameters/WabaId'
      responses:
        '200':
          description: Phone numbers linked to the WABA
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PhoneNumber'

  /v21.0/{phone_number_id}/whatsapp_business_profile:
    get:
      tags: [Phone Numbers]
      summary: Get business profile
      operationId: getBusinessProfile
      parameters:
        - $ref: '#/components/parameters/PhoneNumberId'
        - name: fields
          in: query
          schema:
            type: string
            example: about,address,description,email,profile_picture_url,websites,vertical
      responses:
        '200':
          description: Business profile
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BusinessProfile'

    post:
      tags: [Phone Numbers]
      summary: Update business profile
      operationId: updateBusinessProfile
      parameters:
        - $ref: '#/components/parameters/PhoneNumberId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BusinessProfile'
            example:
              messaging_product: whatsapp
              about: "We sell the best products!"
              address: "123 Main St, Mumbai"
              description: "Your trusted retail partner"
              email: "support@mybusiness.com"
              websites:
                - "https://mybusiness.com"
              vertical: RETAIL
      responses:
        '200':
          description: Profile updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean

  # ─── WABA ────────────────────────────────────────────────────────────────────

  /v21.0/{waba_id}:
    get:
      tags: [WABA]
      summary: Get WABA details
      operationId: getWaba
      parameters:
        - $ref: '#/components/parameters/WabaId'
        - name: fields
          in: query
          schema:
            type: string
            example: id,name,currency,timezone_id,message_template_namespace
      responses:
        '200':
          description: WABA details
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  currency:
                    type: string
                  timezone_id:
                    type: string

# ─── Components ──────────────────────────────────────────────────────────────

components:

  securitySchemes:
    SpotBayToken:
      type: http
      scheme: bearer
      bearerFormat: SpotBay Token (sb_wa_...)
      description: |
        Your SpotBay API token. Format: `sb_wa_<32 hex chars>`.
        Get it from: **SpotBay Business Portal → Developer → API Tokens**

  parameters:
    PhoneNumberId:
      name: phone_number_id
      in: path
      required: true
      description: Your WhatsApp phone number ID (from SpotBay Developer portal)
      schema:
        type: string
      example: "506211495919192"

    WabaId:
      name: waba_id
      in: path
      required: true
      description: Your WhatsApp Business Account ID
      schema:
        type: string
      example: "102290129340398"

  schemas:

    SendMessageRequest:
      type: object
      required: [messaging_product, to, type]
      properties:
        messaging_product:
          type: string
          enum: [whatsapp]
        recipient_type:
          type: string
          enum: [individual]
          default: individual
        to:
          type: string
          description: Recipient phone number in E.164 format (no + prefix)
          example: "919876543210"
        type:
          type: string
          enum: [text, image, video, audio, document, sticker, location, contacts, interactive, template, reaction]
        text:
          $ref: '#/components/schemas/TextObject'
        template:
          $ref: '#/components/schemas/TemplateObject'
        image:
          $ref: '#/components/schemas/MediaObject'
        video:
          $ref: '#/components/schemas/MediaObject'
        audio:
          $ref: '#/components/schemas/MediaObject'
        document:
          $ref: '#/components/schemas/MediaObject'
        interactive:
          type: object
          description: Interactive message payload (buttons, lists, etc.)
        reaction:
          type: object
          properties:
            message_id:
              type: string
            emoji:
              type: string
              example: "❤️"

    SendMessageResponse:
      type: object
      properties:
        messaging_product:
          type: string
          example: whatsapp
        contacts:
          type: array
          items:
            type: object
            properties:
              input:
                type: string
              wa_id:
                type: string
        messages:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                description: WhatsApp message ID
                example: "wamid.HBgLMTU1MDUwNDM1OTUVAgARGBIyRkQyMEE1RkM0MTA4MzA3NTIA"
              message_status:
                type: string
                example: accepted

    TextObject:
      type: object
      properties:
        body:
          type: string
          maxLength: 4096
          example: "Hello! How can we help you today?"
        preview_url:
          type: boolean
          default: false

    TemplateObject:
      type: object
      required: [name, language]
      properties:
        name:
          type: string
          example: hello_world
        language:
          type: object
          properties:
            code:
              type: string
              example: en_US
        components:
          type: array
          items:
            type: object

    MediaObject:
      type: object
      properties:
        id:
          type: string
          description: Media ID from upload endpoint
        link:
          type: string
          description: Public URL (use id OR link, not both)
        caption:
          type: string
        filename:
          type: string

    MediaResponse:
      type: object
      properties:
        url:
          type: string
          description: Temporary download URL (valid 5 minutes)
        mime_type:
          type: string
        sha256:
          type: string
        file_size:
          type: integer
        id:
          type: string
        messaging_product:
          type: string

    TemplateListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              name:
                type: string
              status:
                type: string
                enum: [APPROVED, PENDING, REJECTED, PAUSED, DISABLED]
              category:
                type: string
              language:
                type: string
              components:
                type: array
                items:
                  type: object
        paging:
          type: object
          properties:
            cursors:
              type: object
              properties:
                before:
                  type: string
                after:
                  type: string

    CreateTemplateRequest:
      type: object
      required: [name, language, category, components]
      properties:
        name:
          type: string
          pattern: '^[a-z0-9_]+$'
          example: order_confirmation
        language:
          type: string
          example: en_US
        category:
          type: string
          enum: [MARKETING, UTILITY, AUTHENTICATION]
        components:
          type: array
          items:
            type: object

    PhoneNumber:
      type: object
      properties:
        id:
          type: string
        display_phone_number:
          type: string
        verified_name:
          type: string
        quality_rating:
          type: string
        platform_type:
          type: string
        throughput:
          type: object
        account_mode:
          type: string

    BusinessProfile:
      type: object
      properties:
        messaging_product:
          type: string
        about:
          type: string
          maxLength: 139
        address:
          type: string
        description:
          type: string
          maxLength: 512
        email:
          type: string
        profile_picture_url:
          type: string
        websites:
          type: array
          items:
            type: string
          maxItems: 2
        vertical:
          type: string
          enum: [AUTOMOTIVE, BEAUTY_SPA_SALON, CLOTHING_AND_APPAREL, EDUCATION, ENTERTAINMENT,
                 EVENT_PLANNING_AND_SERVICE, FINANCE_AND_BANKING, FOOD_AND_GROCERY, PUBLIC_SERVICE,
                 HOTEL_AND_LODGING, MEDICAL_AND_HEALTH, NON_PROFIT, PROFESSIONAL_SERVICES,
                 SHOPPING_AND_RETAIL, TRAVEL_AND_TRANSPORTATION, RESTAURANT, OTHER]

    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            message:
              type: string
            type:
              type: string
            code:
              type: integer
            fbtrace_id:
              type: string

  responses:
    BadRequest:
      description: Invalid request payload
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Invalid or missing SpotBay token
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                example: Invalid SpotBay token
    RateLimited:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
