Kerabie
API Reference

Contacts API

List, add, update and import the people you talk to.

These endpoints use your API key and return the same data as the Contacts page in the dashboard.

import { KerAbieClient } from '@kerabie/sdk';

const kerabie = new KerAbieClient({ apiKey: process.env.KERABIE_API_KEY });

A contact is anyone with at least a name, email or phone number. Website visitors who only browsed are not contacts until they message you or you save them.

List contacts

GET /v1/contacts
const { contacts, meta } = await kerabie.contacts.list({ type: 'VIP', sort: 'recent' });
Query paramDescription
searchCase-insensitive match on name, email, phone, company or a tag name.
typeLEAD, CUSTOMER or VIP.
tagIdOnly contacts with this tag.
ownerIdOnly contacts owned by this team member.
sortrecent (default: last contact first, contacts who have never messaged last), newest or name.
page, limitPagination. limit defaults to 20, maximum 100.
{
  "contacts": [
    {
      "id": 24,
      "name": "Chidi Okafor",
      "email": "chidi@palmex.com",
      "phone": "+234 803 555 0142",
      "company": "Palmex",
      "notes": "Prefers WhatsApp.",
      "contactType": "VIP",
      "ownerId": 7,
      "owner": { "id": 7, "user": { "fname": "Amara", "lname": "Osei", "email": "amara@kerabie.com", "avatar": null } },
      "tagLinks": [{ "tag": { "id": 3, "name": "Enterprise", "color": null } }],
      "visitorCountry": "NG",
      "externalSource": null,
      "lastContactAt": "2026-10-05T10:52:00.000Z",
      "createdAt": "2026-09-28T09:10:00.000Z",
      "_count": { "conversations": 3 }
    }
  ],
  "meta": { "total": 9, "page": 1, "limit": 20, "pages": 1 }
}

lastContactAt is the last message in either direction (replies from the AI assistant don't count). For contacts created before this was tracked it falls back to their latest conversation.


Overview numbers

GET /v1/contacts/stats
{ "total": 9, "newThisWeek": 2, "leads": 2, "vip": 2 }

newThisWeek counts contacts added in the last 7 days. Results are cached for up to a minute and refresh immediately when contacts change.


Get a contact

GET /v1/contacts/:id

Returns the contact with its last 10 conversations. 404 if it isn't in your organisation.


Add a contact

POST /v1/contacts
const { contact } = await kerabie.contacts.create({ name: 'Chidi Okafor', email: 'chidi@palmex.com', contactType: 'CUSTOMER' });
Body fieldNotes
name, email, phoneAt least one is required.
company, notesOptional. Notes up to 5,000 characters.
contactTypeLEAD (default), CUSTOMER or VIP.
ownerIdA team-member id in your organisation, or null.
StatusWhen
400Nothing identifying was given, the email is malformed, the type is unknown, or the owner isn't on your team.
409A contact with this email (any casing) already exists.

Update a contact

PATCH /v1/contacts/:id

Send only the fields you want to change. A blank text field clears it, and ownerId: null removes the owner. The same validation and 409 rule as adding applies: you can't give a contact an email another contact already has.


Import contacts

POST /v1/contacts/import
const result = await kerabie.contacts.import([
  { name: 'Sam Adeyemi', email: 'sam@tenda.ng', company: 'Tenda', type: 'lead' },
  { email: 'not-an-email' },
]);
{ "created": 1, "duplicates": 0, "invalid": [{ "row": 2, "error": "\"not-an-email\" is not a valid email" }], "total": 2 }
  • Up to 1,000 rows per call.
  • Each row needs a name or an email. type is lead, customer or vip (any case) and defaults to lead.
  • Rows whose email already belongs to a contact are skipped and counted in duplicates. The same email twice in one request is reported as invalid on the second row.
  • One bad row never fails the others; invalid rows are listed with their number (starting at 1).