ElliboHelp Centre

API, webhooks and Zapier

Connect your website and other software to Ellibo CRM. Add and read leads, deals and contacts with the API, get told the moment something happens with webhooks, and use Zapier, Make or Pabbly Connect without writing code.

The API and webhooks are on the Standard plan and up. A CRM admin sets them up in Settings › API & webhooks.

Without writing code: Zapier, Make, Pabbly Connect

When something happens in CRM (e.g. a deal is won), start a task in another app:

  1. In Zapier, create a Zap with the trigger Webhooks by Zapier › Catch Hook and copy the address it shows. In Make use Webhooks › Custom webhook; in Pabbly Connect use Webhook.
  2. In CRM go to Settings › API & webhooks › New webhook, paste the address and tick the events, e.g. A deal is won.
  3. Click Send test. Zapier now has a sample to map fields from.

To add or change CRM records from another app (e.g. a new Google Sheets row becomes a lead):

  1. In CRM, make an API key (Read & write).
  2. In Zapier use Webhooks by Zapier › Custom Request. In Make use HTTP › Make a request.

    • Method POST.
    • URL https://www.ellibo.com/crm/api.php/v1/leads.
    • Header Authorization: Bearer <your key>.
    • Body like the examples below.

API keys

  • Read & write or Read only.
  • Works as: each key acts as one CRM person. Their role (and custom role) decides what the key can see and change. Records the key adds belong to that person unless you give an owner.
  • The key is shown once when you make it. Keep it secret, like a password. If it leaks, switch it off or delete it, and make a new one.
  • Every change made with a key goes into the audit log, marked "via API: key name".

Send the key with every request:

Authorization: Bearer ek_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

The address

All requests go to https://www.ellibo.com/crm/api.php/v1/... and use JSON. Try it:

curl https://www.ellibo.com/crm/api.php/v1/me \
  -H "Authorization: Bearer <your key>"
WhatMethod and path
ListGET /v1/leads (also deals, contacts, companies, activities, products, quotes)
One recordGET /v1/leads/123
AddPOST /v1/leads
Change (only the fields you send)PATCH /v1/leads/123
DeleteDELETE /v1/leads/123 (leads, deals, contacts, activities)
Deal won / lost / reopenPOST /v1/deals/123/won, /lost (lost_reason, lost_note), /reopen
Activity donePOST /v1/activities/123/done (outcome)
NotesGET /v1/notes?record_type=deal&record_id=123, POST /v1/notes
ListsGET /v1/pipelines (with stages), /v1/users, /v1/sources, /v1/lost-reasons, /v1/fields (custom fields)

Quotes, orders and invoices can be read (GET /v1/quotes?type=quote), not changed, because they are documents in your books.

Examples

Add a lead:

POST /v1/leads
{
  "first_name": "Nila",
  "last_name": "Rao",
  "company": "Rao Textiles",
  "email": "nila@raotex.in",
  "mobile": "98450 11111",
  "source": "Website",
  "value": 125000,
  "tags": ["website"],
  "custom_fields": { "Budget": 150000 }
}

The answer is 201 with the whole lead, including its id. Leave out owner_id and the lead is the key person's. Send "owner_id": "auto" to use your assignment rules.

Add a deal, with a new company and contact made for you:

POST /v1/deals
{
  "name": "Looms order",
  "amount": 480000,
  "company_name": "Rao Textiles Pvt Ltd",
  "contact_name": "Nila Rao",
  "contact_email": "nila@raotex.in",
  "close_date": "2026-12-15"
}

Use company_id / contact_id instead for ones already in CRM. Move a deal with PATCH /v1/deals/45 {"stage_id": 12}; the stage ids are in GET /v1/pipelines.

Plan a call: POST /v1/activities {"type": "call", "subject": "Call Nila", "due_at": "2026-11-20 11:30", "deal_id": 45}. Times are in your business's time zone.

Lists, searching and syncing

  • Pages: ?page=2&per_page=100 (up to 100). The answer has has_more.
  • Filters:

    • leads: status, owner_id, email, q (name, company, email, phone);
    • deals: status, pipeline_id, stage_id, company_id, owner_id;
    • activities: deal_id, lead_id, done, due_from, due_to.
  • Only what changed: ?updated_since=2026-11-01T00:00:00Z&sort=updated. Keep the last updated_at you saw and ask again from there.
  • All times in answers are UTC (...Z), except an activity's due_at, which is in business time.

Answers and errors

CodeMeaning
200 / 201Done. data holds the record (or the list).
401No key, a wrong key, or the key was switched off.
403The key's person or plan doesn't allow it (e.g. a read-only key writing).
404No such record, or the key's person can't see it.
409possible_duplicate: the same email or phone is already in CRM. matches lists them; send "force": true to add it anyway.
422validation_error: field says which value to fix.
429Too many calls: 120 a minute per key, and the plan's daily total.

Errors look like {"error": {"code": "validation_error", "message": "Enter the name.", "field": "first_name"}}.

Daily calls: Standard 2,000, Professional 10,000, Business 50,000. The headers X-RateLimit-Limit and X-RateLimit-Remaining show where you are.

Webhooks

A webhook tells another program about events the moment they happen:

RecordsEvents
Leadslead.created, lead.updated, lead.converted, lead.deleted
Dealsdeal.created, deal.updated, deal.stage_changed, deal.won, deal.lost, deal.deleted
Contacts and companiescontact.created, contact.updated, contact.deleted, company.created, company.updated
Activitiesactivity.created, activity.completed
Quotesquote.accepted, quote.declined

Each delivery is a POST with JSON:

{
  "id": "evt_3f1c9a...",
  "event": "deal.won",
  "created_at": "2026-11-02T09:14:05Z",
  "business_id": 1234,
  "data": { "id": 45, "name": "Looms order", "amount": 480000, "status": "won", ... }
}
  • Answer with any 2xx code within 10 seconds. Otherwise CRM tries again after 1, 5 and 15 minutes, then 1, 3, 6 and 12 hours. If the last try fails, CRM gives up on that delivery and your admins get an alert.
  • Deliveries shows what was sent and what the address answered. Click Send again on any delivery CRM gave up on.
  • Workflows can send too: add the step Send to a web address (event workflow.run, with the workflow's name and the record).
  • Addresses must start with https:// and be public.

Check that it came from Ellibo

Every delivery has the headers X-Ellibo-Timestamp and X-Ellibo-Signature: sha256=<hex>. The signature is the HMAC-SHA256 of timestamp + "." + body, with the webhook's signing secret (shown when you edit the webhook). For example, in PHP:

$sig = 'sha256=' . hash_hmac('sha256', $_SERVER['HTTP_X_ELLIBO_TIMESTAMP'] . '.' . file_get_contents('php://input'), $secret);
$ok  = hash_equals($sig, $_SERVER['HTTP_X_ELLIBO_SIGNATURE']);

Also refuse deliveries whose timestamp is more than 5 minutes old.

Still need help?Write to us and we'll walk you through it.
Contact support