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

  1. 01 · TokenCreate a token under Account → API as an administrator and store it securely immediately.
  2. 02 · TeamUse GET /teams to find the required team ID.
  3. 03 · TicketCreate the ticket with a unique Idempotency-Key.
curl · https://1stlevel.tech/api/v1
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

GET
/teamsList teams

Returns team IDs, names and languages within the token scope.

GET
/ticketsList tickets

Paginated and filterable by status, team, requester, external reference, due date and update time.

POST
/ticketsCreate ticket

Creates a ticket and its first incoming message atomically.

GET
/tickets/{ticketId}Read ticket

Returns the ticket, visible messages and attachment metadata, but never internal notes.

PATCH
/tickets/{ticketId}Update ticket

Changes status, priority, assignee, category, language or due date.

POST
/tickets/{ticketId}/messagesAdd message

Records an incoming customer message or queues an outgoing email reply.

POST
/tickets/{ticketId}/mergeMerge tickets

Moves messages and attachments to a target ticket in the same team and for the same requester.

GET
/attachments/{attachmentId}Download attachment

Private 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 / 201Successful / resource created
401Token missing, invalid, expired or revoked
403Permission, plan, account, verification or team access missing
404Resource does not exist within the token scope
409Idempotency conflict or merged source is read-only
422Validation failed or Idempotency-Key is missing or invalid
429Rate 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.created

A ticket was created.

ticket.status_changed

A ticket status changed.

message.created

A 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-Event-Id: <UUID>
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.