DEVELOPER DOCSREST API · v1

Your application.
Connected to WhatsApp.

Push leads in from any system and let Rechlio run outreach automatically, send WhatsApp messages programmatically, and receive inbound events on your own endpoint. Base URL: https://outreachapi-9bdb.replov.com

Make your first request

01 · Connect

Connect your WhatsApp Business number in the WhatsApp dashboard.

02 · Authorize

Create a scoped key and save its secret when it is shown once.

03 · Integrate

Call the API from your backend and configure response webhooks.

Keep your key in a backend environment variable. Never expose it in browser JavaScript, public environment variables or mobile-app source.

Shell · check your key
export RECHLIO_API_KEY="your-api-key"
curl https://outreachapi-9bdb.replov.com/v1 \
  -H "Authorization: Bearer $RECHLIO_API_KEY"
200 · authenticated
{ "ok": true, "api": "rechlio", "version": "v1" }

For your first send, use an approved template and a recipient you have permission to contact. Template names, language and parameters must match your approved template.

Authentication

Create an API key in Dashboard → API. The key is shown once — store it securely. Send it as a Bearer token (or an X-API-Key header) on every request. Keys are scoped, and a key is granted only what you tick when you create it: leads:write, leads:read and whatsapp:send.

Example
Authorization: Bearer rk_live_...

The key determines your workspace; do not supply another workspace ID. To rotate a key, create a replacement, update your backend, verify a request, then revoke the old key. Revocation takes effect on the next request.

Ingest a lead

Creates a lead. At least an email or a phone is required. Re-posting the same contact updates it (idempotent). If auto-run is enabled, the lead is routed to a playbook and outreach starts on the first channel it can receive.

POST/v1/leads

Scope: leads:write

Example
curl -X POST https://outreachapi-9bdb.replov.com/v1/leads \
  -H "Authorization: Bearer rk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corp",
    "email": "owner@acme.com",
    "phone": "+919876543210",
    "source": "website_form",
    "tags": ["pricing"],
    "consent": { "whatsapp": true, "email": true },
    "external_id": "your-crm-id-123"
  }'

Response

Example
{ "lead_id": "…", "status": "created", "enrolled": true, "campaign_id": "…" }

A name is also required. Matching uses normalized phone when provided, otherwise email. external_id is a reference/filter, not the deduplication key. Updating an existing lead does not re-enroll it. Auto-run must be configured in Dashboard → API; otherwise enrolled is false and campaign_id is null. The WhatsApp Idempotency-Key contract does not apply to lead ingestion.

Read your leads

Closes the loop the ingest endpoint opens: push a contact in, then read back what segmentation decided and which campaign it was enrolled in. Only ever returns leads belonging to the key’s own workspace.

GET/v1/leads

Scope: leads:read

Filters: status, source, external_id, updated_since (ISO 8601). Paging: page and limit (default 50, max 100), newest change first.

Example
curl "https://outreachapi-9bdb.replov.com/v1/leads?status=replied&updated_since=2026-09-01T00:00:00Z&limit=50" \
  -H "Authorization: Bearer rk_live_..."

Response

Example
{
  "leads": [
    {
      "lead_id": "…",
      "external_id": "your-crm-id-123",
      "dedupe_key": "API-PH-919876543210",
      "name": "Acme Corp",
      "email": "owner@acme.com",
      "phone": "+919876543210",
      "status": "replied",
      "source": "website_form",
      "tags": ["pricing"],
      "consent": { "whatsapp": true },
      "score": 82,
      "campaign_id": "…",
      "segment": { "persona": "…", "language": "hinglish", "pain_points": ["…"] },
      "created_at": "…",
      "updated_at": "…"
    }
  ],
  "pagination": { "page": 1, "limit": 50, "total": 1, "total_pages": 1 }
}

One lead

GET/v1/leads/:id

Returns the same object. A lead in another workspace answers 404, not 403 — a key cannot be used to discover that an id exists somewhere else.

Send a WhatsApp message

Send an approved template anytime, or free-form text within the 24-hour customer window. The message appears in your inbox and receives delivery-status updates. Requires a connected WhatsApp account.

POST/v1/whatsapp/messages

Scope: whatsapp:send

Template

cURL · approved template
curl -X POST https://outreachapi-9bdb.replov.com/v1/whatsapp/messages \
  -H "Authorization: Bearer rk_live_..." \
  -H "Idempotency-Key: order-123-confirmation-v1" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+919876543210",
    "type": "template",
    "template": {
      "name": "welcome",
      "language": "en_US",
      "headerType": "image",
      "headerParam": "https://example.com/banner.jpg",
      "bodyParams": ["Shivraj"],
      "buttonParams": [{ "index": 0, "text": "ORDER123" }]
    }
  }'

Session text (within 24h)

Example
{ "to": "+919876543210", "type": "text", "text": "Thanks for reaching out!" }

Response

Example
{ "message_id": "wamid.…", "status": "sent" }

This synchronous response means Meta accepted the message, not that it has been delivered. Store message_id for webhook correlation. Media header links must use public HTTPS without credentials and be accessible to Meta. This endpoint does not upload files or create templates. Obtain and record recipient consent; sending a request does not collect consent.

