API Reference
Complete reference for the TicketForge REST API (v1).
Authentication
All API endpoints require a Bearer token in the Authorization header.
API keys are prefixed with tf_ and scoped to a single project.
Authorization: Bearer tf_your_api_key Base URL & Versioning
/v1/ application/jsonAll request and response bodies use JSON. The API is versioned via URL path — breaking changes will ship as v2.
/v1/tickets
Create a new support ticket. Returns immediately — AI triage runs asynchronously.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| subject | string | Required | Ticket subject line |
| body | string | Required | Full description (Markdown supported) |
| sender_email | string | Optional | Submitter's email address |
| sender_name | string | Optional | Submitter's display name |
| priority | string | Optional | p1_critical, p2_high, p3_medium, p4_low |
| source | string | Optional | api, widget, email, form — defaults to api |
| tags | string[] | Optional | Array of tag names to apply |
| metadata | object | Optional | Arbitrary JSON metadata |
Example
curl -X POST /v1/tickets \
-H "Authorization: Bearer tf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"subject": "Cannot access billing portal",
"body": "Getting a 403 error when clicking Manage Subscription.",
"sender_email": "jane@acme.com",
"priority": "p2_high"
}' Response
202 Accepted{
"ticket_id": "550e8400-e29b-41d4-a716-446655440000",
"ticket_number": 42
} Async side effects:
- AI triage — category, priority, sentiment analysis
- Sentry issue auto-linking (if configured)
- Duplicate ticket detection
- Webhook dispatch (
ticket_created)
/v1/tickets/:id
Retrieve ticket details including conversation messages.
URL Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| id | uuid | Required | Ticket ID |
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| contact_email | string | Optional | Scope results to this contact (validates ownership) |
Example
curl /v1/tickets/550e8400-...?contact_email=jane@acme.com \
-H "Authorization: Bearer tf_your_api_key" Response
200 OK{
"ticket_id": "550e8400-e29b-41d4-a716-446655440000",
"ticket_number": 42,
"subject": "Cannot access billing portal",
"status": "open",
"priority": "p2_high",
"category": "billing",
"created_at": "2026-03-18T14:32:00Z",
"updated_at": "2026-03-18T15:10:00Z",
"messages": [
{
"id": "660e8400-...",
"author_type": "contact",
"body": "Getting a 403 error...",
"created_at": "2026-03-18T14:32:00Z"
}
]
} Only non-internal messages are returned. Messages are ordered by created_at ascending.
/v1/tickets/:id/messages
Add a message to an existing ticket. Reopens resolved tickets automatically.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| body | string | Required | Message text content |
| contact_email | string | Optional | Associate message with a contact |
Example
curl -X POST /v1/tickets/550e8400-.../messages \
-H "Authorization: Bearer tf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"body": "We have deployed a fix. Please try again.",
"contact_email": "jane@acme.com"
}' Response
201 Created{
"message_id": "770e8400-e29b-41d4-a716-446655440001"
} Behavior:
- Creates a
contactauthor-type message - If ticket was resolved/closed, reopens to
open - Triggers automation rules for
ticket_repliedevent - Notifies assigned agent
/v1/articles/search
Full-text search across published knowledge base articles.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| q | string | Required | Search query string |
| limit | integer | Optional | Max results (default: 10, max: 50) |
Example
curl "/v1/articles/search?q=billing+portal&limit=5" \
-H "Authorization: Bearer tf_your_api_key" Response
200 OK{
"articles": [
{
"id": "880e8400-...",
"title": "Managing Your Subscription",
"slug": "managing-subscription",
"excerpt": "Learn how to access and manage your billing portal...",
"category": "Billing",
"relevance": 0.95
}
],
"total": 1
} /v1/search
Unified search across tickets, articles, contacts, and known errors.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| q | string | Required | Search query string |
| limit | integer | Optional | Max per type (default: 10, max: 25) |
| types | string | Optional | Comma-separated: tickets,articles,contacts,known_errors |
Example
curl "/v1/search?q=authentication&types=tickets,articles&limit=5" \
-H "Authorization: Bearer tf_your_api_key" Response
200 OK{
"query": "authentication",
"tickets": [
{
"id": "550e8400-...",
"ticket_number": 42,
"subject": "Auth failing on login",
"status": "open",
"priority": "p2_high",
"relevance": 0.92
}
],
"articles": [
{
"id": "660e8400-...",
"title": "Authentication Guide",
"slug": "auth-guide",
"excerpt": "How to authenticate with TicketForge...",
"relevance": 0.88
}
],
"contacts": [],
"known_errors": []
} /health
Health check — no authentication required.
Example
curl /health Response
200 OK{
"status": "ok",
"service": "ticketforge-ingestion",
"version": "0.1.0"
} Error Codes
All errors return a consistent JSON envelope.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Subject is required"
}
} | Status | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Missing or invalid request fields |
| 401 | UNAUTHORIZED | Invalid or missing API key |
| 404 | NOT_FOUND | Resource does not exist or is outside project scope |
| 409 | CONFLICT | Duplicate or conflicting operation |
| 429 | RATE_LIMITED | Rate limit exceeded (100 req/min per key) |
| 500 | INTERNAL_ERROR | Unexpected server error |
Rate Limiting
100
requests per minute
per key
scoped to API key
429
returned when exceeded
The TypeScript SDK handles retries automatically with exponential backoff and jitter. If calling the API directly, wait and retry with increasing delays.
Webhook Events
Outbound HTTP callbacks. Signed with HMAC-SHA256, with automatic retries (1m, 5m, 30m).
| Event | Description |
|---|---|
| ticket_created | A new ticket was created |
| ticket_replied | A message was added to a ticket |
| ticket_resolved | A ticket was marked as resolved |
| ticket_status_changed | Ticket status changed (open, in_progress, waiting, etc.) |
| ticket_assigned | A ticket was assigned to an agent |
Example Payload
{
"event": "ticket_created",
"timestamp": "2026-03-18T12:00:00Z",
"data": {
"id": "550e8400-...",
"subject": "Cannot access billing portal",
"status": "open",
"priority": "p2_high",
"sender_email": "jane@acme.com",
"project_id": "proj_xyz"
}
} Headers
Content-Type: application/json
X-TicketForge-Event: ticket_created
X-TicketForge-Signature: sha256=<hmac>
X-TicketForge-Delivery: <uuid>
For signature verification code and webhook configuration, see the Webhooks guide.