Skip to content

Developers

REST & webhooks. Plug Niyog into your stack.

Push leads in, send WhatsApp messages, subscribe to outcome events. Every endpoint is tenant-scoped. Webhooks are HMAC-signed. Keys are minted from the admin console.

Live today

REST v1 · signed webhooks (HMAC-SHA256) · API key minting · per-key scopes · MCP server (mcp__niyog-mcp__*) for Claude clients

Coming next

Official TypeScript + Python SDKs · OAuth for third-party apps · public OpenAPI spec · GraphQL surface for the dashboard

Authentication

Every request needs an Authorization: Bearer niyog_live_… header. Mint a key from the admin console. Keys are shown once on creation.

curl https://niyogai.com/api/v1/leads \
  -H "Authorization: Bearer niyog_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Create a lead

POST /api/v1/leads

curl -X POST https://niyogai.com/api/v1/leads \
  -H "Authorization: Bearer $NIYOG_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Rohan Mehta",
    "phone": "919812345678",
    "source": "shopify",
    "intent": "Asked about pricing on the checkout page"
  }'

# Response (201)
{ "id": 4821, "phone": "919812345678", "name": "Rohan Mehta", "created": true, "stage": "New" }

Node

const res = await fetch('https://niyogai.com/api/v1/leads', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.NIYOG_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Rohan Mehta',
    phone: '919812345678',
    source: 'shopify',
    intent: 'Asked about pricing on the checkout page',
  }),
})
const lead = await res.json()

Python

import os, requests
res = requests.post(
    'https://niyogai.com/api/v1/leads',
    headers={'Authorization': f"Bearer {os.environ['NIYOG_KEY']}"},
    json={
        'name': 'Rohan Mehta',
        'phone': '919812345678',
        'source': 'shopify',
        'intent': 'Asked about pricing on the checkout page',
    },
)
lead = res.json()

List & read leads

# All leads in your workspace, newest first.
GET /api/v1/leads?limit=20&stage=Warm

# Single lead by ID.
GET /api/v1/leads/:id

# Update stage or intent.
PATCH /api/v1/leads/:id
{ "stage": "Qualified" }

Send a WhatsApp message

POST /api/v1/messages — sends through your workspace’s WhatsApp Business Account. If the first attempt fails Meta, it auto-queues for retry with exponential backoff.

curl -X POST https://niyogai.com/api/v1/messages \
  -H "Authorization: Bearer $NIYOG_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "919812345678",
    "body": "Hi Rohan, saw you were looking at the pro plan. Free trial works for you?"
  }'

# Response
{ "sent": true, "message_id": "wamid.HBgL...", "to": "919812345678" }

List agents

GET /api/v1/agents
{
  "data": [
    { "slug": "sales.qualifier", "name": "Priya", "category": "sales", "status": "live", "description": "..." },
    { "slug": "sales.demo_booker", "name": "Meera", "category": "sales", "status": "live", "description": "..." },
    ...
  ],
  "count": 26
}

Webhooks

Subscribe a URL to receive outcome events. Every delivery is signed with HMAC-SHA256 using the per-subscription secret returned on creation.

curl -X POST https://niyogai.com/api/v1/webhooks \
  -H "Authorization: Bearer $NIYOG_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/niyog",
    "events": ["lead.qualified", "meeting.booked", "message.sent"]
  }'

# Response (201)
{
  "id": 17,
  "url": "https://example.com/webhooks/niyog",
  "events": ["lead.qualified", "meeting.booked", "message.sent"],
  "secret": "whsec_abcdef...",
  "message": "Save this secret — it will not be shown again."
}

Event payload shape

POST https://your-url/webhooks/niyog
X-Niyog-Event:     lead.qualified
X-Niyog-Signature: t=1716042131,v1=<hex_hmac>

{
  "event": "lead.qualified",
  "client_id": 17,
  "agent_slug": "sales.qualifier",
  "metadata": { "lead_id": 4821, "stage": "Qualified", "score": 8, "intent": "..." },
  "value_cents": null,
  "delivered_at": "2026-05-18T03:42:11.000Z"
}

Verify the signature (Node)

The signature header has the form t=<unix_ts>,v1=<hex_hmac>. The HMAC covers <unix_ts>.<raw_body>. Reject deliveries where |now - t| > 300 seconds — that’s a replay.

import crypto from 'node:crypto'

function verify(req, secret) {
  const header = req.headers['x-niyog-signature']                    // "t=1716042131,v1=..."
  const parts = Object.fromEntries(header.split(',').map(kv => kv.split('=')))
  const ts = parseInt(parts.t, 10)
  if (Math.abs(Date.now() / 1000 - ts) > 300) return false           // replay protection
  const signed = ts + '.' + req.rawBody.toString('utf8')
  const expected = crypto.createHmac('sha256', secret).update(signed).digest('hex')
  return crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected))
}

Available events

lead.created           — A new lead enters the workspace (any source).
lead.qualified         — Priya (or your custom qualifier) classifies a lead.
message.sent           — An outbound WhatsApp message delivered successfully.
deal.updated           — A deal's stage or value changes.
meeting.booked         — Meera (or your booking agent) confirms a demo slot.
agent.run.completed    — Any agent cron finishes (success or failure).

Need a key, custom scope, higher rate limit, or stuck on something? WhatsApp the founder.

WhatsApp