Developers

Build on PromReach

A REST API for your campaigns, content, analytics and orders, and signed webhooks that tell your tools when something happens. Connect Zapier, Make, Slack or your own code.

Authentication

Create a key in Settings → Integrations (Agency plan). A key belongs to one workspace and only has the scopes you give it. Send it as a bearer token; it's shown once, so store it safely.

curl https://api.promreach.com/api/v1/campaigns \
  -H "Authorization: Bearer pz_live_…"

Scopes

ScopeAllowsFor example
campaigns.readRead campaigns and their results.GET /api/v1/campaigns, GET /api/v1/campaigns/{id}
campaigns.manageCreate, launch, pause and edit campaigns.POST /api/v1/campaigns, POST /api/v1/campaigns/{id}/pause
content.readRead posts and the content calendar.GET /api/v1/content, GET /api/v1/content/calendar
content.manageCreate, schedule and publish posts.POST /api/v1/content, POST /api/v1/content/{id}/schedule
analytics.readRead analytics, dashboards and reports.GET /api/v1/analytics/overview, GET /api/v1/dashboards/{id}/data
orders.readRead service orders.GET /api/v1/orders
orders.managePlace and manage service orders.POST /api/v1/orders
wallet.readRead the wallet balance and transactions.GET /api/v1/wallet, GET /api/v1/wallet/transactions
wallet.manageSpend from the wallet (deposits and payments).POST /api/v1/wallet/deposits
creators.manageInvite creators and manage collaborations.POST /api/v1/creator-campaigns
social.manageConnect and manage social accounts.GET /api/v1/social-accounts

Requests and errors

  • JSON in and out. Successful responses are { success: true, data }; lists add meta with page, pageSize, total and totalPages.
  • Page through lists with ?page=2&limit=50 (up to 100).
  • Errors are { success: false, error: { code, message, fields } } with the HTTP status: 401 bad key, 403 missing scope, 404 not found, 402 plan limit, 409 conflict, 422 validation (see fields), 429 too many requests (wait for Retry-After).
  • Money is a decimal string or number in the workspace currency, with the currency code next to it.

Webhooks

Add an endpoint in Settings → Integrations and choose events. We POST each event as JSON and retry with backoff if your endpoint doesn't answer with 2xx. Check the signature before you trust a delivery:

POST /your-endpoint
PromReach-Event: content.failed
PromReach-Delivery: 9a1e…           (unique; use it to ignore repeats)
PromReach-Signature: t=1728000000,v1=<hex HMAC-SHA256 of "<t>.<raw body>" with your secret>

{ "id": "9a1e…", "type": "content.failed", "createdAt": "2026-10-04T08:00:00Z",
  "organizationId": "…", "data": { "postId": "…", "platform": "facebook", "error": "Reconnect your Page." } }

Node.js

import crypto from "node:crypto";

// header: PromReach-Signature: t=1728000000,v1=5257a8…
function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Python

import hmac, hashlib, time

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    signed = f"{parts['t']}.".encode() + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return abs(time.time() - int(parts["t"])) < 300 and hmac.compare_digest(expected, parts["v1"])

