Skip to main content
POST
/
api
/
public
/
customer
/
upsert
/
info
curl --request POST \
  --url https://api.vambe.me/api/public/customer/upsert/info \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <x-api-key>' \
  --data '
{
  "channel": "whatsapp",
  "meta_data": {
    "source": "landing-page"
  }
}
'

Overview

Create or update a customer contact with intelligent AI-powered data processing. This endpoint automatically creates the contact if it doesn’t exist, or updates it if it does, along with optional metadata, custom field values, stage assignment, and agent assignment - all in a single request. Supports WhatsApp, Web-WhatsApp, and Webchat channels. For WhatsApp-based channels the contact is identified by phone number; for webchat, the contact is identified by an external user ID you provide.

Use Cases

  • CRM Data Import: Bulk import customer data from external CRM systems
  • Form Submissions: Create customers from web form submissions with flexible data
  • E-commerce Integration: Sync customer data from your e-commerce platform
  • Lead Capture: Capture leads with any structure of data
  • Customer Onboarding: Create customer profiles during signup flows
  • Data Migration: Migrate customer data from legacy systems
  • Webchat User Tracking: Create contacts for authenticated webchat users with your own external IDs

Authentication

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

Request Body

Common Fields

FieldTypeRequiredDescription
channelstringYesChannel type: "whatsapp", "web-whatsapp", or "webchat"
contact_namestringNoCustomer’s display name
contact_emailstringNoCustomer’s email address
stageIdstringNoPipeline stage UUID to assign the customer to
agentIdstringNoTeam member UUID to assign as responsible agent
meta_dataobjectNoAny additional customer data (AI will structure it)
custom_field_valuesarrayNoCustom field values to set on the customer (see below)

WhatsApp / Web-WhatsApp Fields

Required when channel is "whatsapp" or "web-whatsapp":
FieldTypeRequiredDescription
channel_phone_numberstringYesYour WhatsApp channel phone number (the sender)
contact_phone_numberstringYesCustomer’s phone number

Webchat Fields

Required when channel is "webchat":
FieldTypeRequiredDescription
channel_idstringYesUUID of your webchat channel
external_user_idstringYesYour unique identifier for the user (used to find or create the contact)

Custom Field Values

The custom_field_values array lets you set values on the associated customer using custom field definition keys. Each entry has:
FieldTypeRequiredDescription
keystringYesThe custom field definition key
valuestringYesThe value to set
If a custom field definition is marked as an identifier, the value will participate in customer deduplication automatically.
"custom_field_values": [
  { "key": "rut", "value": "12345678-9" },
  { "key": "company_name", "value": "Acme Corp" }
]

Response Structure

Returns the created or updated AI contact object:
FieldTypeDescription
idstring (UUID)Unique identifier for the contact
namestringContact’s name
phonestringContact’s phone number
emailstringContact’s email
platformstringChannel platform (whatsapp, web-whatsapp, webchat)
client_idstring (UUID)Your organization ID
ai_customer_idstring (UUID)Associated customer profile ID
created_atstring (ISO)Contact creation timestamp
default_stage_idstring (UUID)Current pipeline stage (if assigned)

Example Requests

WhatsApp Contact

curl --request POST \
  'https://api.vambe.me/api/public/customer/upsert/info' \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: your_api_key_here' \
  --data-raw '{
    "channel_phone_number": "+56987654321",
    "channel": "whatsapp",
    "contact_phone_number": "+56912345678",
    "contact_name": "Maria Rodriguez",
    "contact_email": "maria.rodriguez@example.com",
    "stageId": "550e8400-e29b-41d4-a716-446655440000",
    "agentId": "228d7a0d-9072-4ca8-939b-959b75cc606a",
    "meta_data": {
      "company": "Acme Corp",
      "position": "CEO",
      "industry": "Technology",
      "source": "LinkedIn Campaign"
    },
    "custom_field_values": [
      { "key": "company_name", "value": "Acme Corp" },
      { "key": "rut", "value": "12345678-9" }
    ]
  }'

Webchat Contact

curl --request POST \
  'https://api.vambe.me/api/public/customer/upsert/info' \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: your_api_key_here' \
  --data-raw '{
    "channel": "webchat",
    "channel_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "external_user_id": "user-abc-123",
    "contact_name": "Jane Doe",
    "contact_email": "jane@example.com",
    "custom_field_values": [
      { "key": "plan", "value": "premium" },
      { "key": "account_id", "value": "ACC-9876" }
    ]
  }'

Example Response

{
  "id": "df980fc8-b6db-4820-bf22-2969482d106d",
  "name": "Maria Rodriguez",
  "phone": "+56912345678",
  "email": "maria.rodriguez@example.com",
  "platform": "whatsapp",
  "client_id": "550e8400-e29b-41d4-a716-446655440000",
  "ai_customer_id": "660e8400-e29b-41d4-a716-446655440001",
  "created_at": "2024-09-30T10:00:00.000Z",
  "default_stage_id": "550e8400-e29b-41d4-a716-446655440000",
  "blocked": false,
  "chat_status": "UNATTENDED",
  "is_chat_read": false
}

