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

# Open a new ticket for whatsapp

## Overview

Create a new support ticket for a WhatsApp Business API contact. This endpoint initializes a conversation in a specific pipeline stage, optionally sends an initial message, and allows you to set custom metadata for both the contact and ticket.

This endpoint is specifically for WhatsApp Business API connections (not WhatsApp Web/QR). Use this when you have an official WhatsApp Business API integration.

## Use Cases

* **Form-triggered Tickets**: Create a ticket when a user submits a contact form
* **E-commerce Integration**: Open tickets for new orders or delivery issues
* **Onboarding Workflows**: Start onboarding tickets for new customers
* **Support Escalation**: Programmatically create tickets from other systems
* **Event-based Tickets**: Create tickets based on user behavior or triggers
* **CRM Synchronization**: Sync customer issues from external CRM to Vambe

## Authentication

This endpoint requires authentication using an API key. Include your API key in the request header:

```
x-api-key: your_api_key_here
```

## Path Parameters

| Parameter | Type          | Required | Description                                   |
| --------- | ------------- | -------- | --------------------------------------------- |
| `phoneId` | number/string | Yes      | Your WhatsApp Business API phone ID (numeric) |

<Note>
  **WhatsApp Business API**: The `phoneId` must be a numeric ID from your
  WhatsApp Business API configuration. This is different from WhatsApp Web (QR)
  which uses string identifiers.
</Note>

## Request Body

| Field              | Type   | Required | Description                                               |
| ------------------ | ------ | -------- | --------------------------------------------------------- |
| `to_phone_number`  | string | Yes      | Contact's WhatsApp phone number (with country code)       |
| `stage_id`         | string | Yes      | UUID of the pipeline stage where the ticket should start  |
| `contact_name`     | string | No       | Full name of the contact                                  |
| `email`            | string | No       | Contact's email address (must be valid email format)      |
| `contact_metadata` | object | No       | Custom key-value pairs for contact-level data             |
| `ticket_metadata`  | object | No       | Custom key-value pairs for ticket-level data              |
| `integration_data` | object | No       | Integration-specific data (e.g., external system IDs)     |
| `message`          | object | No       | Optional initial message to send when creating the ticket |

### Message Object

When providing an initial message, use this structure:

| Field          | Type    | Required | Description                                          |
| -------------- | ------- | -------- | ---------------------------------------------------- |
| `content`      | string  | No       | Text content of the message to send                  |
| `templateId`   | string  | No       | ID of a template to use (if using smart templates)   |
| `ai_generated` | boolean | Yes      | Whether the message is AI-generated (true) or manual |

## Response Structure

The endpoint returns a success response with the created contact information:

| Field         | Type          | Description                                          |
| ------------- | ------------- | ---------------------------------------------------- |
| `aiContactId` | string (UUID) | Unique identifier of the created or existing contact |
| `status`      | string        | Status of the operation (always "ok")                |

## Example Request

```bash theme={null}
curl --request POST \
  'https://api.vambe.me/api/public/ticket/open/whatsapp/123456789' \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: your_api_key_here' \
  --data-raw '{
    "to_phone_number": "+56912345678",
    "stage_id": "550e8400-e29b-41d4-a716-446655440000",
    "contact_name": "Maria Rodriguez",
    "email": "maria.rodriguez@example.com",
    "contact_metadata": {
      "company": "Acme Corp",
      "plan": "Premium",
      "source": "website_form"
    },
    "ticket_metadata": {
      "issue_type": "billing",
      "priority": "high",
      "order_id": "ORD-12345"
    },
    "message": {
      "content": "Hola Maria! Hemos recibido tu consulta sobre facturación. ¿En qué podemos ayudarte?",
      "ai_generated": false
    }
  }'
```

## Example Response

```json theme={null}
{
  "aiContactId": "df980fc8-b6db-4820-bf22-2969482d106d",
  "status": "ok"
}
```

## Common Use Cases

### 1. Create Ticket from Contact Form

```javascript theme={null}
const createTicketFromForm = async (formData) => {
  const response = await fetch(
    'https://api.vambe.me/api/public/ticket/open/whatsapp/123456789',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': 'your_api_key_here',
      },
      body: JSON.stringify({
        to_phone_number: formData.phone,
        stage_id: 'your_initial_stage_id',
        contact_name: formData.name,
        email: formData.email,
        contact_metadata: {
          form_source: 'contact_page',
          submission_date: new Date().toISOString(),
        },
        ticket_metadata: {
          subject: formData.subject,
          message: formData.message,
        },
        message: {
          content: `Hola ${formData.name}! Hemos recibido tu mensaje y te responderemos pronto.`,
          ai_generated: false,
        },
      }),
    },
  );

  const result = await response.json();
  console.log('Ticket created for contact:', result.aiContactId);
  return result;
};
```

### 2. E-commerce Order Ticket

