Developers
API keys, REST API, and webhooks

Webhooks

Once you've added an endpoint under Account → API & Webhooks, Treads.nz will POST a signed JSON batch to your URL every time one of your subscribed events happens. Deliveries are batched - if several events fire close together they may arrive in one request rather than several.

Available events
Event Fires when…
photo.uploaded A member uploads a new photo
status.updated A status post is created or edited
status.deleted A status post is deleted
comment.created A new comment is posted
trader.listed A new Trader listing is published
Payload shape

Every delivery is a single JSON object containing one or more events:

{
  "batch_id": "9f1c2e7a4b3d6081a2c5e7f9b1d3a5c7",
  "sent_at": "2026-09-16T04:12:03+00:00",
  "event_count": 2,
  "events": [
    {
      "id": "3fa81c0b9d2e7a45",
      "event": "photo.uploaded",
      "data": {
        "photo_id": 48213,
        "album_id": 902,
        "uploaded_at": "2026-09-16T04:11:58+00:00"
      }
    },
    {
      "id": "b71e02c4f9a3d856",
      "event": "status.updated",
      "data": {
        "status_id": 771234,
        "updated_at": "2026-09-16T04:12:01+00:00"
      }
    }
  ]
}

Each event's id stays the same if a delivery is retried, so you can safely ignore an event you've already handled.

The exact fields inside each event's data object depend on the event type and are still being finalised alongside the REST API - treat the shapes above as illustrative for now.

Verifying a delivery

Every request includes an X-Webhook-Signature header - the hex-encoded HMAC-SHA256 digest of the raw request body, signed with your webhook's own signing secret (shown on the API & Webhooks page), prefixed sha256=. There's also an X-Webhook-Timestamp header (unix time the request was sent) if you want to reject stale/replayed deliveries.

Always verify the signature before trusting or processing the body:

<?php

// Your endpoint - receives the raw POST body from Treads.nz.

$secret = 'your_webhook_signing_secret'; // from /account/api

$raw_body = file_get_contents('php://input');
$received_signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

$expected_signature = 'sha256=' . hash_hmac('sha256', $raw_body, $secret);

if (!hash_equals($expected_signature, $received_signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$batch = json_decode($raw_body, true);

foreach ($batch['events'] as $event) {
    switch ($event['event']) {
        case 'photo.uploaded':
            // handle it - e.g. queue a re-sync job
            break;
        case 'status.updated':
            // ...
            break;
    }
}

http_response_code(200); // acknowledge receipt
Retries

If your endpoint doesn't respond with a 2xx status (or times out), the delivery is retried with exponential backoff - roughly 1, 2, 4, 8… minutes apart, capped at an hour between attempts, up to 8 attempts total before we give up on that event. Respond quickly and with a 2xx status as soon as you've accepted the batch; do any slow processing afterwards on your end rather than inside the request.

Not sure how to get a signing secret in the first place? See Getting started.