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.

Authenticated request
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 shape
{
  "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_limited

Rate 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

GET/api/v1/leads

List leads, newest first.

Query parameters for listing leads
ParameterTypeDescription
statusstring, optionalFilter: new · contacted · qualified · won · lost
limitinteger, optionalPage size, 1–100 (default 50)
offsetinteger, optionalRows to skip (default 0)
Request
curl -H "Authorization: Bearer ne_live_YOUR_KEY" \
  "https://nella-engage.vercel.app/api/v1/leads?status=new&limit=2"
Response · 200
{
  "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 }
}
POST/api/v1/leadswrite scope

Create a lead. Provide at least one of name, phone, email. New leads start with status new.

Body fields for creating a lead
ParameterTypeDescription
namestring ≤120, optionalLead's name
phonestring ≤30, optionalPhone number
emailstring, optionalValid email address
intereststring ≤500, optionalWhat they asked about
budgetstring ≤120, optionalStated budget
locationstring ≤120, optionalWhere they are
notesstring ≤5000, optionalFree-form notes
sourcestring ≤40, optionalAttribution tag (default "api")
Request
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"
  }'
Response · 201
{
  "data": {
    "id": "4f81a3d0-…",
    "name": "Kofi Boateng",
    "phone": "+233209876543",
    "email": null,
    "status": "new",
    "created_at": "2026-07-03T15:22:47.902Z"
  }
}
GET/api/v1/contacts

List contacts, newest first.

Query parameters for listing contacts
ParameterTypeDescription
limitinteger, optionalPage size, 1–100 (default 50)
offsetinteger, optionalRows to skip (default 0)
Request
curl -H "Authorization: Bearer ne_live_YOUR_KEY" \
  "https://nella-engage.vercel.app/api/v1/contacts?limit=1"
Response · 200
{
  "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 }
}
POST/api/v1/contactswrite scope

Create a contact. Provide at least one of name, phone, email.

Body fields for creating a contact
ParameterTypeDescription
namestring ≤120, optionalContact's name
phonestring ≤30, optionalPhone number
emailstring, optionalValid email address
tagsstring[], optionalUp to 25 tags, each ≤40 characters
notesstring ≤5000, optionalFree-form notes
Request
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"] }'
Response · 201
{
  "data": {
    "id": "c1d2e3f4-…",
    "name": "Esi Owusu",
    "phone": "+233245550123",
    "email": null,
    "created_at": "2026-07-03T15:24:10.331Z"
  }
}
GET/api/v1/conversationsread-only

List conversations, most recently active first. Each row embeds the contact's name, phone and email.

Query parameters for listing conversations
ParameterTypeDescription
statusstring, optionalFilter: open · pending · resolved · escalated
channelstring, optionalFilter: webchat · whatsapp · voice
limitinteger, optionalPage size, 1–100 (default 50)
offsetinteger, optionalRows to skip (default 0)
Request
curl -H "Authorization: Bearer ne_live_YOUR_KEY" \
  "https://nella-engage.vercel.app/api/v1/conversations?status=escalated&channel=whatsapp"
Response · 200
{
  "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

EventNameFires when
lead.createdLead createdA new lead is captured.
lead.wonLead wonA lead is marked won.
conversation.resolvedConversation resolvedA conversation is marked resolved.
conversation.escalatedConversation escalatedThe AI hands a conversation to the team.
appointment.bookedAppointment bookedA new appointment is created.
payment.succeededPayment succeededA payment is confirmed.
quote.acceptedQuote acceptedA customer accepts a quote.
csat.receivedCSAT receivedA 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).

Example delivery
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.

Node.js
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.