Common Use Cases

1. Import CRM Data with Custom Fields

const importCRMCustomer = async (crmData) => {
  const response = await fetch(
    'https://api.vambe.me/api/public/customer/upsert/info',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': 'your_api_key_here',
      },
      body: JSON.stringify({
        channel_phone_number: '+56987654321',
        channel: 'whatsapp',
        contact_name: crmData.full_name,
        contact_phone_number: crmData.phone,
        contact_email: crmData.email,
        stageId: 'your_initial_stage_id',
        custom_field_values: [
          { key: 'company_name', value: crmData.company_name },
          { key: 'industry', value: crmData.industry_sector },
          { key: 'lead_score', value: String(crmData.qualification_score) },
        ],
        meta_data: {
          source: crmData.lead_source,
          notes: crmData.internal_notes,
        },
      }),
    },
  );

  const contact = await response.json();
  console.log(`Imported customer: ${contact.name} (${contact.id})`);
  return contact;
};

2. Create Webchat Contact from Authenticated User

const createWebchatContact = async (authenticatedUser) => {
  const response = await fetch(
    'https://api.vambe.me/api/public/customer/upsert/info',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': 'your_api_key_here',
      },
      body: JSON.stringify({
        channel: 'webchat',
        channel_id: 'your_webchat_channel_uuid',
        external_user_id: authenticatedUser.id,
        contact_name: authenticatedUser.displayName,
        contact_email: authenticatedUser.email,
        custom_field_values: [
          { key: 'plan', value: authenticatedUser.plan },
          { key: 'account_id', value: authenticatedUser.accountId },
        ],
      }),
    },
  );

  return await response.json();
};

3. Process Form Submission

const processContactForm = async (formData) => {
  const response = await fetch(
    'https://api.vambe.me/api/public/customer/upsert/info',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': 'your_api_key_here',
      },
      body: JSON.stringify({
        channel_phone_number: process.env.WHATSAPP_PHONE,
        channel: 'whatsapp',
        contact_name: formData.name,
        contact_phone_number: formData.phone,
        contact_email: formData.email,
        stageId: 'your_leads_stage_id',
        agentId: formData.assignToAgent || null,
        meta_data: {
          formType: 'Contact Form',
          submittedAt: new Date().toISOString(),
          subject: formData.subject,
          message: formData.message,
          source: formData.utm_source,
          campaign: formData.utm_campaign,
        },
      }),
    },
  );

  return await response.json();
};

4. E-commerce Customer Sync

const syncEcommerceCustomer = async (order) => {
  const response = await fetch(
    'https://api.vambe.me/api/public/customer/upsert/info',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': 'your_api_key_here',
      },
      body: JSON.stringify({
        channel_phone_number: '+56987654321',
        channel: 'whatsapp',
        contact_name: `${order.customer.first_name} ${order.customer.last_name}`,
        contact_phone_number: order.customer.phone,
        contact_email: order.customer.email,
        stageId: 'your_customers_stage_id',
        meta_data: {
          orderId: order.id,
          orderNumber: order.order_number,
          orderTotal: order.total_price,
          currency: order.currency,
          products: order.line_items.map((item) => item.title).join(', '),
        },
      }),
    },
  );

  return await response.json();
};

5. Bulk Customer Import

const bulkImportCustomers = async (customers) => {
  const results = [];

  for (const customer of customers) {
    try {
      const response = await fetch(
        'https://api.vambe.me/api/public/customer/upsert/info',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'x-api-key': 'your_api_key_here',
          },
          body: JSON.stringify({
            channel_phone_number: process.env.WHATSAPP_PHONE,
            channel: 'whatsapp',
            contact_name: customer.name,
            contact_phone_number: customer.phone,
            contact_email: customer.email,
            custom_field_values: customer.customFields || [],
            meta_data: customer.additionalData,
          }),
        },
      );

      const result = await response.json();
      results.push({ phone: customer.phone, success: true, id: result.id });
    } catch (error) {
      results.push({
        phone: customer.phone,
        success: false,
        error: error.message,
      });
    }

    // Add delay to avoid rate limiting
    await new Promise((resolve) => setTimeout(resolve, 200));
  }

  console.log(
    `Imported ${results.filter((r) => r.success).length} of ${customers.length} customers`,
  );

  return results;
};

Key Features

Upsert Behavior

The contact lookup depends on the channel:
ChannelIdentified by
whatsappcontact_phone_number on the given channel
web-whatsappcontact_phone_number on the given channel
webchatexternal_user_id on the given channel_id
  • If contact exists: Returns the existing contact and applies any updates (name, agent, stage, metadata, custom fields)
  • If contact doesn’t exist: Creates a new contact and customer
  • Idempotent: Safe to call multiple times with the same data

