REST API · Version 1
Tickets aus Ihren Systemen anlegen und bearbeiten.
Die API bildet den vollständigen öffentlichen Ticket-Workflow ab: Teams lesen, Tickets anlegen und filtern, antworten, zusammenführen und Anhänge laden. Interne Notizen verlassen 1stlevel.tech nicht.
In drei Schritten
Schnellstart
- 01 · TokenAls Admin unter Konto → API erstellen und sofort sicher speichern.
- 02 · TeamMit
GET /teamsdie passende Team-ID ermitteln. - 03 · TicketTicket mit einem eindeutigen Idempotency-Key anlegen.
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": "kunde@example.com",
"requester_name": "Ada Beispiel",
"subject": "VPN-Zugang funktioniert nicht",
"body": "Seit heute schlägt die Anmeldung fehl.",
"external_ref": "CRM-4711",
"locale": "de"
}'
Alle Antworten sind JSON, außer dem Binärdownload eines Anhangs. Ressourcen liegen unter data; Listen enthalten zusätzlich links und meta.
Zugriff, Scopes und Limits
Bearer-Token
Senden Sie den Token als Authorization: Bearer <token>. In der Oberfläche erzeugte Tokens laufen nach einem Jahr ab und werden beim Widerruf oder nach einem Passwort-Reset ungültig.
Berechtigungen
tickets:read erlaubt GET. Schreibende Anfragen brauchen zusätzlich tickets:write, ein nutzbares Konto und einen Tarif mit API-Schreibzugriff. Die E-Mail-Adresse des Token-Inhabers muss bestätigt sein.
Team-Bereich
Ein Token kann auf ein Team beschränkt sein. Fremde Tickets und Anhänge antworten dann mit 404; beim Anlegen mit abweichender Team-ID folgt 403. Ohne Team-Beschränkung gelten alle Teams des Mandanten.
Rate Limits pro Token
- Solo
- 60/min · nur lesen
- Test & Team
- 120/min
- Team+
- 300/min
Bei 429 gibt Retry-After die Wartezeit an.
POST sicher wiederholen
Jede POST-Anfrage benötigt Idempotency-Key mit 1–128 Zeichen aus A–Z a–z 0–9 . _ : -. Für einen Retry senden Sie denselben Schlüssel, dieselbe Route und exakt dieselben rohen JSON-Bytes. Eine erfolgreiche Wiederholung liefert die ursprüngliche Antwort mit Idempotency-Replayed: true. Wird derselbe Schlüssel für eine andere Anfrage verwendet, antwortet die API mit 409. Gespeicherte Antworten bleiben bis zum Widerruf des Tokens erhalten.
PATCH und GET benötigen keinen Idempotency-Key.
Alle Endpunkte
/teamsTeams abrufenTeam-IDs und Namen im Token-Bereich.
/ticketsTickets auflistenPaginiert, filterbar und auf den Token-Bereich begrenzt.
/ticketsTicket anlegenLegt Ticket und erste eingehende Nachricht gemeinsam an.
/tickets/{ticketId}Ticket abrufenEnthält ein- und ausgehende Nachrichten, aber keine internen Notizen.
/tickets/{ticketId}Ticket bearbeitenÄndert Status, Priorität, Zuweisung, Kategorie, Sprache oder Wiedervorlage.
/tickets/{ticketId}/messagesNachricht hinzufügenErfasst eine Kundennachricht oder stellt eine Antwort in die Versandwarteschlange.
/tickets/{ticketId}/mergeTickets zusammenführenVerschiebt Nachrichten und Anhänge in das Zielticket.
/attachments/{attachmentId}Anhang ladenPrivater Binärdownload innerhalb des Mandanten- und Team-Bereichs.
Tickets
Listen, lesen, anlegen, ändern
GET/tickets
Liefert Tickets nach ID sortiert und paginiert. Standard: 25 Einträge, maximal 100.
| Query | Typ | Wirkung |
|---|---|---|
| status | open | in_progress | done | Exakter Status |
| team | Integer | Team innerhalb des Token-Bereichs |
| due_today | Boolean | Offene Tickets mit Wiedervorlage heute oder früher |
| requester_email | Exakte Adresse, ohne Beachtung der Großschreibung | |
| external_ref | String ≤ 255 | Exakte externe Referenz |
| updated_since | Datum/Zeit | Seit diesem Zeitpunkt aktualisiert |
| per_page | 1–100 | Seitengröße, Standard 25 |
| page | Integer | Seitennummer |
POST/tickets
Pflichtfelder: team (entfällt bei Team-Token), requester_email (max. 190), subject (max. 200) und body (1–100.000 Zeichen). Optional: requester_name (max. 190), locale (de oder en), external_ref (max. 255) und attachments. Antwort: 201 mit Ticket und erster Nachricht.
GET/tickets/{ticketId}
Liefert das Ticket mit sichtbaren Nachrichten und deren Anhängen. Interne Notizen werden weder ausgegeben noch angedeutet. Ein zusammengeführtes Quellticket bleibt als schreibgeschützter Verweis mit merged_into_id lesbar.
PATCH/tickets/{ticketId}
| Feld | Zulässige Werte |
|---|---|
| status | open, in_progress, done |
| priority | normal, high |
| assignee_id | Existierende Benutzer-ID oder null |
| category | hardware, software, access, network, other oder null |
| locale | de oder en |
| due_at | YYYY-MM-DD oder null |
POST/tickets/{ticketId}/merge
Body: {"target_id": 456}. Quelle und Ziel müssen demselben Team und derselben anfragenden E-Mail-Adresse gehören. Nachrichten und Anhänge wandern atomar zum Ziel; das Ziel öffnet wieder, wenn die Quelle noch offen war. Die Quell-ID bleibt lesbar und verweist über merged_into_id auf das Ziel. Weitere Änderungen an der Quelle antworten mit 409.
{
"data": {
"id": 123,
"number": 1042,
"merged_into_id": null,
"team": 1,
"requester_email": "kunde@example.com",
"requester_name": "Ada Beispiel",
"subject": "VPN-Zugang funktioniert nicht",
"status": "open",
"priority": "normal",
"category": "access",
"due_at": null,
"assignee_id": null,
"locale": "de",
"external_ref": "CRM-4711",
"created_at": "2026-09-09T10:15:00+00:00",
"updated_at": "2026-09-09T10:15:00+00:00",
"messages": []
}
}Nachrichten
Kundennachricht erfassen oder antworten
POST/tickets/{ticketId}/messages
Pflichtfelder: direction (in oder out) und body (1–100.000 Zeichen). in erfasst eine eingegangene Nachricht. out legt eine Antwort an und stellt die E-Mail asynchron zu; delivery_status beginnt dann mit pending. Anhänge sind optional. Interne Notizen können über die öffentliche API nicht angelegt werden.
Anhänge
Base64 hinein, privater Download heraus
Ticket- und Nachrichten-POSTs akzeptieren maximal 10 Anhänge. Pro Datei gelten 10 MiB, für alle dekodierten Dateien einer Nachricht zusammen 15 MiB. Dateinamen sind höchstens 200 Zeichen lang. Nur name und content_base64 sind erlaubt; ungültiges Base64 liefert 422.
Nachrichtenantworten enthalten id, name, size, mime_type, sha256 und download_url. Rufen Sie diese URL mit demselben Bearer-Token ab. Die Antwort ist application/octet-stream, nicht JSON; Team- und Leserechte gelten weiterhin.
Antworten
Statuscodes und Fehlerformat
| Code | Bedeutung |
|---|---|
| 200 / 201 | Erfolgreich / Ressource angelegt |
| 401 | Token fehlt, ist ungültig, abgelaufen oder widerrufen |
| 403 | Fähigkeit, Tarif, Kontostatus, E-Mail-Bestätigung oder Team-Zugriff fehlt |
| 404 | Ressource existiert im Token-Bereich nicht |
| 409 | Idempotency-Key kollidiert oder zusammengeführte Quelle ist schreibgeschützt |
| 422 | Validierung fehlgeschlagen oder Idempotency-Key fehlt/ist ungültig |
| 429 | Rate Limit erreicht; Retry-After beachten |
{
"message": "The requester email field is required.",
"errors": {"requester_email": ["The requester email field is required."]}
}Webhooks
Änderungen empfangen
Admins hinterlegen unter Konto → API bis zu 10 Empfänger, optional auf ein Team beschränkt. Zulässig sind ausschließlich öffentlich erreichbare HTTPS-Adressen auf Port 443. 1stlevel.tech folgt keinen Weiterleitungen und prüft die Zieladresse vor jeder Zustellung.
ticket.createdTicket wurde angelegt.
ticket.status_changedStatus hat sich geändert.
message.createdSichtbare Nachricht wurde angelegt.
{
"id": "a9635c13-949f-4f68-a006-e53aa6f9f912",
"type": "message.created",
"created_at": "2026-09-09T10:18:00+00:00",
"data": {
"ticket_id": 123,
"merged_into_id": null,
"team_id": 1,
"status": "open",
"external_ref": "CRM-4711",
"message": {"id": 987, "direction": "out", "body": "Bitte versuchen Sie die Anmeldung erneut."}
}
}Signatur prüfen
Der einmal angezeigte Webhook-Schlüssel signiert timestamp + "." + rawBody mit HMAC-SHA256. Lesen Sie t und v1 aus X-1stlevel-Signature, lehnen Sie Zeitstempel außerhalb von fünf Minuten ab und vergleichen Sie die Hex-Signatur konstantzeitlich. Verwenden Sie unveränderte Request-Bytes, nicht erneut serialisiertes JSON.
X-1stlevel-Signature: t=<Unix>,v1=<64 hex>
Zustellung erfolgt mindestens einmal und ohne Reihenfolgegarantie. Deduplizieren Sie anhand der Ereignis-UUID. Bei Fehlern folgen bis zu acht Versuche mit wachsendem Abstand; jeder HTTP-Status außerhalb 200–299 gilt als Fehler. Interne Notizen erzeugen nie Webhooks.