Node.js · server-side send
const { RECHLIO_API_KEY } = process.env;
if (!RECHLIO_API_KEY) throw new Error('Set your backend API key first');
const operationKey = 'order-123-confirmation-v1'; // persist with your order
const response = await fetch('https://outreachapi-9bdb.replov.com/v1/whatsapp/messages', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + RECHLIO_API_KEY,
    'Content-Type': 'application/json',
    'Idempotency-Key': operationKey,
  },
  body: JSON.stringify({
    to: '+919876543210', type: 'template',
    template: { name: 'welcome', language: 'en_US', bodyParams: ['Asha'] },
  }),
});
const result = await response.json();
if (!response.ok) throw new Error(result.error || 'Send was not confirmed');
// Save result.message_id with the corresponding business record.

Retries & idempotency

Use one persistent Idempotency-Key per logical message, up to 255 characters. Reuse the same key and request body after a client timeout. Keys are scoped to workspace and endpoint.

  • Same key and body: replay the stored outcome with Idempotent-Replay: true.
  • Same key with a different body: 422.
  • Still running: 409. Retry the same request later. A stale claim asks for reconciliation.
  • Provider timeout or uncertain server outcome: the claim is retained, including stored 5xx responses, to prevent another send.
Unknown does not mean unsent. Check your inbox and delivery events, then contact support if needed. Do not generate a fresh key to bypass an uncertain outcome. Automatic reconciliation is not available yet.

The header is optional for compatibility; sends without it have no request-replay protection. There is currently no automatic key expiry. Keep your operation key with its business record.

Receive events (webhooks)

Configure an endpoint in Dashboard → API → Response webhooks. Rechlio POSTs an event when a lead messages your number (message.received), on delivery/read status (message.status), and when a lead replies (lead.replied). Failed deliveries retry with exponential backoff.

Example delivery

Example
POST https://your-app.com/webhooks/rechlio
X-Rechlio-Event: message.received
X-Rechlio-Signature: 9f2c…   (HMAC-SHA256 of the raw body)

{
  "event": "message.received",
  "workspaceId": "…",
  "timestamp": "2026-08-26T10:00:00.000Z",
  "data": { "from": "919876543210", "type": "text", "text": "Hi!", "messageId": "wamid.…" }
}

Verifying the signature

Compute an HMAC-SHA256 of the raw request body using your webhook signing secret (shown on the API page) and compare it to the X-Rechlio-Signature header.

Example
import crypto from 'crypto';

function verify(rawBody, signature, secret) {
  if (!secret || typeof signature !== 'string' ||
      !/^[a-f0-9]{64}$/i.test(signature)) return false;
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest();
  const received = Buffer.from(signature, 'hex');
  return received.length === expected.length &&
    crypto.timingSafeEqual(received, expected);
}

Read the original body bytes before JSON parsing. Reject an invalid signature, durably accept or enqueue the verified event, then return a 2xx promptly. Configure a public HTTPS endpoint: redirects and private destinations are refused. Keep responses under 64 KiB.

JSON · delivery-status data
{
  "messageId": "wamid.example", "status": "delivered",
  "recipient": "919876543210", "error": null,
  "at": "2026-09-09T10:00:00.000Z"
}

For message.status, correlate data.messageId with your send response. Webhook retries can produce duplicate events. Deduplicate incoming messages by message ID, and status updates by message ID plus status so a later read update is not discarded. Tolerate out-of-order updates. The top-level timestamp may change on retries. Delivery attempts are visible in the dashboard.

Limits & billing

120 / minute

per source IP

300 / minute

per API key

600 / minute

per workspace

All three limits apply, including to reads and replayed requests. Multiple keys do not increase the workspace ceiling. On 429, back off with jitter and retain your original message key. These limits are fixed, not plan-specific.

WhatsApp API sends record usage and use your configured platform fee. The default platform fee is ₹0; Meta charges are separate. A configured fee can return 402 when balance is insufficient. Definitive failures refund usage; uncertain delivery remains held for reconciliation.

STOP and other recognized opt-outs suppress future sends. Suppressed and do-not-contact recipients are blocked. An unconnected workspace cannot silently borrow the platform’s number; shared-number mode is an explicit operator setting.

Troubleshoot a request

Errors return a JSON body { "error": "…" } with a standard HTTP status. Save the operation key and any confirmed message ID alongside your business record.

API errors and recovery actions
StatusWhat to do
400Check fields, WhatsApp connection, approved template and the 24-hour text window.
401Supply a valid, non-revoked API key.
402Check the workspace balance and configured send fee.
403Check key scope and recipient suppression/do-not-contact status.
404Check the lead ID and workspace associated with the key.
409The operation is running or needs reconciliation. Keep the same key.
422The key was used with a different body. Check the original operation.
429Back off; an IP, key or workspace rate limit was reached.
5xxA send may have been accepted. Reuse its key to inspect the stored outcome; do not blindly create another send.

What is available today?

Available: scoped API keys, lead ingestion and lookup, template/session-text sends, signed webhooks and existing campaign auto-run routing.

Not available yet: POST /v1/events, canonical contacts endpoints, public automation CRUD/run endpoints, and a local template/media API. Do not build integrations against these planned endpoints.

The larger event → condition → wait → send automation platform is still in development. You can integrate direct messaging and lead-driven campaigns using the endpoints above once your account and WhatsApp connection are configured.

Need help? Contact support@rechlio.com.