REST API · Version 1
Create and manage tickets from your systems.
The API covers the public ticket workflow: read teams, create and filter tickets, reply, merge duplicates and download attachments. Internal notes never leave 1stlevel.tech.
Three steps
Quickstart
- 01 · TokenCreate a token under Account → API as an administrator and store it securely immediately.
- 02 · TeamUse GET /teams to find the required team ID.
- 03 · TicketCreate the ticket with a unique Idempotency-Key.
curl "https://1stlevel.tech/api/v1/tickets" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: crm-case-4711" \
-d '{"team":1,"requester_email":"customer@example.com","subject":"VPN login fails","body":"Login has failed since this morning.","locale":"en"}'All responses are JSON except for binary attachment downloads. Resources are returned under data; lists also contain links and meta.
Access, scopes and limits
Bearer tokens
Send the token as Authorization: Bearer <token>. Tokens created in the interface expire after one year and are invalidated when revoked or after a password reset.
Permissions
tickets:read permits GET requests. Writes additionally require tickets:write, a usable account, a plan with API write access and a verified token-owner email address.
Team scope
A token can be restricted to one team. Resources outside that scope return 404; creating a ticket for another team returns 403.
Per-token limits
Solo: 60 requests/minute and read only. Trial and Team: 120/minute. Team+: 300/minute. A 429 response includes Retry-After.
Retry POST requests safely
Every POST request requires an Idempotency-Key of 1–128 characters using A–Z, a–z, 0–9, dot, underscore, colon or hyphen. A retry must send the same key, route and exact raw JSON bytes. A successful replay returns the original response with Idempotency-Replayed: true. Reusing the key for a different request returns 409.
PATCH and GET requests do not need an Idempotency-Key.
All endpoints
/teamsList teamsReturns team IDs, names and languages within the token scope.
/ticketsList ticketsPaginated and filterable by status, team, requester, external reference, due date and update time.
/ticketsCreate ticketCreates a ticket and its first incoming message atomically.
/tickets/{ticketId}Read ticketReturns the ticket, visible messages and attachment metadata, but never internal notes.
/tickets/{ticketId}Update ticketChanges status, priority, assignee, category, language or due date.
/tickets/{ticketId}/messagesAdd messageRecords an incoming customer message or queues an outgoing email reply.
/tickets/{ticketId}/mergeMerge ticketsMoves messages and attachments to a target ticket in the same team and for the same requester.
/attachments/{attachmentId}Download attachmentPrivate binary download within the tenant, token and team scope.
Tickets
List, read, create and update
GET /tickets supports status, team, due_today, requester_email, external_ref, updated_since, page and per_page. The default page size is 25 and the maximum is 100.
POST /tickets requires requester_email, subject and body plus team unless the token is team-scoped. requester_name, locale, external_ref and attachments are optional. The response is 201.
PATCH /tickets/{ticketId} accepts status (open, in_progress, done), priority (normal, high), assignee_id, category, locale (de, en) and due_at (YYYY-MM-DD or null).
POST /tickets/{ticketId}/merge accepts target_id. Source and target must belong to the same team and requester email. The source remains readable and points to merged_into_id; further writes return 409.
Messages
Record a customer message or send a reply
POST /tickets/{ticketId}/messages requires direction (in or out) and body. in records an incoming message. out queues an email and initially returns delivery_status pending. Attachments are optional; internal notes cannot be created through the public API.
Attachments
Base64 in, private binary download out
Ticket and message POST requests accept up to 10 attachments. Each file may be 10 MiB and all decoded files in one message may total 15 MiB. Filenames may contain up to 200 characters. Invalid Base64 returns 422.
Attachment metadata includes id, name, size, mime_type, sha256 and download_url. Call the URL with the same Bearer token. The response is application/octet-stream and remains subject to read and team permissions.
Responses
Status codes and error format
| 200 / 201 | Successful / resource created |
|---|---|
| 401 | Token missing, invalid, expired or revoked |
| 403 | Permission, plan, account, verification or team access missing |
| 404 | Resource does not exist within the token scope |
| 409 | Idempotency conflict or merged source is read-only |
| 422 | Validation failed or Idempotency-Key is missing or invalid |
| 429 | Rate limit reached; respect Retry-After |
Webhooks
Receive changes
Administrators can configure up to 10 public HTTPS endpoints on port 443, optionally restricted to one team. Redirects are not followed and the destination is checked before every delivery.
ticket.createdA ticket was created.
ticket.status_changedA ticket status changed.
message.createdA visible message was created.
Verify the signature
The webhook secret signs timestamp + "." + rawBody with HMAC-SHA256. Read t and v1 from X-1stlevel-Signature, reject timestamps outside five minutes and compare the hexadecimal signature in constant time. Use the unchanged request bytes.
X-1stlevel-Signature: t=<Unix>,v1=<64 hex>
Delivery is at least once without ordering guarantees. Deduplicate using X-1stlevel-Event-Id. Failed deliveries are retried up to eight times with increasing delay. Internal notes never create webhooks.