Skip to content

API: Contacts & tags

Contacts are the heart of the CRM, and the API mirrors what the app can do with them — including the consent rules. See the API overview for authentication and errors.

The contact object

{
"id": "0d9f7c3e-…",
"phone": "+4915112345678",
"name": "Ada Example",
"locale": "de",
"source": "api",
"opt_in_status": "confirmed",
"attributes": { "company": "Example GmbH" },
"tags": ["webinar", "vip"],
"last_inbound_at": "2026-07-01T18:22:10Z",
"last_outbound_at": "2026-07-01T18:22:41Z",
"awaiting_reply": false,
"assigned_user_id": null,
"assigned_team_id": null,
"created_at": "2026-06-12T09:03:44Z"
}

last_inbound_at is the contact’s last message to you, last_outbound_at your last message to them — from any sender (AI agent, teammate, automation, broadcast, API). awaiting_reply is true while the contact wrote after your last message, i.e. the chat is waiting for an answer.

opt_in_status is one of none, pending, confirmed, opted_out. Campaigns only go to confirmed contacts; opted_out contacts are never messaged.

Create or update — POST /v1/contacts

Upserts by phone number: if the phone already exists in the workspace, the contact is updated; otherwise it is created (and the Contact is created automation trigger fires).

Terminal window
curl -s https://app.nybero.com/api/v1/contacts \
-H "Authorization: Bearer $NYBERO_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "0151 1234 5678",
"default_country": "DE",
"name": "Ada Example",
"source": "landingpage",
"attributes": { "company": "Example GmbH" },
"tags": ["webinar"],
"opt_in": true,
"consent_proof": "Checked the WhatsApp opt-in box on example.com/webinar"
}'
  • phone (required) — international format preferred (+4915112345678). National formats work when you send default_country (ISO code, e.g. DE).
  • attributes — free key/value custom fields; keys merge into the contact’s existing attributes.
  • tags — Nybero tags; missing ones are created. Each newly attached tag fires the Tag is added trigger, so this can start automations.
  • opt_in + consent_proof — see consent semantics below.

The response is the contact object plus "created": true|false.

List & search — GET /v1/contacts

Terminal window
curl -s "https://app.nybero.com/api/v1/contacts?search=ada&tag=webinar&opt_in_status=confirmed&limit=50&offset=0" \
-H "Authorization: Bearer $NYBERO_KEY"

Filters combine: search matches name or phone, tag filters by an exact tag name, opt_in_status by consent state, awaiting_reply=true returns only chats waiting for an answer, inbound_since (ISO-8601) only contacts who wrote at or after that time. Paginated (data/total/limit/offset).

Find unanswered chats

Terminal window
# Everyone who wrote in the last 24 h and is still waiting for a reply
curl -s "https://app.nybero.com/api/v1/contacts?awaiting_reply=true&inbound_since=2026-10-20T08:00:00Z" \
-H "Authorization: Bearer $NYBERO_KEY"

Run it on a schedule (e.g. hourly in Make) and alert your team for every hit — or react in real time with the message.sent and agent.* webhook events.

Message history — GET /v1/contacts/{id}/messages

Terminal window
curl -s "https://app.nybero.com/api/v1/contacts/{id}/messages?limit=50" \
-H "Authorization: Bearer $NYBERO_KEY"
{
"data": [
{ "id": "…", "direction": "outbound", "sender": "agent", "type": "text",
"text": "Dann kannst du dich gerne hier einbuchen …", "template": null,
"status": "read", "user_id": null, "created_at": "2026-10-20T09:01:12Z" },
{ "id": "…", "direction": "inbound", "sender": "contact", "type": "text",
"text": "Gerne ja", "template": null,
"status": "received", "user_id": null, "created_at": "2026-10-20T08:36:02Z" }
],
"limit": 50,
"has_more": true
}

Newest first. sender is contact for inbound messages; for outbound ones agent, team (with the teammate’s user_id), automation, broadcast, api, business_app (sent from the WhatsApp Business app) or system. Page backwards with before=<created_at of the oldest message you have>.

Read, update, delete

Terminal window
# One contact
curl -s https://app.nybero.com/api/v1/contacts/{id} -H "Authorization: Bearer $NYBERO_KEY"
# Update fields (attributes merge into existing ones)
curl -s -X PATCH https://app.nybero.com/api/v1/contacts/{id} \
-H "Authorization: Bearer $NYBERO_KEY" -H "Content-Type: application/json" \
-d '{"name":"Ada Lovelace","attributes":{"stage":"customer"}}'
# GDPR delete — removes the contact, its consent trail and tag links
curl -s -X DELETE https://app.nybero.com/api/v1/contacts/{id} \
-H "Authorization: Bearer $NYBERO_KEY"

Deleting is the same GDPR erasure the app performs — use it to honour a right-to-erasure request programmatically. It returns 204 No Content.

Tags

Terminal window
# All tags in the workspace
curl -s https://app.nybero.com/api/v1/tags -H "Authorization: Bearer $NYBERO_KEY"
# Add a tag (created if missing; fires the "Tag is added" trigger when newly attached)
curl -s https://app.nybero.com/api/v1/contacts/{id}/tags \
-H "Authorization: Bearer $NYBERO_KEY" -H "Content-Type: application/json" \
-d '{"name":"vip"}'
# Remove a tag
curl -s -X DELETE https://app.nybero.com/api/v1/contacts/{id}/tags/vip \
-H "Authorization: Bearer $NYBERO_KEY"

Tags are Nybero-native (more on tags) — they drive segments and the Tag is added automation trigger, which makes POST …/tags a handy way to kick off a flow for one contact.

Worked example: sync signups from your backend

Your shop backend marks buyers in Nybero so a post-purchase flow runs:

  1. Customer buys → your backend calls POST /v1/contacts with phone, name, opt_in: true (consent collected at checkout), attributes: {"order_id": "A-1042"}.
  2. The same call adds "tags": ["customer"].
  3. In Nybero, an automation with trigger Tag is added (tag customer) sends the approved order-confirmation template and a review request three days later.

No polling, no CSV exports — one HTTP call per purchase.