Update metadata to an AI contact
curl --request POST \
--url https://api.vambe.me/api/public/contact/{aiContactId}/update-metadata \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '{
"metadata": {}
}'const options = {
method: 'POST',
headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({metadata: {}})
};
fetch('https://api.vambe.me/api/public/contact/{aiContactId}/update-metadata', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.vambe.me/api/public/contact/{aiContactId}/update-metadata"
payload = { "metadata": {} }
headers = {
"x-api-key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)Contact Management
Update metadata to an AI contact
POST
/
api
/
public
/
contact
/
{aiContactId}
/
update-metadata
Update metadata to an AI contact
curl --request POST \
--url https://api.vambe.me/api/public/contact/{aiContactId}/update-metadata \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '{
"metadata": {}
}'const options = {
method: 'POST',
headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({metadata: {}})
};
fetch('https://api.vambe.me/api/public/contact/{aiContactId}/update-metadata', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.vambe.me/api/public/contact/{aiContactId}/update-metadata"
payload = { "metadata": {} }
headers = {
"x-api-key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)Overview
Update or add custom metadata fields to a contact. Metadata allows you to store any additional information about a contact beyond the standard fields (name, email, phone). This endpoint is intelligent - it processes unstructured data and automatically fills custom field definitions if they exist in your account. Field keys are automatically converted to snake_case for consistency.Use Cases
- E-commerce Data: Store order history, lifetime value, preferred products
- Customer Segmentation: Add custom attributes for targeting and personalization
- CRM Integration: Sync custom fields from external CRM systems
- Lead Scoring: Store qualification scores, lead source, conversion probability
- Business Context: Add company info, industry, decision maker status
- Behavioral Data: Track user actions, preferences, interaction history
- Support Information: Store account tier, support plan, SLA requirements
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 |
|---|---|---|---|
aiContactId | string (UUID) | Yes | Unique identifier of the contact |
Request Body
The request body is a flexible object where you can include any key-value pairs:| Field | Type | Required | Description |
|---|---|---|---|
{any} | any | No | Any custom field as key-value pair |
{
"company": "Acme Corp",
"industry": "Technology",
"employeeCount": "500-1000",
"annualRevenue": "5000000",
"leadScore": "85",
"source": "website",
"interests": "AI, Automation",
"custom_field_1": "value1"
}
Response Structure
The endpoint returns an array of updated custom field values:| Field | Type | Description |
|---|---|---|
| Array | array | Array of custom field value objects that were updated |
Example Request
curl --request POST \
'https://api.vambe.me/api/public/contact/1937bd2c-a13c-4365-af06-43af9a988e36/update-metadata' \
--header 'Content-Type: application/json' \
--header 'x-api-key: your_api_key_here' \
--data-raw '{
"company": "Acme Corporation",
"position": "CEO",
"industry": "Technology",
"employeeCount": "100-500",
"annualRevenue": "2000000",
"leadScore": 95,
"leadSource": "LinkedIn Campaign",
"interestedProducts": "Enterprise Plan, API Access",
"notes": "Very interested in automation features",
"budget": "50000-100000",
"decisionMaker": true,
"expectedCloseDate": "2024-12-31"
}'
Example Response
[
{
"id": 123,
"key": "company",
"value": "Acme Corporation",
"custom_field_definition_id": 45
},
{
"id": 124,
"key": "position",
"value": "CEO",
"custom_field_definition_id": 46
},
{
"id": 125,
"key": "lead_score",
"value": "95",
"custom_field_definition_id": 47
}
]
Common Use Cases
1. Update E-commerce Customer Data
const updateEcommerceData = async (contactId, orderData) => {
const response = await fetch(
`https://api.vambe.me/api/public/contact/${contactId}/update-metadata`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
totalOrders: orderData.orderCount.toString(),
lifetimeValue: orderData.totalSpent.toString(),
averageOrderValue: orderData.averageValue.toString(),
lastPurchaseDate: orderData.lastPurchase,
favoriteCategory: orderData.topCategory,
customerSince: orderData.firstOrderDate,
vipStatus: orderData.isVIP ? 'Yes' : 'No',
}),
},
);
const result = await response.json();
console.log(`Updated ${result.length} metadata fields`);
return result;
};
2. Lead Qualification Data
const updateLeadQualification = async (contactId, qualificationData) => {
const response = await fetch(
`https://api.vambe.me/api/public/contact/${contactId}/update-metadata`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
leadScore: qualificationData.score,
leadGrade: qualificationData.grade, // A, B, C, D
qualificationDate: new Date().toISOString(),
budgetRange: qualificationData.budget,
timeframe: qualificationData.timeframe, // Immediate, 1-3 months, 3-6 months
authority: qualificationData.isDecisionMaker
? 'Decision Maker'
: 'Influencer',
need: qualificationData.painPoints,
source: qualificationData.leadSource,
}),
},
);
return await response.json();
};
3. Sync from External CRM
const syncFromExternalCRM = async (contactId, crmData) => {
// Map CRM fields to Vambe metadata
const metadata = {
crmContactId: crmData.id,
accountType: crmData.account_type,
industry: crmData.industry,
companySize: crmData.employee_count,
annualRevenue: crmData.revenue,
territory: crmData.sales_territory,
accountOwner: crmData.owner_name,
lastActivityDate: crmData.last_activity,
stage: crmData.sales_stage,
probability: crmData.win_probability,
};
const response = await fetch(
`https://api.vambe.me/api/public/contact/${contactId}/update-metadata`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify(metadata),
},
);
return await response.json();
};
4. Add Support Plan Information
const updateSupportPlan = async (contactId, planDetails) => {
const response = await fetch(
`https://api.vambe.me/api/public/contact/${contactId}/update-metadata`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
supportPlan: planDetails.tier, // Basic, Premium, Enterprise
planStartDate: planDetails.startDate,
planExpiryDate: planDetails.expiryDate,
slaLevel: planDetails.sla, // 24h, 12h, 4h
dedicatedManager: planDetails.hasManager ? 'Yes' : 'No',
maxTicketsPerMonth: planDetails.ticketLimit.toString(),
supportChannels: planDetails.channels.join(', '), // Email, Phone, Chat
}),
},
);
return await response.json();
};
5. Update Form Submission Data
const saveFormSubmission = async (contactId, formData) => {
const response = await fetch(
`https://api.vambe.me/api/public/contact/${contactId}/update-metadata`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
formName: formData.formType,
submissionDate: new Date().toISOString(),
utmSource: formData.utm_source,
utmMedium: formData.utm_medium,
utmCampaign: formData.utm_campaign,
referrer: formData.referrer,
landingPage: formData.landingPage,
message: formData.userMessage,
}),
},
);
return await response.json();
};
6. Bulk Update Multiple Contacts
const bulkUpdateMetadata = async (contactIds, metadata) => {
const results = [];
for (const contactId of contactIds) {
try {
const response = await fetch(
`https://api.vambe.me/api/public/contact/${contactId}/update-metadata`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify(metadata),
},
);
const result = await response.json();
results.push({ contactId, success: true, fieldsUpdated: result.length });
} catch (error) {
results.push({ contactId, success: false, error: error.message });
}
// Add small delay to avoid rate limiting
await new Promise((resolve) => setTimeout(resolve, 100));
}
return results;
};
// Usage: Apply same metadata to multiple contacts
bulkUpdateMetadata(['contact-id-1', 'contact-id-2'], {
campaignParticipant: 'Summer Sale 2024',
enrolled: new Date().toISOString(),
});
Key Behavior & Features
Automatic Snake Case Conversion
Field keys are automatically converted to snake_case: You send:{ "companyName": "Acme Corp" }
Stored as: { "company_name": "Acme Corp" }
You send: { "LeadScore": "95" }
Stored as: { "lead_score": "95" }
Intelligent Field Processing
The endpoint uses AI to process unstructured data and match it to your custom field definitions:- If a custom field definition exists for a key, it will be used
- Data types are automatically formatted based on field definitions
- Missing fields are created as needed
- All fields are updated (not merged)
Update Behavior
- Additive: New metadata fields are added to existing ones
- Overwrite: If a field already exists, its value is updated
- Flexible Types: Values can be strings, numbers, booleans, or objects (converted to strings)
- No Validation: You can send any fields - they donβt need to be pre-defined
Data Type Handling
Metadata values should generally be sent as strings for consistency:| Data Type You Send | How Itβs Stored | Example |
|---|---|---|
| String | As is | "Acme Corp" |
| Number | Converted to string | 95 β "95" |
| Boolean | Converted to string | true β "true" |
| Object | JSON string | Converted to JSON |
| Array | Joined string | ["a","b"] β "a, b" |
Error Responses
| Status Code | Description |
|---|---|
| 400 | Bad Request - Invalid metadata format |
| 401 | Unauthorized - Invalid or missing API key |
| 404 | Not Found - Contact not found |
| 500 | Internal Server Error - Something went wrong |
Important Notes
- No Field Limit: You can send as many metadata fields as needed
- Size Limit: Very large metadata objects may be rejected (keep under 1MB)
- Field Names: Use descriptive, consistent naming (prefer snake_case or camelCase)
- Retrieve Metadata: Use GET
/api/public/contact/{aiContactId}/infoto see all metadata - Type Coercion: All values are ultimately stored as strings in custom fields
- Activity Logging: Metadata updates are logged in contact activity
Best Practices
1. Use Consistent Field Names
// Good: Consistent naming convention
const goodMetadata = {
leadSource: 'Website',
leadScore: '85',
companyName: 'Acme Corp',
isQualified: 'true',
};
// Avoid: Inconsistent naming
const badMetadata = {
'Lead Source': 'Website', // Has spaces
LeadScore: '85', // Mixed case
company_name: 'Acme Corp', // Different convention
qualified: 'true', // Missing is prefix
};
2. Include Timestamps
const metadataWithTimestamps = {
lastUpdated: new Date().toISOString(),
dataSource: 'API Import',
importBatch: 'batch-2024-09-30',
// ... other fields
};
3. Validate Before Sending
const validateAndUpdateMetadata = (contactId, metadata) => {
// Remove null/undefined values
const cleanMetadata = Object.entries(metadata).reduce((acc, [key, value]) => {
if (value !== null && value !== undefined && value !== '') {
acc[key] = String(value); // Ensure all values are strings
}
return acc;
}, {});
return fetch(
`https://api.vambe.me/api/public/contact/${contactId}/update-metadata`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify(cleanMetadata),
},
);
};
4. Handle Errors Gracefully
const safeUpdateMetadata = async (contactId, metadata) => {
try {
const response = await fetch(
`https://api.vambe.me/api/public/contact/${contactId}/update-metadata`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify(metadata),
},
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
return await response.json();
} catch (error) {
console.error('Failed to update metadata:', error);
// Maybe retry or log to error tracking
throw error;
}
};
Related Endpoints
- GET /api/public/contact//info - Get contact info including metadata
- POST /api/public/ticket/open/web-whatsapp/ - Create ticket with metadata
- PATCH /api/public/contact/tags/ - Update contact tags
Complete Workflow Example
// Complete workflow: Create ticket with metadata, then update it
const createAndEnrichContact = async (phoneNumber, initialData) => {
// 1. Create ticket/contact
const createResponse = await fetch(
'https://api.vambe.me/api/public/ticket/open/web-whatsapp/your_phone_id',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
to_phone_number: phoneNumber,
stage_id: 'your_stage_id',
contact_name: initialData.name,
contact_metadata: {
source: initialData.source,
},
}),
},
);
const { aiContactId } = await createResponse.json();
// 2. Enrich with additional metadata after qualification
const enrichResponse = await fetch(
`https://api.vambe.me/api/public/contact/${aiContactId}/update-metadata`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'your_api_key_here',
},
body: JSON.stringify({
company: initialData.company,
industry: initialData.industry,
employeeCount: initialData.size,
leadScore: calculateLeadScore(initialData),
enrichedAt: new Date().toISOString(),
dataQuality: 'High',
}),
},
);
const metadata = await enrichResponse.json();
console.log(`Created and enriched contact ${aiContactId}`);
console.log(`Updated ${metadata.length} metadata fields`);
return { aiContactId, metadata };
};
Metadata vs Tags
| Feature | Metadata (This Endpoint) | Tags |
|---|---|---|
| Purpose | Store detailed data | Categorize/label contacts |
| Format | Key-value pairs | Simple labels |
| Quantity | Unlimited fields | Multiple tags |
| Search | By field name and value | By tag name |
| Use Case | Customer details, scores, history | Segments, categories, flags |
Was this page helpful?
