Create a contact and add a tag
You need a key with the level Draft or higher (permission contacts:write). Nothing in this guide sends a message.
The three steps tell one story: Mia is created, gets the tag vip, and is read back with that tag. The answers on this page belong together.
#1. Create the contact
curl -X POST "https://api.smartchat.marketing/v1/contacts" \
-H "Authorization: Bearer $SMARTCHAT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "Mia Muster",
"phone": "+4915112345678",
"email": "mia@example.com"
}'import os
import uuid
import requests
response = requests.post(
"https://api.smartchat.marketing/v1/contacts",
headers={
"Authorization": "Bearer " + os.environ["SMARTCHAT_API_KEY"],
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"name": "Mia Muster",
"phone": "+4915112345678",
"email": "mia@example.com",
},
)
response.raise_for_status()
print(response.json())const response = await fetch("https://api.smartchat.marketing/v1/contacts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMARTCHAT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"name": "Mia Muster",
"phone": "+4915112345678",
"email": "mia@example.com"
}),
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());Response (201):
{
"object": "contact",
"id": "con_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
"name": "Mia Muster",
"phone": "+4915112345678",
"email": "mia@example.com",
"language": "en",
"status": "unconfirmed",
"optin_whatsapp": "none",
"optin_whatsapp_at": null,
"purpose": "marketing",
"source": "api",
"tags": [],
"tag_details": [],
"created_at": "2026-10-25T09:41:07Z"
}Calls that create things need an Idempotency-Key (why). The new contact has optin_whatsapp set to none until the contact confirms. The API never sets a contact to confirmed.
If a contact with the same phone number or email exists, the answer is contact_already_exists with the ID of the existing contact in existing_id. Change that contact with update_contact instead.
#2. Add a tag
Tags are added to one or more contacts at once. The tag is created if it does not exist yet.
curl -X POST "https://api.smartchat.marketing/v1/contacts/tags" \
-H "Authorization: Bearer $SMARTCHAT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"contact_ids": [
"con_0f8c1a2e4b7d4c3e9a5b6d7e8f901234"
],
"add_tags": [
"vip"
]
}'import os
import uuid
import requests
response = requests.post(
"https://api.smartchat.marketing/v1/contacts/tags",
headers={
"Authorization": "Bearer " + os.environ["SMARTCHAT_API_KEY"],
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"contact_ids": [
"con_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
],
"add_tags": [
"vip",
],
},
)
response.raise_for_status()
print(response.json())const response = await fetch("https://api.smartchat.marketing/v1/contacts/tags", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMARTCHAT_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"contact_ids": [
"con_0f8c1a2e4b7d4c3e9a5b6d7e8f901234"
],
"add_tags": [
"vip"
]
}),
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());Response (200):
{
"object": "contact_tags_update",
"updated": 1,
"unchanged": 0,
"not_found": 0,
"failed": 0,
"results": [
{
"contact_id": "con_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
"status": "updated",
"tags": [
"vip"
],
"error_code": null
}
]
}#3. Read the contact back
curl "https://api.smartchat.marketing/v1/contacts/con_0f8c1a2e4b7d4c3e9a5b6d7e8f901234" \
-H "Authorization: Bearer $SMARTCHAT_API_KEY"import os
import requests
response = requests.get(
"https://api.smartchat.marketing/v1/contacts/con_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
headers={"Authorization": "Bearer " + os.environ["SMARTCHAT_API_KEY"]},
)
response.raise_for_status()
print(response.json())const response = await fetch("https://api.smartchat.marketing/v1/contacts/con_0f8c1a2e4b7d4c3e9a5b6d7e8f901234", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.SMARTCHAT_API_KEY}`,
},
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());Response (200):
{
"object": "contact",
"id": "con_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
"name": "Mia Muster",
"phone": "+4915112345678",
"email": "mia@example.com",
"language": "en",
"status": "unconfirmed",
"optin_whatsapp": "none",
"optin_whatsapp_at": null,
"purpose": "marketing",
"source": "api",
"tags": [
"vip"
],
"tag_details": [
{
"name": "vip",
"origin": "manual",
"added_at": "2026-10-25T09:42:30Z"
}
],
"created_at": "2026-10-25T09:41:07Z"
}The contact now has the tag vip.
#Next
- Ask the contact for the opt-in:
create_optin_confirmations. See Consent and the 24-hour window. - Find contacts by tag:
search_contacts.