Create tags for a contact
curl --request POST \
--url https://api.vambe.me/api/public/channels/{channelType}/{platformIdentifier}/tags \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"tags": [
"<string>"
]
}
'const options = {
method: 'POST',
headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({tags: ['<string>']})
};
fetch('https://api.vambe.me/api/public/channels/{channelType}/{platformIdentifier}/tags', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.vambe.me/api/public/channels/{channelType}/{platformIdentifier}/tags"
payload = { "tags": ["<string>"] }
headers = {
"x-api-key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"status": "success",
"createdCount": 2,
"assignedCount": 3,
"notAssignedCount": 1,
"notAssignedTags": [
"vip-ticket"
],
"details": "Some tags were not assigned because they are TICKET type and the contact has no active ticket."
}Channels Management
Create tags for a contact
Creates tags for the contact for the specified channel. TICKET-type tags are only assigned when the contact has an active ticket. The response reports counts for created, assigned, and not-assigned tags, plus details explaining why some could not be assigned.
POST
/
api
/
public
/
channels
/
{channelType}
/
{platformIdentifier}
/
tags
Create tags for a contact
curl --request POST \
--url https://api.vambe.me/api/public/channels/{channelType}/{platformIdentifier}/tags \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"tags": [
"<string>"
]
}
'const options = {
method: 'POST',
headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({tags: ['<string>']})
};
fetch('https://api.vambe.me/api/public/channels/{channelType}/{platformIdentifier}/tags', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.vambe.me/api/public/channels/{channelType}/{platformIdentifier}/tags"
payload = { "tags": ["<string>"] }
headers = {
"x-api-key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"status": "success",
"createdCount": 2,
"assignedCount": 3,
"notAssignedCount": 1,
"notAssignedTags": [
"vip-ticket"
],
"details": "Some tags were not assigned because they are TICKET type and the contact has no active ticket."
}Overview
Create and assign tags to a contact using their channel information (phone number or username) instead of contact ID. This endpoint is perfect when you know the contact’s phone/username but not their Vambe contact ID. The endpoint automatically creates tags that don’t exist and intelligently handles TICKET-type tags (only assigned when the contact has an active ticket).Use Cases
- Webhook Integration: Tag contacts from external webhooks using phone numbers
- Form Submissions: Tag contacts from web forms without looking up their ID
- CSV Imports: Bulk tag contacts using phone numbers from spreadsheets
- E-commerce Events: Tag customers after purchases using their phone
- Marketing Automation: Auto-tag contacts from campaign responses
- Support Tickets: Tag customers when tickets are created in external systems
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 |
|---|---|---|---|
channelType | string | Yes | Channel type: “whatsapp”, “web-whatsapp”, “instagram”, “playground” |
platformIdentifier | string | Yes | Phone number (with country code) or username |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
tags | string[] | Yes | Array of tag names (strings) to create/assign |
Response Structure
| Field | Type | Description |
|---|---|---|
status | string | Status of the operation (always “success”) |
createdCount | number | Number of new tags created |
assignedCount | number | Number of tags successfully assigned to the contact |
notAssignedCount | number | Number of tags that couldn’t be assigned |
notAssignedTags | string[] | Names of tags that weren’t assigned |
details | string | Explanation of why some tags weren’t assigned (if any) |
Example Request
curl --request POST \
'https://api.vambe.me/api/public/channels/whatsapp/+56912345678/tags' \
--header 'Content-Type: application/json' \
--header 'x-api-key: your_api_key_here' \
--data-raw '{
"tags": ["vip-customer", "interested-in-premium", "contacted-2024"]
}'
Example Response
{
"status": "success",
"createdCount": 2,
"assignedCount": 3,
"notAssignedCount": 0,
"notAssignedTags": [],
"details": null
}
Example Response with Ticket Tags
When a contact has no active ticket and you try to assign TICKET-type tags:{
"status": "success",
"createdCount": 1,
"assignedCount": 2,
"notAssignedCount": 1,
"notAssignedTags": ["urgent-ticket"],
"details": "Some tags were not assigned because they are TICKET type and the contact has no active ticket."
}
Common Use Cases
1. Tag Contact from Webhook
const tagContactFromWebhook = async (phoneNumber, eventTags) => {
const response = await fetch(
`https://api.vambe.me/api/public/channels/whatsapp/${phoneNumber}/tags`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
tags: eventTags,
}),
},
);
const result = await response.json();
console.log(`Created ${result.createdCount} new tags`);
console.log(`Assigned ${result.assignedCount} tags to contact`);
return result;
};
// Usage from webhook
// tagContactFromWebhook('+56912345678', ['webinar-attendee', 'lead']);
2. Tag Customer After Purchase
const tagAfterPurchase = async (customerPhone, productCategory, orderValue) => {
const tags = ['customer', `purchased-${productCategory}`];
// Add VIP tag for high-value purchases
if (orderValue > 500) {
tags.push('vip-customer', 'high-value-order');
}
const response = await fetch(
`https://api.vambe.me/api/public/channels/whatsapp/${customerPhone}/tags`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
tags: tags,
}),
},
);
return await response.json();
};
// Usage
tagAfterPurchase('+56912345678', 'electronics', 750);
3. Tag from Form Submission
const tagFromContactForm = async (formData) => {
const phone = formData.phone;
const tags = ['contact-form-lead', `interest-${formData.interest}`];
// Add urgency tag if requested
if (formData.urgency === 'high') {
tags.push('urgent-contact');
}
const response = await fetch(
`https://api.vambe.me/api/public/channels/whatsapp/${phone}/tags`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
tags: tags,
}),
},
);
const result = await response.json();
if (result.notAssignedCount > 0) {
console.warn('Some tags not assigned:', result.notAssignedTags);
console.warn('Reason:', result.details);
}
return result;
};
4. Bulk Tag from CSV
const bulkTagFromCSV = async (csvData) => {
const results = [];
for (const row of csvData) {
try {
const result = await fetch(
`https://api.vambe.me/api/public/channels/whatsapp/${row.phone}/tags`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
tags: row.tags.split(','), // CSV might have "tag1,tag2,tag3"
}),
},
);
const data = await result.json();
results.push({ phone: row.phone, success: true, ...data });
} catch (error) {
results.push({ phone: row.phone, success: false, error: error.message });
}
// Add delay to avoid rate limiting
await new Promise((resolve) => setTimeout(resolve, 100));
}
console.log(
`Tagged ${results.filter((r) => r.success).length} of ${csvData.length} contacts`,
);
return results;
};
5. Tag Instagram Contact
const tagInstagramContact = async (username, tags) => {
const response = await fetch(
`https://api.vambe.me/api/public/channels/instagram/${username}/tags`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
tags: tags,
}),
},
);
return await response.json();
};
// Usage
tagInstagramContact('customer_username', ['dm-lead', 'interested-in-product']);
6. Campaign Response Tagging
const tagCampaignResponse = async (phoneNumber, campaignName, responseType) => {
const tags = [
`campaign-${campaignName}`,
`response-${responseType}`,
'engaged-contact',
];
const response = await fetch(
`https://api.vambe.me/api/public/channels/whatsapp/${phoneNumber}/tags`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
tags: tags,
}),
},
);
const result = await response.json();
return {
...result,
campaignName,
phoneNumber,
};
};
// Usage
tagCampaignResponse('+56912345678', 'summer-sale-2024', 'clicked-link');
Channel Types
| Channel Type | Platform Identifier Format | Example |
|---|---|---|
whatsapp | Phone with country code | +56912345678 |
web-whatsapp | Phone with country code | +56912345678 |
instagram | Username (no @) | customer_username |
playground | Phone or identifier | +56912345678 |
Platform Identifier Formatting
The endpoint automatically cleans the platform identifier:- Removes
+symbols - Removes spaces
- Normalizes the format
+5691234567856912345678+569 1234 5678
Tag Creation Behavior
Automatic Tag Creation
If a tag doesn’t exist, it will be automatically created for your organization: Request:{ "tags": ["new-tag-2024"] }
- System checks if tag “new-tag-2024” exists
- If not, creates it
- Assigns it to the contact
- Returns
createdCount: 1
Tag Assignment
- CONTACT Tags: Always assigned to the contact
- TICKET Tags: Only assigned if contact has an active ticket
Response Breakdown
Example Scenario:- Request tags:
["customer", "vip", "urgent-ticket"] - “customer” and “vip” exist as CONTACT tags
- “urgent-ticket” exists as a TICKET tag
- Contact has NO active ticket
{
"createdCount": 0,
"assignedCount": 2,
"notAssignedCount": 1,
"notAssignedTags": ["urgent-ticket"],
"details": "Some tags were not assigned because they are TICKET type and the contact has no active ticket."
}
Error Responses
| Status Code | Description |
|---|---|
| 400 | Bad Request - Invalid channel type or missing tags |
| 401 | Unauthorized - Invalid or missing API key |
| 404 | Not Found - Contact not found for the specified channel/identifier |
| 500 | Internal Server Error - Something went wrong |
Important Notes
- Auto-Create: Tags are automatically created if they don’t exist
- Additive Operation: This endpoint adds tags, it doesn’t replace existing ones
- Case Sensitive: Tag names are case-sensitive
- Duplicates: Duplicate tags in the array won’t create duplicate assignments
- Contact Lookup: Contact must exist with the specified platform identifier
- Phone Format: Phone numbers should include country code (e.g., +56 for Chile)
Differences from PATCH Endpoint
| Feature | POST (This Endpoint) | PATCH (Update Tags) |
|---|---|---|
| Lookup Method | Phone/username | Contact ID (UUID) |
| Tag Format | Tag names (strings) | Tag IDs (numbers) |
| Behavior | Adds tags (additive) | Replaces all tags |
| Tag Creation | Auto-creates missing tags | Requires existing tag IDs |
| Response Detail | Created/assigned/not-assigned counts | Simple success + count |
Best Practices
1. Normalize Phone Numbers
const normalizePhone = (phone) => {
// Remove all non-numeric characters except +
return phone.replace(/[^\d+]/g, '');
};
const tagByPhone = async (rawPhone, tags) => {
const normalizedPhone = normalizePhone(rawPhone);
return await fetch(
`https://api.vambe.me/api/public/channels/whatsapp/${normalizedPhone}/tags`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({ tags }),
},
).then((r) => r.json());
};
2. Handle Ticket Tags Gracefully
const tagWithTicketCheck = async (phone, tags) => {
const response = await fetch(
`https://api.vambe.me/api/public/channels/whatsapp/${phone}/tags`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({ tags }),
},
);
const result = await response.json();
if (result.notAssignedCount > 0) {
console.log(`Warning: ${result.notAssignedCount} tags not assigned`);
console.log('Reason:', result.details);
console.log('Tags:', result.notAssignedTags);
}
return result;
};
3. Use Consistent Tag Naming
// Good: kebab-case, descriptive
const goodTags = [
'vip-customer',
'purchased-electronics',
'newsletter-subscriber',
];
// Avoid: mixed case, spaces, unclear
const badTags = ['VIP Customer', 'bought stuff', 'tag1'];
Related Endpoints
- GET /api/public/tags - Get all available tags and their IDs
- PATCH /api/public/contact/tags/ - Update tags using contact ID
- GET /api/public/contact//info - Get contact info including tags
- POST /api/public/ticket/open/web-whatsapp/ - Create ticket (enables TICKET tags)
Complete Workflow Example
// Complete workflow: Form submission -> Contact tagging
const handleFormSubmission = async (formData) => {
const { name, phone, email, interest, source } = formData;
// 1. Normalize phone
const cleanPhone = phone.replace(/[^\d+]/g, '');
// 2. Determine tags based on form data
const tags = [
'contact-form-lead',
`source-${source}`,
`interest-${interest}`,
`submitted-${new Date().toISOString().split('T')[0]}`,
];
// 3. Add urgency tag if email includes 'urgent'
if (email.includes('urgent')) {
tags.push('urgent-contact');
}
// 4. Tag the contact
try {
const result = await fetch(
`https://api.vambe.me/api/public/channels/whatsapp/${cleanPhone}/tags`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.VAMBE_API_KEY,
},
body: JSON.stringify({ tags }),
},
);
const data = await result.json();
console.log(`✅ Tagged contact ${name}`);
console.log(` Created: ${data.createdCount} tags`);
console.log(` Assigned: ${data.assignedCount} tags`);
return {
success: true,
...data,
};
} catch (error) {
console.error('Failed to tag contact:', error);
return {
success: false,
error: error.message,
};
}
};
Headers
API key for request authorization
Path Parameters
The platform identifier for the contact, e.g. phone number (with country code) or username
The type of channel to create a tag for
Available options:
whatsapp, playground, web-whatsapp, instagram Body
application/json
Response
Tags processed successfully
Was this page helpful?
