Developers
Build on NELLA Engage
A simple REST API for your leads, contacts and conversations — plus signed webhooks that push events into your own systems the moment they happen.
Authentication
Every request is authenticated with an API key sent as a bearer token. Keys look like ne_live_… and are created by workspace owners and admins in Settings → API keys (Professional plan and above). A key is shown once at creation — store it securely and never expose it in client-side code. Keys are read-only by default; grant write scope to create records.
curl -H "Authorization: Bearer ne_live_YOUR_KEY" \
"https://nella-engage.vercel.app/api/v1/leads"All errors share one shape, so a single handler covers everything:
{
"error": {
"code": "invalid_key",
"message": "This API key is invalid or revoked."
}
}
// Codes you may see:
// 401 unauthorized · 401 invalid_key · 403 workspace_suspended
// 403 insufficient_scope · 400 invalid_body · 429 rate_limitedRate limits & pagination
Each key may make 120 requests per minute. Beyond that you'll receive 429 rate_limited — back off and retry after a minute. List endpoints paginate with ?limit= (1–100, default 50) and ?offset=, and every list response includes a pagination object with the total count:
{
"data": [ … ],
"pagination": { "limit": 50, "offset": 0, "total": 214 }
}API reference
Base URL: https://nella-engage.vercel.app/api/v1
/api/v1/leadsList leads, newest first.
| Parameter | Type | Description |
|---|---|---|
| status | string, optional | Filter: new · contacted · qualified · won · lost |
| limit | integer, optional | Page size, 1–100 (default 50) |
| offset | integer, optional | Rows to skip (default 0) |
curl -H "Authorization: Bearer ne_live_YOUR_KEY" \
"https://nella-engage.vercel.app/api/v1/leads?status=new&limit=2"{
"data": [
{
"id": "9b2f6c1e-…",
"name": "Ama Mensah",
"phone": "+233201234567",
"email": "ama@example.com",
"interest": "Bridal make-up package",
"budget": "GHS 1,500",
"location": "Accra",
"timeline": null,
"source": "whatsapp",
"status": "new",
"score": 82,
"estimated_value": 1500,
"follow_up_at": null,
"notes": null,
"created_at": "2026-07-01T09:14:03.511Z",
"updated_at": "2026-07-01T09:14:03.511Z"
}
],
"pagination": { "limit": 2, "offset": 0, "total": 41 }
}/api/v1/leadswrite scopeCreate a lead. Provide at least one of name, phone, email. New leads start with status new.
| Parameter | Type | Description |
|---|---|---|
| name | string ≤120, optional | Lead's name |
| phone | string ≤30, optional | Phone number |
| string, optional | Valid email address | |
| interest | string ≤500, optional | What they asked about |
| budget | string ≤120, optional | Stated budget |
| location | string ≤120, optional | Where they are |
| notes | string ≤5000, optional | Free-form notes |
| source | string ≤40, optional | Attribution tag (default "api") |
curl -X POST "https://nella-engage.vercel.app/api/v1/leads" \
-H "Authorization: Bearer ne_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Kofi Boateng",
"phone": "+233209876543",
"interest": "Generator servicing quote",
"source": "website-form"
}'{
"data": {
"id": "4f81a3d0-…",
"name": "Kofi Boateng",
"phone": "+233209876543",
"email": null,
"status": "new",
"created_at": "2026-07-03T15:22:47.902Z"
}
}/api/v1/contactsList contacts, newest first.
| Parameter | Type | Description |
|---|---|---|
| limit | integer, optional | Page size, 1–100 (default 50) |
| offset | integer, optional | Rows to skip (default 0) |
curl -H "Authorization: Bearer ne_live_YOUR_KEY" \
"https://nella-engage.vercel.app/api/v1/contacts?limit=1"{
"data": [
{
"id": "c1d2e3f4-…",
"name": "Esi Owusu",
"phone": "+233245550123",
"email": null,
"whatsapp_wa_id": "233245550123",
"tags": ["vip", "wholesale"],
"opt_in_whatsapp": true,
"lifetime_value": 3200,
"created_at": "2026-06-18T11:02:19.204Z"
}
],
"pagination": { "limit": 1, "offset": 0, "total": 128 }
}/api/v1/contactswrite scopeCreate a contact. Provide at least one of name, phone, email.
| Parameter | Type | Description |
|---|---|---|
| name | string ≤120, optional | Contact's name |
| phone | string ≤30, optional | Phone number |
| string, optional | Valid email address | |
| tags | string[], optional | Up to 25 tags, each ≤40 characters |
| notes | string ≤5000, optional | Free-form notes |
curl -X POST "https://nella-engage.vercel.app/api/v1/contacts" \
-H "Authorization: Bearer ne_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Esi Owusu", "phone": "+233245550123", "tags": ["vip"] }'{
"data": {
"id": "c1d2e3f4-…",
"name": "Esi Owusu",
"phone": "+233245550123",
"email": null,
"created_at": "2026-07-03T15:24:10.331Z"
}
}/api/v1/conversationsread-onlyList conversations, most recently active first. Each row embeds the contact's name, phone and email.
| Parameter | Type | Description |
|---|---|---|
| status | string, optional | Filter: open · pending · resolved · escalated |
| channel | string, optional | Filter: webchat · whatsapp · voice |
| limit | integer, optional | Page size, 1–100 (default 50) |
| offset | integer, optional | Rows to skip (default 0) |
curl -H "Authorization: Bearer ne_live_YOUR_KEY" \
"https://nella-engage.vercel.app/api/v1/conversations?status=escalated&channel=whatsapp"{
"data": [
{
"id": "7a9c0b2d-…",
"channel": "whatsapp",
"status": "escalated",
"is_ai_handled": false,
"sentiment": "negative",
"lead_score": 67,
"ai_summary": "Customer wants a refund on last week's order.",
"message_count": 14,
"created_at": "2026-07-02T08:41:55.118Z",
"last_message_at": "2026-07-03T10:05:12.660Z",
"contacts": {
"name": "Yaw Darko",
"phone": "+233541112233",
"email": null
}
}
],
"pagination": { "limit": 50, "offset": 0, "total": 3 }
}Webhooks
Instead of polling the API, let NELLA Engage call you. Owners and admins create webhook endpoints in Developers inside the app, pick which events to receive, and get a signing secret to verify every delivery.
Event catalogue
| Event | Name | Fires when |
|---|---|---|
| lead.created | Lead created | A new lead is captured. |
| lead.won | Lead won | A lead is marked won. |
| conversation.resolved | Conversation resolved | A conversation is marked resolved. |
| conversation.escalated | Conversation escalated | The AI hands a conversation to the team. |
| appointment.booked | Appointment booked | A new appointment is created. |
| payment.succeeded | Payment succeeded | A payment is confirmed. |
| quote.accepted | Quote accepted | A customer accepts a quote. |
| csat.received | CSAT received | A customer rates a conversation. |
Delivery format
Deliveries are JSON POSTs. Two headers accompany every request: X-Nella-Event (the event type) and X-Nella-Signature(an HMAC of the raw body, keyed with your endpoint's signing secret).
POST /webhooks/nella HTTP/1.1
Content-Type: application/json
X-Nella-Event: lead.created
X-Nella-Signature: sha256=6c1d4b1f0a2e…
{
"event": "lead.created",
"occurred_at": "2026-07-03T15:30:02.114Z",
"data": {
"id": "4f81a3d0-…",
"name": "Kofi Boateng",
"phone": "+233209876543",
"source": "website-form",
"status": "new"
}
}Verifying signatures
Compute an HMAC-SHA256 of the raw request body with your signing secret and compare it to the header in constant time. Reject anything that doesn't match.
import { createHmac, timingSafeEqual } from "node:crypto";
function verifyNellaSignature(rawBody, signatureHeader, secret) {
// signatureHeader is the X-Nella-Signature value: "sha256=<hex>"
const expected =
"sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(signatureHeader);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}
// Express example — keep the raw body for verification
app.post("/webhooks/nella", express.raw({ type: "application/json" }), (req, res) => {
if (!verifyNellaSignature(req.body, req.header("X-Nella-Signature"), process.env.NELLA_WEBHOOK_SECRET)) {
return res.status(401).end();
}
const event = JSON.parse(req.body);
// handle event.event / event.data …
res.status(200).end();
});Retries & failure handling
- Respond with any 2xx status quickly — do slow work asynchronously.
- Failed deliveries are retried up to 3 times with increasing backoff: 5 minutes, 30 minutes, then 2 hours.
- After 20 consecutive failuresan endpoint is automatically disabled — re-enable it from the Developers page once it's healthy.
Slack endpoints
Prefer events in a channel? Create a Slack endpoint and paste a Slack incoming-webhook URL. Events arrive as readable channel messages, and no signature verification is needed — Slack's webhook URL itself is the secret.
Ready to build?
Create a workspace, mint an API key in Settings, and make your first call in minutes.

