SK Tickets · Developers

Same rails as the whole suite.

Bearer keys, prefixed ULIDs, cursor pagination, idempotency on every mutation, signed webhooks. Learn it once for SK Tickets; it holds across all of Softknack.

01

How it fits together

Ticket threads are append-only; recordings and transcripts are linked by reference, not copied. Status transitions are guarded — you can't post an illegal state change.

fig · the shape of itthe callfrustratedtranscript+ recordingticket #218evidence ✓the first human to look already knows the whole story
02

Your first ticket in three steps

Get a test key, make one authenticated call, and listen for the webhook. The same three moves work for every endpoint in the suite.

1

Get a test key

Test and live keys are separate environments. Build against sk_test_ without touching a real customer.

2

Create a ticket

One authenticated POST with an idempotency key. Same key + same body always returns the same result.

3

Receive the webhook

A signed ticket.created event hits your endpoint — verify the HMAC, act on it, return 200.

Terminal
curl -X POST https://api.softknack.com/tickets/v1/tickets \
  -H "Authorization: Bearer sk_live_..." \
  -H "Idempotency-Key: 9f2c-4d1a-...-e7b3" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "ctc_01J9X...",
    "subject": "Part delayed",
    "source": "voice",
    "call_id": "cal_01J9X..."
  }'
03

Webhooks you can trust

Signed with HMAC-SHA256, delivered at-least-once, retried on a fixed schedule, and replayable from a dead-letter queue. You will never miss an event because a deploy was mid-flight.

EventWhen it fires
ticket.createdFrom any door — call, chat, form, API. Evidence attached.
ticket.assignedOwner set; queue position cleared.
ticket.status_changedGuarded transition with actor and reason.
ticket.resolvedClosed with resolution note; customer notified.
ticket.reopenedTracked, not hidden.
ticket.sla_breachedAging crossed your threshold.
retry schedule
1s4s16s1m5m30m2hdead-letter
04

Guarantees, not vibes

The platform conventions every SK product obeys — learn them once, rely on them everywhere.

Idempotency, 24h

Every mutation takes an Idempotency-Key. Same key + body returns the original result; a conflicting body gets 409.

Prefixed ULIDs

Sortable, debuggable IDs like tkt_01J9X... — you can read the type and the time right off the wire.

Cursor pagination

Stable cursors that never skip or repeat a row when data changes mid-list. No page-offset drift.

Row-level tenancy

Isolation enforced in the database. 404-over-403, so the existence of another tenant's record never leaks.

Signed webhooks

HMAC-SHA256 on every delivery, with the full retry schedule and dead-letter replay above.

Spec drift-checked

The OpenAPI spec is generated from the code's validators and checked in CI — the docs can't lie.

05

Bring your own agent

Create tickets from your own channels over REST with evidence attached by reference. Subscribe to ticket.status_changed to drive your own automations, or expose triage to your AI agents over MCP — the same way SK Chat escalates what it can't resolve.

fig · MCP, scopedcatalogheadlessAPI · webhook · MCPservedyour agentsbuild on your catalog instead of being held by it
06

Just want a contact form?

Drop a hosted support form on any page — submissions become proper tickets with an owner and a state, routed by topic, the moment they arrive.

The docs go deeper.

Auth, errors, pagination, every endpoint and schema — written once for the platform, shared by every product.

docs.softknack.com/tickets  See pricing →