Developers
REST API v1 and outbound webhooks for integrating AD Partners with Zapier, Make, n8n, or your own systems.
Authentication
Create a token from your account under Billing › API Access (needs the manage-billing permission). The raw token is shown once — store it safely; only a hash is kept, so a lost token must be revoked and a new one created.
Send it on every request:
Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- Missing/malformed header, or an invalid/revoked token → 401.
- Every response is JSON. A token is scoped to exactly the one agency it was created for — there is no way to reach another tenant's data with it.
- A token can read your data and create draft posts. It cannot publish, connect social accounts, or touch billing — a leaked token is a data-read exposure, not an account takeover.
- An agency's API access can be turned off entirely (feature flag) — in that state every request below returns 403 regardless of an otherwise-valid token.
Base URL: {your app URL}/api/v1
Endpoints
This table is generated from the real Api controller's public methods, not hand-typed — an endpoint added or removed there shows up here automatically the next time this page renders.
| Method | Path | Purpose |
|---|---|---|
GET |
/api/v1/clients |
This agency's clients. Query params: limit (≤100, default 25), offset. |
GET |
/api/v1/inbox |
Inbox messages. Query params: client_id, unanswered=1, limit, offset. |
GET |
/api/v1/me |
The authenticated agency (id, name, status). |
GET |
/api/v1/metrics |
Aggregate metrics per client. Query params: from=YYYY-MM-DD, to=YYYY-MM-DD. |
GET |
/api/v1/posts |
Posts. Query params: client_id, status, limit, offset. |
GET |
/api/v1/posts/{id} |
One post with its per-account schedule. |
POST |
/api/v1/lead |
Push an inbound lead in (JSON body: client_id required, plus at least one of name/email/phone). Idempotent via source+source_ref; emits lead.created on the Event Hub for outbound forwarding. |
POST |
/api/v1/posts/create |
Create a DRAFT post (JSON body: client_id, headline required). Never publishes — appears in the calendar backlog for a human to schedule. |
POST /api/v1/posts/create
Body (JSON):
{
"client_id": 15,
"headline": "Launch teaser",
"caption": "Big news coming...",
"hashtags": "#launch #new",
"campaign_label": "Q3 launch",
"post_type": "single_image"
}
client_idandheadlineare required; the client must belong to the token's own agency (else 404).post_typeis one ofsingle_image(default),carousel,reel,story.- Always created as a draft — it appears in the content calendar's backlog for a human to schedule, choose targets, and save. The API never puts content live on a social account.
- Success → 201
{"data":{"id":42,"status":"draft"}}.
POST /api/v1/lead
Body (JSON):
{
"client_id": 15,
"name": "Priya Shah",
"email": "priya@example.com",
"phone": "+919999999999",
"city": "Gwalior",
"message": "Interested in your services",
"source": "api",
"source_ref": "your-system-id-123"
}
client_idis required; at least one ofname/email/phoneis required.source_refmakes the call idempotent — retrying the same (source, source_ref) pair returns the already-created lead instead of a duplicate.- On create, emits a
lead.createdevent to the Event Hub (see Webhooks below) — a lead pushed in through this endpoint can be forwarded straight back out to another system automatically. - Success → 201
{"data":{"id":88,"status":"new"}}.
Outbound webhooks
Two independent mechanisms exist today, both live — configure whichever fits, or both:
1. Integrations (recommended) — multiple hooks, filtering, retries
Configure any number of webhooks under Integrations in the app, each with its own target URL, event subscriptions, optional client scoping, field filters and key remapping. Every delivery is queued and retried on failure (backoff 1m → 5m → 15m → 1h → 6h, then marked dead after 6 attempts) rather than sent synchronously, so a slow endpoint never delays lead capture or a scheduled post.
Events available: lead.created, lead.status_changed, lead.assigned, post.published, post.failed.
Payload:
{
"event": "post.published",
"sent_at": "2026-08-09T09:15:00+00:00",
"agency_id": 1,
"client_id": 15,
"data": { "post_id": 42, "platform": "facebook", "account": "Acme Page", "platform_post_id": "123_456" }
}
Headers on every delivery:
X-Event: the event nameX-Delivery: the delivery's own id (useful for your own dedup/logging)X-Signature:sha256=<HMAC-SHA256 of the exact request body, using the hook's own signing secret shown once when you create it>
2. Legacy single webhook (still supported)
An older, simpler mechanism kept working unchanged for anyone already relying on it: one webhook URL per agency, set under Billing › API Access. Fires synchronously (short timeouts — 3s connect / 5s total — so it never blocks publishing) for exactly two events, post.published and post.failed, with no retry queue.
{
"event": "post.published",
"occurred_at": "2026-08-09T09:15:00+00:00",
"agency_id": 1,
"post_id": 42,
"platform": "facebook",
"account": "Acme Page",
"data": { "platform_post_id": "123_456" }
}
Headers: X-Event and X-Signature (hash_hmac('sha256', <raw body>, <your webhook secret>) — no sha256= prefix on this one, unlike Integrations above).
Verify every delivery
$raw = file_get_contents('php://input');
$expected = hash_hmac('sha256', $raw, $YOUR_SECRET);
$sent = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
// Integrations deliveries prefix the header with "sha256=" — strip it first if present.
$sent = str_starts_with($sent, 'sha256=') ? substr($sent, 7) : $sent;
if (!hash_equals($expected, $sent)) { http_response_code(401); exit; }
Notes
- All timestamps are server time (UTC).
- Every endpoint listed above is checked against the real
Apicontroller each time this page renders — see the note under Endpoints. - Rate limits and formal versioning beyond v1 are not yet published — ask support if you're integrating at volume.