Webhooks

Send signed JSON to your own URL when feedback is created, changed or commented on.

Updated October 2026

Set up

In Project → Settings → Integrations, add a Custom Webhook with your endpoint URL. PinMarks generates a secret (whsec_…) used to sign each request. Only owners and admins can manage it, and there is one webhook per project. Use Send test to deliver a ping event.

Events

EventWhen
feedback.createdNew feedback submitted.
feedback.status_changedStatus changed.
feedback.priority_changedPriority changed.
feedback.type_changedType changed.
feedback.assignee_changedAssignee changed.
comment.createdNew public comment (internal notes are never sent).

Payload

json
{
"id": "evt_...",
"event": "feedback.status_changed",
"created_at": "2026-10-13T09:30:00Z",
"project": { "id": "...", "name": "Acme website" },
"data": {
"feedback": { "title": "...", "status": "resolved", "priority": "high", "page_url": "..." },
"actor": { },
"changes": { "status": { "from": "open", "to": "resolved" } }
}
}

Requests carry X-Pinmarks-Event, X-Pinmarks-Event-Id (use it to de-duplicate), X-Pinmarks-Delivery, X-Pinmarks-Timestamp and X-Pinmarks-Signature.

Verify the signature

The signature header looks like t=<unix>,v1=<hex>. It is an HMAC-SHA256 of <timestamp>.<raw body> using your secret. Reject requests older than 5 minutes to prevent replays.

javascript
import crypto from 'crypto';
function verify(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('=')));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Delivery and retries

  • Your endpoint must answer with a 2xx within 10 seconds. Redirects are not followed.
  • Failed deliveries are retried up to 3 times: immediately, after 30 seconds, then after 5 minutes.
  • The delivery log keeps 30 days and lets you redeliver. You can regenerate the secret at any time.
  • Private and internal addresses are blocked, so use a public HTTPS URL.

Still stuck?

Email support@pinmarks.io and we'll get back to you within one business day.