Docs/API & webhooks

Webhooks and API

Protodesk's webhook events and REST API. Available on Pro and above. Authentication, event payloads, rate limits.

Last updated April 19, 2026

Protodesk exposes two integration surfaces:

  • Webhooks — we POST events to your URL when things happen in your workspace
  • REST API — you call our endpoints to read and write workspace data

Both are available on Pro and above.

Webhooks

Configure at Settings → Webhooks → "New webhook".

Fields

  • URL — your HTTPS endpoint (must be HTTPS in production)
  • Events — pick which events trigger this webhook (or "All events")
  • Secret — we generate one; use it to verify signature (see below)

Event types

Event When it fires
ticket.created A new ticket enters the workspace
ticket.updated Ticket status, assignee, labels, or priority changes
ticket.resolved Ticket moves to resolved
ticket.reopened Resolved ticket is reopened
message.received Customer replies on any channel
message.sent Agent sends a reply
customer.created New customer record
customer.updated Customer profile changes
ai.action Any AI action completes (triage, Ticket Context, Suggest, auto-resolve)
sla.breach_imminent SLA timer within warning threshold
sla.breached SLA has been breached

More on the roadmap — ask if you need a specific one.

Payload

All events POST JSON with a consistent envelope:

{
  "event": "ticket.created",
  "timestamp": "2026-04-19T12:34:56.789Z",
  "workspaceId": "wsk_xyz",
  "data": {
    "ticket": { /* full ticket object */ },
    "customer": { /* embedded customer */ }
  }
}

Signature verification

Every webhook request includes two headers:

  • X-Protodesk-Signature — HMAC-SHA256 of the raw body, hex-encoded
  • X-Protodesk-Timestamp — Unix epoch ms

Verify in your handler (pseudocode):

import { createHmac } from "node:crypto";

const signature = req.headers["x-protodesk-signature"];
const timestamp = req.headers["x-protodesk-timestamp"];
const body = await req.text();

const expected = createHmac("sha256", WEBHOOK_SECRET)
  .update(`${timestamp}.${body}`)
  .digest("hex");

if (expected !== signature) throw new Error("Invalid signature");
if (Date.now() - Number(timestamp) > 5 * 60 * 1000) throw new Error("Replay");

Delivery guarantees

  • At-least-once. We retry failed deliveries with exponential backoff for up to 24 hours (1m, 5m, 15m, 1h, 6h, 24h).
  • Ordered per resource, not global. Events for the same ticket arrive in order; events across different tickets may interleave.
  • Idempotency key. Every event has a unique event_id in the envelope. Use it to dedupe on your side.

REST API

Base URL: https://api.protodesk.io/v1

Authentication

Generate an API key at Settings → API → "New key". Scoped to your workspace.

Authorization: Bearer pk_live_xxxxxxxxxxxx

Never expose API keys in client-side code. Use a server or a serverless function.

Endpoints (MVP)

Method Path Purpose
GET /tickets List tickets with filters (status, label, priority, assignee)
GET /tickets/:id Get a single ticket with messages
POST /tickets Create a ticket programmatically
PATCH /tickets/:id Update status, assignee, labels, priority
POST /tickets/:id/messages Send a reply
GET /customers List customers
GET /customers/:id Get a single customer + their tickets
POST /customers Create or upsert a customer
GET /knowledge/articles List knowledge base articles
POST /knowledge/articles Create an article

Full reference on the Docs homepage (coming soon — we're expanding as we ship endpoints).

Pagination

List endpoints return:

{
  "data": [ /* items */ ],
  "pagination": {
    "nextCursor": "eyJpZCI6...",
    "hasMore": true
  }
}

Pass ?cursor=<nextCursor> to get the next page. Default page size: 50. Max: 200 (pass ?limit=200).

Rate limits

  • 1,000 requests / minute per workspace (Pro)
  • 5,000 requests / minute per workspace (Business)
  • Custom (Enterprise)

Responses include:

  • X-RateLimit-Limit — your current per-minute limit
  • X-RateLimit-Remaining — requests left in this window
  • X-RateLimit-Reset — Unix epoch ms when the window resets

Over-limit responses: 429 Too Many Requests with a Retry-After header.

Errors

All errors return JSON:

{
  "error": {
    "code": "ticket.not_found",
    "message": "Ticket tck_xyz not found",
    "details": { /* optional extras */ }
  }
}

Common codes: auth.invalid_key, auth.insufficient_permissions, validation.failed, rate_limit.exceeded, <resource>.not_found.

What's not in the API yet

  • Analytics / insight endpoints — on the roadmap
  • Real-time SSE feed for inbox updates — on the roadmap (currently internal only)
  • Bulk operations (mass update) — file a request if you need it

Summary

  • Webhooks push events to you; REST API lets you pull + mutate
  • HMAC-SHA256 signature verification on webhooks
  • API keys authenticate REST; never expose client-side
  • Rate limits scale with plan

Questions? Email us.