```javascript theme={null}
const createOrderTicket = async (order) => {
  const response = await fetch(
    'https://api.vambe.me/api/public/ticket/open/whatsapp/123456789',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': 'your_api_key_here',
      },
      body: JSON.stringify({
        to_phone_number: order.customerPhone,
        stage_id: 'your_orders_stage_id',
        contact_name: order.customerName,
        email: order.customerEmail,
        contact_metadata: {
          customer_since: order.accountCreatedDate,
          lifetime_value: order.lifetimeValue.toString(),
        },
        ticket_metadata: {
          order_id: order.id,
          order_total: order.total.toString(),
          items: order.items.length.toString(),
          payment_method: order.paymentMethod,
        },
        integration_data: {
          shopify_order_id: order.shopifyId,
          tracking_number: order.trackingNumber,
        },
        message: {
          content: `¡Hola ${order.customerName}! Tu pedido #${order.id} ha sido confirmado y será enviado pronto. Total: $${order.total}`,
          ai_generated: false,
        },
      }),
    },
  );

  return await response.json();
};
```

### 3. Create Ticket Without Initial Message

```javascript theme={null}
// Let the AI assistant handle the first message based on pipeline configuration
const createSilentTicket = async (phone, stageId) => {
  const response = await fetch(
    'https://api.vambe.me/api/public/ticket/open/whatsapp/123456789',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': 'your_api_key_here',
      },
      body: JSON.stringify({
        to_phone_number: phone,
        stage_id: stageId,
        // No message object - AI will handle first contact
      }),
    },
  );

  return await response.json();
};
```

### 4. Using Smart Templates

```javascript theme={null}
const createTicketWithTemplate = async (contact, templateId) => {
  const response = await fetch(
    'https://api.vambe.me/api/public/ticket/open/whatsapp/123456789',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': 'your_api_key_here',
      },
      body: JSON.stringify({
        to_phone_number: contact.phone,
        stage_id: 'your_stage_id',
        contact_name: contact.name,
        message: {
          templateId: templateId,
          content: contact.name, // Template variable
          ai_generated: false,
        },
      }),
    },
  );

  return await response.json();
};
```

## Phone ID Requirements

<Warning>
  The `phoneId` in the path must be a **numeric ID** from your WhatsApp Business
  API configuration. This is NOT the phone number itself.
</Warning>

**Examples**:

* ✅ Correct: `123456789` (numeric phone ID from WhatsApp Business API)
* ❌ Incorrect: `"+56912345678"` (this is the customer's phone number, not your phone ID)
* ❌ Incorrect: `"my-phone-id"` (string identifier - use web-whatsapp endpoint instead)

To get your phone ID:

1. Check your WhatsApp Business API configuration
2. Look in your Vambe dashboard under WhatsApp channels
3. The phone ID is a numeric value assigned by WhatsApp

## Phone Number Format

The `to_phone_number` field accepts phone numbers in various formats:

* **With country code**: `"+56912345678"` (recommended)
* **String format**: `"56912345678"`
* **Number format**: `56912345678`

The system automatically strips non-numeric characters and validates the number.

## Metadata Best Practices

### Contact Metadata

Store information about the person:

* Company name
* Industry
* Customer tier/plan
* Account creation date
* Language preference
* Time zone

### Ticket Metadata

Store information about this specific ticket:

* Issue type/category
* Priority level
* Related order/transaction IDs
* Urgency
* Source (web, mobile, API, etc.)
* Custom fields specific to your workflow

## Error Responses

| Status Code | Description                                          |
| ----------- | ---------------------------------------------------- |
| 400         | Bad Request - Invalid phone number or stage ID       |
| 401         | Unauthorized - Invalid or missing API key            |
| 404         | Not Found - Phone ID doesn't exist or is not numeric |
| 500         | Internal Server Error - Something went wrong         |

## Important Notes

* **Phone ID Must Be Numeric**: The `phoneId` parameter must be a number, not a string identifier
* **WhatsApp Business API Only**: This endpoint is for official WhatsApp Business API connections
* **For WhatsApp Web**: Use `POST /api/public/ticket/open/web-whatsapp/{phoneId}` instead
* **Stage ID**: Make sure the `stage_id` exists in your pipelines - use [GET /api/public/pipeline](/reference/publicpipeline/get-pipelines) to get valid stage IDs
* **Duplicate Contacts**: If a contact with the same phone number already exists, the ticket will be created for that existing contact
* **Metadata Flexibility**: Both `contact_metadata` and `ticket_metadata` accept any key-value pairs as objects
* **AI Processing**: When you don't provide a message, the AI assistant will automatically engage based on your pipeline configuration
* **Message vs Template**: You can provide either plain `content` or use a `templateId` with variables

## What Happens After Creation

1. **Phone ID Validation**: System verifies the phone ID is numeric and exists
2. **Contact Creation/Update**: The system finds or creates a contact with the provided phone number
3. **Metadata Processing**: Contact and ticket metadata are processed and stored
4. **Stage Assignment**: The ticket is placed in the specified pipeline stage
5. **Message Sending** (if provided):
   * If `message.content` is provided without `templateId`: Sends a plain text message via WhatsApp Business API
   * If `message.templateId` is provided: Sends a WhatsApp approved template with variables
   * If no message: AI assistant takes over based on pipeline configuration
6. **Contact ID Return**: You receive the `aiContactId` to track this contact for future operations

## WhatsApp Business API vs WhatsApp Web

| Feature             | WhatsApp Business API (This)        | WhatsApp Web (QR)                       |
| ------------------- | ----------------------------------- | --------------------------------------- |
| **Endpoint**        | `/api/public/ticket/open/whatsapp/` | `/api/public/ticket/open/web-whatsapp/` |
| **Phone ID Format** | Numeric (e.g., `123456789`)         | String (e.g., `"phone_abc123"`)         |
| **Connection Type** | Official API from Meta              | QR code connection                      |
| **Message Types**   | Templates and plain text            | Plain text only                         |
| **Reliability**     | Higher (official API)               | Depends on QR connection                |
| **Scalability**     | Better for high volume              | Limited by QR session                   |

## Related Endpoints

* [GET /api/public/pipeline](/reference/publicpipeline/get-pipelines) - Get available pipeline stages
* [GET /api/public/contact/{aiContactId}/info](/reference/contact/get-info-of-an-ai-contact) - Get ticket and contact info
* [POST /api/public/contact/{aiContactId}/update-metadata](/reference/contact/update-contact-metadata) - Update contact metadata later
* [POST /api/public/ticket/close/contact/{contactId}](#) - Close an active ticket
* [POST /api/public/ticket/open/web-whatsapp/{phoneId}](/reference/ticket/open-ticket-web-whatsapp) - WhatsApp Web version

## Complete Workflow Example

```javascript theme={null}
// Complete workflow: Search contact, create ticket if needed
const createOrUpdateTicket = async (customerData) => {
  // 1. Search if contact already exists
  const searchResponse = await fetch(
    `https://api.vambe.me/api/public/contacts/search?phone=${encodeURIComponent(customerData.phone)}`,
    {
      headers: {
        'x-api-key': 'your_api_key_here',
      },
    },
  );

  const existingContacts = await searchResponse.json();

  if (existingContacts.length > 0) {
    console.log('Contact exists, creating new ticket');
    // Contact exists - just create new ticket with updated metadata
  } else {
    console.log('New contact - creating first ticket');
  }

  // 2. Create ticket (works for both new and existing contacts)
  const ticketResponse = await fetch(
    'https://api.vambe.me/api/public/ticket/open/whatsapp/123456789',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': 'your_api_key_here',
      },
      body: JSON.stringify({
        to_phone_number: customerData.phone,
        stage_id: 'your_stage_id',
        contact_name: customerData.name,
        email: customerData.email,
        contact_metadata: {
          company: customerData.company,
          updated_at: new Date().toISOString(),
        },
        ticket_metadata: {
          ticket_type: customerData.inquiryType,
          source: 'api',
        },
        message: {
          content: `Hola ${customerData.name}! Gracias por contactarnos.`,
          ai_generated: false,
        },
      }),
    },
  );

  const result = await ticketResponse.json();
  console.log('Ticket created:', result.aiContactId);

  return result;
};
```


## OpenAPI

````yaml post /api/public/ticket/open/whatsapp/{phoneId}
openapi: 3.0.0
info:
  title: Vambe AI API
  description: Vambe AI documentation
  version: '1.0'
  contact: {}
servers:
  - url: https://api.vambe.me
    description: Production Server
security: []
tags:
  - name: Vambe AI
    description: ''
paths:
  /api/public/ticket/open/whatsapp/{phoneId}:
    post:
      tags:
        - Ticket
      summary: Open a new ticket for whatsapp
      operationId: CreateTicketPublicController_openTicketWhatsApp
      parameters:
        - name: phoneId
          required: true
          in: path
          schema:
            type: string
        - name: x-api-key
          in: header
          description: API key needed to authorize the request
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OpenTicketDto'
      responses:
        '200':
          description: Ticket created successfully
components:
  schemas:
    OpenTicketDto:
      type: object
      properties:
        contact_name:
          type: string
        to_phone_number:
          anyOf:
            - type: number
              minimum: 1
            - type: string
        contact_metadata:
          default: {}
          type: object
          additionalProperties: true
        ticket_metadata:
          default: {}
          type: object
          additionalProperties: true
        integration_data:
          type: object
          additionalProperties: true
        email:
          type: string
          format: email
          pattern: >-
            ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
        message:
          type: object
          properties:
            templateId:
              type: string
            content:
              type: string
            ai_generated:
              type: boolean
        stage_id:
          type: string
      required:
        - to_phone_number
        - contact_metadata
        - ticket_metadata
        - integration_data
        - message
        - stage_id

````