Developers

    REST API & webhooks

    Use the REST API to read post status from your backend, and webhooks to get notified when a post goes live—without polling. Start in the dashboard, test with one click, then wire up production.

    Local test code

    Copy-paste a webhook listener and curl examples for your laptop on the Local test examples page.

    Recommended approach

    Most integrations use webhooks for real-time updates and the REST API as a fallback or for backfills.

    1

    Configure

    Create an API key and save a webhook URL in Dashboard → API Keys.

    2

    Test

    Send a test webhook, verify your signature handler, then curl a REST endpoint.

    3

    Ship

    Listen for post.sent in production; use GET /posts/[id] only when you need a refresh.

    Poll vs push

    Webhooks (push) — Prostnow POSTs to your server when a post is first published. Best for automation that should react immediately. REST (pull) — Your server calls GET /api/v1/posts/[id] when you need to double-check status. Use both: webhooks for speed, REST for recovery after downtime.

    Testing your integration

    Follow these steps in order before connecting production traffic.

    1. 1Open Dashboard → API Keys and create a key. Copy pn_live_… into your server env (never the browser).
    2. 2Enter your webhook endpoint URL and click Save. Copy the whsec_… signing secret — you need it to verify incoming POSTs.
    3. 3Click Send test webhook. Your endpoint should receive a sample post.sent payload with test: true. Return HTTP 2xx.
    4. 4Implement signature verification (see below), then re-run the test until your handler accepts the event.
    5. 5Call GET /api/v1/posts?limit=5 with your API key to confirm REST auth works.
    6. 6Publish a real post from the dashboard. Confirm you receive a live post.sent webhook (no test flag) or poll GET /posts/[id] until sent is true.

    All setup and testing controls live in Dashboard → API Keys. The test button sends a signed payload identical to production, except test: true and a fake post id.

    Local development

    Use http://localhost:… or http://127.0.0.1:… as your webhook URL, or expose a tunnel (ngrok, Cloudflare Tunnel, etc.) if you need a public https URL. Save the URL in the dashboard, then use Send test webhook.

    Authentication (REST API)

    API keys are separate from webhook signing secrets.

    CredentialPrefixUsed for
    API keypn_live_…Outbound REST calls from your server
    Signing secretwhsec_…Verifying inbound webhook POSTs from Prostnow

    Send the API key on every REST request:

    Authorization: Bearer pn_live_…

    Base URL (adjust host for local dev):

    https://www.prostnow.com/api/v1

    Webhooks

    One POST per post, when it first reaches a published state.

    Configure the endpoint in Dashboard → API Keys. Production URLs must use https://.

    Request

    • Method POST, body application/json
    • X-Prostnow-Timestamp — Unix ms
    • X-Prostnow-Signature t={timestamp},v1={hex}

    Payload shape

    {
      "type": "post.sent",
      "test": true,
      "occurredAt": "2026-06-06T12:00:00.000Z",
      "post": {
        "id": "prostnow_webhook_test",
        "title": "Webhook test",
        "status": "posted",
        "sent": true,
        "failed": false,
        "displayStatus": "posted",
        "platforms": ["instagram", "x"],
        "platformViewUrls": null,
        "content": "…",
        "mediaUrls": [],
        "scheduledFor": null,
        "createdAt": "…",
        "updatedAt": "…"
      }
    }

    Live events omit test and use the real Convex post id. The post object matches REST API fields.

    Verify the signature

    Parse t from X-Prostnow-Signature, then compute HMAC-SHA256 of {timestamp}.{raw request body} using your whsec_… secret. Compare the hex digest to v1.

    // Node.js example (use the raw body string, not re-serialized JSON)
    import crypto from "crypto";
    
    function verifyProstnowWebhook(rawBody, signatureHeader, secret) {
      const parts = Object.fromEntries(
        signatureHeader.split(",").map((p) => p.trim().split("="))
      );
      const timestamp = parts.t;
      const expected = parts.v1;
      if (!timestamp || !expected) return false;
    
      const signed = `${timestamp}.${rawBody}`;
      const digest = crypto
        .createHmac("sha256", secret)
        .update(signed)
        .digest("hex");
    
      return crypto.timingSafeEqual(
        Buffer.from(digest, "hex"),
        Buffer.from(expected, "hex")
      );
    }

    Handler checklist

    Read the raw body before JSON parsing · Reject if signature invalid · Return 2xx quickly · Ignore events where test: true in production logs if you only want live posts · Rotate the signing secret from the dashboard if compromised

    GET post status

    Fetch one post by id — useful after downtime or when webhooks are disabled.

    GET https://www.prostnow.com/api/v1/posts/{postId}

    Use the post id from the dashboard URL, webhook payload, or list response. Important fields:

    • sent true when published
    • failed true if publishing failed
    • displayStatus posted, scheduled, or draft
    • platformViewUrls — public URLs per platform after publish

    Example:

    curl -s \
      -H "Authorization: Bearer $PROSTNOW_API_KEY" \
      "https://www.prostnow.com/api/v1/posts/j572abc123..."

    List posts

    Newest first — handy for finding ids during initial REST testing.

    GET https://www.prostnow.com/api/v1/posts?limit=20

    Optional limit (1–50, default 20). Response: { "posts": [ … ] }.

    curl -s \
      -H "Authorization: Bearer $PROSTNOW_API_KEY" \
      "https://www.prostnow.com/api/v1/posts?limit=5"

    Errors

    • 401 — missing API key, wrong prefix, or revoked key
    • 404 — post id not found or not owned by your account
    • Webhook delivery fails if your endpoint returns non-2xx or times out (15s). Fix the handler, then use Send test webhook to retry.

    Quick reference

    Dashboard
    /dashboard/api-keys — keys, webhook URL, test button
    REST auth
    Authorization: Bearer pn_live_…
    Webhook secret
    whsec_… (HMAC-SHA256)
    Event type
    post.sent
    Test flag
    test: true on dashboard test events only