Event catalogue

  • campaign.launched

    A campaign went live on the ad platform.

    {
     "data": {
      "campaignId": "3f6c…",
      "name": "Eid sale",
      "platform": "facebook"
     }
    }
  • campaign.completed

    A campaign reached its end date or budget.

    {
     "data": {
      "campaignId": "3f6c…",
      "name": "Eid sale"
     }
    }
  • campaign.failed

    The ad platform rejected or stopped a campaign.

    {
     "data": {
      "campaignId": "3f6c…",
      "error": "Ad account is disabled."
     }
    }
  • content.published

    A scheduled post was published.

    {
     "data": {
      "platforms": [
       "instagram"
      ],
      "postId": "9a1e…"
     }
    }
  • content.failed

    A post couldn't be published on a platform.

    {
     "data": {
      "error": "Reconnect your Page.",
      "platform": "facebook",
      "postId": "9a1e…"
     }
    }
  • content.review_requested

    A post is waiting for approval.

    {
     "data": {
      "postId": "9a1e…"
     }
    }
  • content.approved

    A post was approved.

    {
     "data": {
      "postId": "9a1e…"
     }
    }
  • content.changes_requested

    A reviewer asked for changes to a post.

    {
     "data": {
      "note": "Use the new photo.",
      "postId": "9a1e…"
     }
    }
  • inbox.new_messages

    New comments or messages arrived in the inbox.

    {
     "data": {
      "count": 3,
      "threadIds": [
       "c41d…"
      ]
     }
    }
  • inbox.lead_captured

    Someone finished a WhatsApp or Messenger lead form.

    {
     "data": {
      "answers": {
       "email": "rina@example.com",
       "name": "Rina"
      },
      "channel": "whatsapp",
      "leadId": "5e0a…"
     }
    }
  • insights.weekly_digest

    The weekly AI digest is ready.

    {
     "data": {
      "digestId": "77b0…",
      "periodStart": "2026-09-28"
     }
    }
  • insights.anomaly

    A metric moved unusually (for example, a drop in reach).

    {
     "data": {
      "change": -42.5,
      "metric": "reach"
     }
    }
  • agent.plan_ready

    The AI agent drafted a plan to review.

    {
     "data": {
      "goalId": "5c2a…"
     }
    }
  • agent.plan_failed

    The AI agent couldn't draft a plan.

    {
     "data": {
      "goalId": "5c2a…"
     }
    }
  • agent.goal_completed

    An agent goal reached its target or end date.

    {
     "data": {
      "goalId": "5c2a…"
     }
    }
  • listening.crisis

    Negative mentions of a monitored term are spiking.

    {
     "data": {
      "alertId": "1b7c…",
      "monitorId": "e09f…"
     }
    }
  • ads.boost_live

    A boosted post is running.

    {
     "data": {
      "adAccountId": "0c5e…",
      "boostId": "aa31…"
     }
    }
  • ads.boost_failed

    Boosting a post didn't work.

    {
     "data": {
      "adAccountId": "0c5e…",
      "boostId": "aa31…"
     }
    }
  • order.status_changed

    A service order changed status.

    {
     "data": {
      "orderId": "d2f8…",
      "status": "in_progress"
     }
    }
  • payment.succeeded

    A wallet deposit or payment succeeded.

    {
     "data": {
      "amount": "50.00",
      "currency": "USD",
      "paymentId": "61aa…"
     }
    }
  • payment.failed

    A payment failed.

    {
     "data": {
      "paymentId": "61aa…"
     }
    }
  • wallet.transaction

    Money moved in or out of the wallet.

    {
     "data": {
      "amount": "50.00",
      "transactionId": "f3d2…",
      "type": "deposit"
     }
    }
  • creator.application

    A creator applied to an open brief.

    {
     "data": {
      "applicationId": "2c90…",
      "briefId": "8e3b…"
     }
    }
  • creator.submission

    A creator submitted a deliverable.

    {
     "data": {
      "collaborationId": "4d1f…"
     }
    }
  • creator.response

    A creator accepted or declined an invitation.

    {
     "data": {
      "collaborationId": "4d1f…",
      "status": "accepted"
     }
    }
  • creator.completed

    A creator collaboration was completed and paid.

    {
     "data": {
      "collaborationId": "4d1f…"
     }
    }
  • creator.contract_signed

    A creator signed a collaboration contract.

    {
     "data": {
      "collaborationId": "4d1f…",
      "contractId": "71ce…"
     }
    }
  • subscription.renewed

    The subscription renewed.

    {
     "data": {
      "plan": "pro"
     }
    }
  • subscription.changed

    The plan changed.

    {
     "data": {
      "from": "starter",
      "to": "pro"
     }
    }
  • subscription.payment_failed

    A subscription payment failed.

    {
     "data": {
      "invoiceId": "b8d1…"
     }
    }
  • subscription.addon_expired

    An add-on couldn't renew and ended.

    {
     "data": {
      "addonId": "c0f4…",
      "kind": "team_seats"
     }
    }

Zapier, Make and Slack

Zapier

  1. Trigger: Webhooks by Zapier → Catch Hook; copy its URL.
  2. Add it as a PromReach webhook and pick events.
  3. Actions back into PromReach: Webhooks by Zapier → Custom Request with your API key.

Make

  1. Start a scenario with Webhooks → Custom webhook; copy the address.
  2. Add it as a PromReach webhook.
  3. Call the API with the HTTP → Make a request module and a bearer token.

Slack

No code needed: connect a channel in Settings → Integrations to get approvals, failed posts and new inbox messages there.