Custom Field Values

  • Values are set on the customer (not the contact), so they are shared across all contacts for that customer
  • Fields are identified by their definition key (e.g. "rut", "company_name")
  • If a field definition is marked as an identifier, the value participates in automatic customer deduplication
  • All custom field definition keys must exist beforehand; the endpoint returns a 400 error listing any missing keys
  • Supported field types: text, number, date, boolean, options

AI-Powered Data Processing

The meta_data field uses AI to:
  • Extract structured data from unstructured metadata
  • Match fields to your custom field definitions
  • Convert data types automatically
  • Handle flexible formats for phone numbers, dates, etc.

Automatic Processing

All in one request:
  1. Create/update contact
  2. Assign to pipeline stage
  3. Assign to agent
  4. Process and save metadata
  5. Upsert custom field values

Channel Types

ChannelDescriptionRequired Fields
whatsappWhatsApp Business APIchannel_phone_number, contact_phone_number
web-whatsappWhatsApp Web (QR Code)channel_phone_number, contact_phone_number
webchatWebchat widgetchannel_id, external_user_id

Error Responses

Status CodeDescription
400Bad Request - Missing required fields for the channel, or invalid custom field keys
401Unauthorized - Invalid or missing API key
500Internal Server Error - Something went wrong

Important Notes

  • Channel Phone Number: Must be a WhatsApp number/channel you own and have configured
  • Channel ID: Must be a webchat channel UUID you own
  • External User ID: Your own unique identifier for the webchat user; used to deduplicate contacts
  • Phone Format: Automatically cleaned (spaces, dashes, etc. are removed)
  • Custom Field Keys: Must match existing custom field definitions; create definitions first in the Vambe dashboard
  • AI Processing: Metadata is processed asynchronously with AI
  • Immediate Response: Returns contact immediately, metadata processing continues in background

Best Practices

1. Use Custom Fields for Structured Data

Prefer custom_field_values over meta_data when you have well-defined fields. Custom fields are typed, searchable, and can be marked as identifiers for deduplication.
// Preferred: structured custom fields
{
  "custom_field_values": [
    { "key": "company_name", "value": "Acme Corp" },
    { "key": "rut", "value": "12345678-9" },
    { "key": "plan", "value": "enterprise" }
  ]
}

// Use meta_data for unstructured/dynamic data
{
  "meta_data": {
    "notes": "Met at conference, interested in premium plan",
    "source": "Trade Show 2025"
  }
}

2. Include Source Information

meta_data: {
  source: 'LinkedIn Campaign',
  importedAt: new Date().toISOString(),
  importedBy: 'CRM Sync Script',
}

3. Validate Data Before Sending

const validateAndUpsert = async (customerData) => {
  if (!customerData.phone || !customerData.name) {
    throw new Error('Phone and name are required');
  }

  const cleanPhone = customerData.phone.replace(/[^\d+]/g, '');

  return await fetch('https://api.vambe.me/api/public/customer/upsert/info', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': 'your_api_key_here',
    },
    body: JSON.stringify({
      channel_phone_number: process.env.WHATSAPP_PHONE,
      channel: 'whatsapp',
      contact_phone_number: cleanPhone,
      contact_name: customerData.name,
      contact_email: customerData.email,
      custom_field_values: customerData.customFields || [],
      meta_data: customerData.additionalData,
    }),
  }).then((r) => r.json());
};

Migration from Deprecated Endpoint

If you’re migrating from the deprecated POST /api/public/whatsapp/message/note/send endpoint: Old:
POST /api/public/whatsapp/message/note/send
{
  "to_phone": "+56912345678",
  "from_phone": "your_phone",
  "note": "Internal note",
  "contact_name": "John Doe",
  "meta_data": { ... }
}
New (This endpoint):
POST /api/public/customer/upsert/info
{
  "channel_phone_number": "your_phone",
  "channel": "whatsapp",
  "contact_phone_number": "+56912345678",
  "contact_name": "John Doe",
  "meta_data": {
    "internal_note": "Internal note",
    ...
  }
}
The new endpoint provides better structure and automatic AI processing of all metadata!

Headers

x-api-key
string
required

API key needed to authorize the request

Body

application/json
channel
enum<string>
required

Channel type for the contact.

Available options:
whatsapp,
web-whatsapp,
webchat
meta_data
object
required

Arbitrary metadata to set on the contact.

channel_phone_number
string

Phone number or ID of the channel. Required for whatsapp/web-whatsapp.

Minimum string length: 1
channel_id
string<uuid>

UUID of the webchat channel. Required for webchat.

Pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
stageId
string<uuid>

Stage ID to assign to the contact.

Pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
agentId
string<uuid>

Agent ID to assign to the contact.

Pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
contact_phone_number
string

Phone number of the contact. Required for whatsapp/web-whatsapp.

external_user_id
string

External user identifier used to find or create the webchat contact. Required for webchat.

Minimum string length: 1
contact_email
string

Email of the contact.

contact_name
string

Display name of the contact.

custom_field_values
object[]

Custom field values to upsert on the customer, identified by definition key.

Response

Contact created or found successfully.