REST-API
Lesen und schreiben Sie Ihre Monitore, lesen und aktualisieren Sie Vorfälle, und laden Sie Source Maps hoch. Alles hier nutzt dieselben Berechtigungsprüfungen und denselben Mandantenfilter wie das Dashboard — es gibt keine getrennte Umsetzung auf der API-Seite, die davon abweichen könnte.
In jedem Tarif enthalten, auch im kostenlosen. Es gibt nichts dazuzukaufen und keine Stufe, die es freischaltet.
Basis-URL
https://vitrinaengine.com/api/v1Maschinenlesbare Beschreibung
/openapi.json ist ein OpenAPI-3.1-Dokument, das jede Route auf dieser Seite abdeckt. Richten Sie einen Client-Generator darauf, oder geben Sie es einem Agenten, der diese API aufrufen soll, ohne sie erklärt zu bekommen.
Es wird aus dem Dienst erzeugt und nicht daneben geschrieben: die Routen stammen aus der Oberfläche, die die API unter GET / selbst veröffentlicht, die Datenstrukturen und ihre Erläuterungen aus denselben .proto-Dateien unter /api/proto, und die Ratenbegrenzungen aus dem Code, der sie durchsetzt. Ein Build schlägt fehl, wenn das eingecheckte Dokument und die API auseinanderlaufen — es beschreibt also, was ausgeliefert wird, und nicht, was zuletzt jemand hineingeschrieben hat.
Es beschreibt die Datenstrukturen. Die Gründe stehen auf dieser Seite — dass eine fremde ID mit 404 antwortet, dass config nie zurückgegeben wird — und die kann kein Generator schreiben.
Für Agenten: MCP
https://vitrinaengine.com/mcp ist ein Model-Context-Protocol-Server. Tragen Sie ihn mit einem API-Schlüssel als Bearer-Token in einen MCP-Client ein, und ein Agent kann Ihre Monitore, Vorfälle, Fehler und Analysen lesen — und Monitore anlegen, ändern und löschen —, ohne dass ihm jemand erklärt, wie diese API funktioniert.
{
"mcpServers": {
"vitrina-engine": {
"type": "http",
"url": "https://vitrinaengine.com/mcp",
"headers": { "Authorization": "Bearer vte_your_key_here" }
}
}
}Er liest alles und schreibt drei Dinge. Jede GET-Operation auf dieser Seite ist ein Werkzeug, ebenso POST /monitors, PATCH /monitors/{id} und DELETE /monitors/{id}. Sonst ist nichts Schreibendes erreichbar — kein Arbeitsbereich, kein Mitglied, kein API-Schlüssel, keine Statusseite und nicht Ihr Konto —, denn dafür existiert kein Werkzeug; und die Liste der erlaubten Schreibzugriffe sind drei Zeilen, die jemand bewusst ergänzen muss.
Ein Schlüssel ohne Schreibrecht wird weiterhin abgewiesen. Ein Werkzeugaufruf ist dieselbe Anfrage, die der Schlüssel direkt stellen würde, durch dieselbe Berechtigungsprüfung und denselben Mandantenfilter — ein Agent mit einem Nur-Lese-Schlüssel liest also. Geben Sie ihm einen solchen, sofern er Ihre Überwachung nicht verändern soll, und rechnen Sie damit, dass ein Client vor dem Löschen nachfragt: Mit einem Monitor verschwindet seine Historie, und es gibt kein Zurück. Um einen Monitor stillzulegen, ohne ihn zu verlieren, pausieren Sie ihn per PATCH.
Weil es dieselbe Anfrage ist, sieht sie genau das, was der Schlüssel sieht, schreibt denselben Audit-Eintrag wie das Dashboard und zählt gegen dasselbe Ratenlimit — und zwar doppelt: einmal für den Aufruf und einmal für die Anfrage darin. Ein Schreibzugriff zählt gegen das Schreiblimit.
Eines sollte man wissen, bevor ein Agent einen Monitor bearbeitet: config wird vollständig ersetzt, nicht zusammengeführt. Lesen Sie den Monitor zuerst, ändern Sie das eine Feld und senden Sie das ganze Objekt zurück. Eine unvollständige Konfiguration verwirft stillschweigend die Header und Zugangsdaten, von denen die Prüfung abhängt — und lässt sie weiterlaufen.
Authentifizierung
Erstellen Sie einen Schlüssel unter Einstellungen → API-Schlüssel und senden Sie ihn als Bearer-Token. Der Schlüssel wird einmal angezeigt, bei der Erstellung, und nur als Hash gespeichert — wenn Sie ihn verlieren, erstellen Sie einen neuen.
curl https://vitrinaengine.com/api/v1/summary \
-H "Authorization: Bearer vte_your_key_here"Ein Schlüssel gewährt nie mehr, als die Person hatte, die ihn erstellt hat. Er ist an deren Mitgliedschaft gebunden und trägt daher deren Rolle: Ein Schlüssel, den jemand mit einer Nur-Lese-Rolle erstellt hat, kann nicht schreiben, was auch immer Sie senden. Ein Schlüssel kann außerdem auf einen einzelnen Arbeitsbereich beschränkt werden; in dem Fall wird jede Antwort auf diesen Arbeitsbereich gefiltert, und was außerhalb liegt, existiert für diesen Schlüssel nicht.
Jemanden aus Ihrer Organisation zu entfernen widerruft im selben Vorgang die Schlüssel, die diese Person erstellt hat. Einen Zugang zu entziehen muss die Zugangsdaten mitnehmen, sonst behält die Person einen funktionierenden.
Konventionen
Jede erfolgreiche Antwort ist ein JSON-Objekt mit einer Eigenschaft data. Jeder Fehlschlag ist ein JSON-Objekt mit einer Eigenschaft error, die einen für Menschen gedachten Satz enthält.
{ "data": { "id": "8f14e45f-…", "name": "Marketing site" } }
{ "error": "This key cannot create monitors." }Antworten werden mit Cache-Control: private, no-store gesendet. Es handelt sich um schlüsselbezogene Daten auf einem gemeinsamen Ursprung, und sie dürfen von keinem Proxy aufbewahrt werden.
Protobuf und gzip
Jeder Endpunkt unter /api/v1 spricht auch Protocol Buffers. Mit Accept: application/x-protobuf kommt die Antwort als Protobuf; wer einen Protobuf-Body mit Content-Type: application/x-protobuf sendet, erhält die Antwort im selben Format zurück. Ohne beides bleibt es JSON, genau wie bisher.
curl https://vitrinaengine.com/api/v1/monitors \
-H "Authorization: Bearer vte_your_key_here" \
-H "Accept: application/x-protobuf" \
--compressed -o monitors.pbDie Nachrichten sind veröffentlicht: /api/proto listet jede Datei auf. Laden Sie sie unter ihren Pfaden herunter und richten Sie protoc -I auf das Verzeichnis. Drei Dinge weichen von dem ab, was man bei Protobuf erwarten würde: Ein Feld, das leer sein kann, ist in JSON null und fehlt in Protobuf; einige Felder, deren Form variiert — etwa das config eines Monitors oder eines Kanals —, sind JSON-Dokumente in einem String; und StringList umschließt eine Liste, die selbst null sein kann.
Gzip funktioniert in beide Richtungen: Accept-Encoding: gzip für Antworten, Content-Encoding: gzip für Anfragen. Weil zwei Aufrufer von derselben URL jetzt unterschiedliche Bytes erhalten können, trägt jede Antwort Vary: Accept, Content-Type.
Statuscodes
| Code | Bedeutung |
|---|---|
200 | Alles in Ordnung. 201, wenn etwas angelegt wurde. |
400 | Der Body war kein JSON, ein Feld fehlt, oder es wurde nichts verlangt. |
401 | Kein Schlüssel, oder kein gültiger. Sagt bewusst nie, welches von beidem — eine Meldung, die das unterscheidet, ist ein Weg, Schlüssel auszuprobieren. |
403 | Ein gültiger Schlüssel ohne die Berechtigung für diese Aktion. Die Meldung nennt sie. |
404 | Kein solcher Datensatz für Sie. Siehe unten. |
413 | Eine Source Map über der Größenobergrenze. |
429 | Über einer Ratenbegrenzung. Trägt Retry-After. Siehe unten. |
Refusal-Codes
Jeder Nicht-2xx-Body trägt neben dem Satz einen code — not_found, limit_reached, rate_limited — und das ist das Feld, auf das Sie verzweigen. Der error-Text ist Prosa für jemanden, der ein Log liest, und kann jederzeit umformuliert werden; der Code ist stabil. Wo der Satz einen Wert nennt, trägt vars diese Werte als Zeichenketten, sodass Sie sie dorthin setzen können, wo Ihre eigene Grammatik sie haben will, statt sie aus dem Englischen zurückzuparsen.
{
"error": "The Pro plan includes 50 monitors, and you have 50.",
"code": "limit_reached",
"vars": { "plan": "pro", "limit": "50", "current": "50", "resource": "monitors" }
}Daraus stellen unsere eigenen Apps eine Absage in der Sprache des Lesers dar. Behandeln Sie einen Code, den Sie nicht kennen, genauso — fallen Sie auf error zurück — denn Codes kommen ohne Versionssprung hinzu.
Ratenbegrenzungen
Pro Organisation, nicht pro Schlüssel — einen weiteren Schlüssel zu erstellen hebt sie nicht an.
| Kategorie | Grenze |
|---|---|
Lesezugriffe (GET) | 120 pro Minute |
Schreibzugriffe (POST, PATCH, DELETE) | 30 pro Minute |
| Hochgeladene Source Maps | 300 pro Stunde |
Über der Grenze antwortet 429 mit einem Retry-After-Header, der ganze Sekunden bis zum Zurücksetzen des Fensters angibt. Halten Sie sich daran, statt sofort erneut zu versuchen.
Sie sind dort angesetzt, wo eine normale Integration sie nie erreicht: Eine Wandtafel, die alle zehn Sekunden abfragt, verbraucht sechs der 120 Lesezugriffe. In allen Tarifen sind sie gleich, weil die Sammelendpunkte alles in einer Antwort zurückgeben — ein Konto mit fünfhundert Monitoren braucht nicht mehr Anfragen als eines mit zwanzig. Source Maps haben ein Stundenkontingent, weil sie beim Deployment im Schwung ankommen, wo ein Frontend leicht hundert Fragmente haben kann.
404 statt 403, mit Absicht
Eine Kennung, die einem anderen Kunden gehört, wird mit „Not found.“ beantwortet, nicht mit „Forbidden.“ Ein 403 würde bestätigen, dass der Datensatz existiert, und damit würde der Endpunkt zu einem Mittel, um zu prüfen, ob eine Kennung echt ist. Lesen Sie einen 404 nicht als Beleg dafür, dass nirgends etwas existiert — nur dafür, dass nichts existiert, was dieser Schlüssel sehen darf.
Endpunkte
GET /search
Alles im Konto, das auf ?q= passt: Monitore, Vorfälle und ihre Nachbetrachtungen, Server, Statusseiten, Arbeitsbereiche, Benachrichtigungskanäle, Wartungsfenster, Fehlerprojekte und Probleme, Analyse-Websites, Mitglieder und Einladungen, API-Schlüssel, Agenten und private Sonden. Eine Anfrage statt einer pro Art.
?type= grenzt auf eine kommagetrennte Liste von Arten ein, ?limit= begrenzt die Treffer je Art auf 1 bis 20 (Standard 5). Jede Art erfordert dieselbe Berechtigung wie ihr eigener Endpunkt; eine Art, die Ihr Schlüssel nicht lesen darf, fehlt genauso, wie eine Art ohne Treffer fehlt. Nichts Versiegeltes, Gehashtes oder Geheimes wird durchsucht oder zurückgegeben.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
limit | query | integer |
q | query | string |
type | query | string |
| Antwort | SearchResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /summary
Zählwerte, für eine Wandtafel oder eine Tageszusammenfassung. Erfordert monitor:read.
{
"data": {
"total": 42, "up": 39, "degraded": 1, "down": 1,
"paused": 1, "pending": 0,
"openIncidents": 2, "suppressedIncidents": 1
}
}suppressedIncidents zählt Vorfälle, die zurückgehalten werden, weil sie der Auswirkungsbereich eines anderen sind. Sie sind echt, und sie sind keine eigenständigen Ausfälle.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | GetSummaryResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /setup
Was ein neues Konto noch zu tun hat — dieselben vier Fragen, die die Einrichtungsliste im Dashboard stellt, bei jedem Abruf neu abgeleitet. Erfordert monitor:read.
{
"data": {
"hasMonitor": true,
"hasConfirmedChannel": false,
"hasStatusPage": false,
"hasColleague": false,
"dismissedAt": null
}
}hasConfirmedChannel fragt, ob ein Alarm tatsächlich ankommen könnte, und nicht, ob ein Kanal existiert. Das ist einmal übel auseinandergefallen, und eine Liste, die einen Kanal, den wir gar nicht beliefern, als erledigte Alarmierung abhakt, würde denselben Fehler als Beruhigung wiederholen.
hasColleague zählt Mitgliedschaften und nie Einladungen: eine verschickte und nicht angenommene Einladung hat niemanden hinzugefügt.
Nicht in /summary eingebaut, denn jener Endpunkt sind Zählungen nach Status und sonst nichts — eine Wandtafel, die ihn im Sekundentakt abfragt, will keine fünf zusätzlichen Abfragen, nur um einen Hinweis zu zeigen, der an jemanden gerichtet ist, der das Konto vor Monaten eingerichtet hat.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | GetSetupResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
DELETE /setup
Überspringt die Liste. Erfordert org:update, weil das Ausblenden eine organisationsweite Zeile ist und keine persönliche Einstellung — wer danach dazukommt, bekommt sie nicht noch einmal gezeigt.
Sonst ändert sich nichts am Konto, und es wird kein Audit-Eintrag geschrieben: einen Hinweis auszublenden ändert nichts daran, wie das Produkt sich verhält, alarmiert oder abrechnet.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | DismissedResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /monitors
Alle Monitore, die der Schlüssel sehen kann. Erfordert monitor:read. Jeder trägt id, name, kind, status, statusSince, enabled, intervalSeconds, tags, workspace, lastCheckedAt, lastResponseTimeMs, lastMessage, uptime24h, uptime30d und openIncidentId.
?tag=prod,eu schränkt die Liste auf Monitore ein, die jedes genannte Tag tragen — UND, nicht ODER, sodass ein zweites Tag immer weniger Monitore zurückgibt statt mehr. Der Filter im Dashboard liest sich genauso. Tags werden in Kleinbuchstaben gespeichert, und der Wert hier wird vor dem Vergleich ebenso umgewandelt, also findet ?tag=Prod sie. Ein Eintrag, der kein Tag sein kann — leer oder länger als ein Tag sein darf —, wird verworfen und der Rest des Filters gilt weiter, statt den Aufruf abzulehnen: ein Link soll nicht aufhören zu funktionieren, weil eines seiner Tags umbenannt wurde.
config wird nie zurückgegeben. Bei manchen Arten enthält es Anfrage-Header und Zugangsdaten, und ein nur zum Lesen berechtigter Schlüssel soll kein Weg sein, die Geheimnisse zurückzulesen, die jemand in ein Formular getippt hat.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
tag | query | string |
| Antwort | ListMonitorsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
POST /monitors
Erfordert monitor:create. Verlangt name, kind, workspaceId und config. Optional: intervalSeconds (Standard 300), confirmations, dependsOn.
curl -X POST https://vitrinaengine.com/api/v1/monitors \
-H "Authorization: Bearer vte_…" \
-H "Content-Type: application/json" \
-d '{
"name": "Marketing site",
"kind": "http",
"workspaceId": "…",
"intervalSeconds": 60,
"config": {
"url": "https://example.com",
"assertions": [{ "type": "status_code", "operator": "lt", "value": "400" }]
}
}'Antwortet 201 mit der neuen Kennung. Das Intervall wird auf die Untergrenze Ihres Tarifs angehoben statt abgelehnt: 10 Sekunden in einem Tarif mit einer Untergrenze von 60 ergeben 60 — lesen Sie es zurück, wenn es darauf ankommt.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
name | body | string |
kind | body | string |
workspaceId | body | string |
config | body | string |
intervalSeconds | body | integer |
confirmations | body | integer |
dependsOn | body | string[] |
probeId | body | string |
tags | body | string[] |
| Antwort | CreatedResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /monitors/{id}
Ein Monitor, mit allem, was die Liste liefert, plus paused. Erfordert monitor:read.
Für mail_posture, tls_audit und snmp kommt zusätzlich lastCheckDetail hinzu, das Ergebnis der letzten Prüfung selbst: die Befunde hinter dem Status, jeweils mit stabilem code und einer severity, dazu eine TLS-Note oder die SNMP-Messwerte. Bis zur ersten Prüfung ist es null, bei allen anderen Arten fehlt es.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | GetMonitorResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
PATCH /monitors/{id}
Senden Sie nur, was Sie ändern wollen: name, intervalSeconds, confirmations, enabled, config oder paused.
paused wird gegen monitor:pause geprüft und alles Übrige gegen monitor:update, jeweils getrennt — ein Schlüssel, der pausieren, aber nicht bearbeiten darf, kann trotzdem pausieren. Eine leere Änderung zu senden ergibt einen 400.
Der Monitor wird neu gelesen und zurückgegeben, statt die Eingabe zurückzuspiegeln — was Sie sehen, ist also das, was gespeichert wurde.
# Silence a monitor for the length of a deploy.
curl -X PATCH https://vitrinaengine.com/api/v1/monitors/$ID \
-H "Authorization: Bearer vte_…" \
-H "Content-Type: application/json" \
-d '{"paused": true}'Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
name | body | string |
intervalSeconds | body | integer |
confirmations | body | integer |
enabled | body | boolean |
paused | body | boolean |
config | body | string |
tags | body | StringList |
| Antwort | UpdatedMonitorResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /monitors/{id}
Erfordert monitor:delete. Antwortet { "data": { "id": "…", "deleted": true } }.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /hosts · POST /hosts
Server sind die zweite Art, Monitore zu gruppieren: der Arbeitsbereich sagt, wem ein Monitor gehört, der Server sagt, worauf er läuft. Völlig optional — ein Konto, das nie einen anlegt, verliert nichts, und die meisten Monitore nennen gar keinen Server.
Jeder Server trägt status, pinned und spanning. status stammt ausschließlich von Monitoren, die nur auf diesem Server laufen. Ein Monitor über mehrere Maschinen zählt zu spanning und färbt keine davon: Fällt ein lastverteilter Endpunkt aus, sagt das, dass der Dienst kaputt ist, nicht welche Maschine ihn kaputt gemacht hat. Ein Server ohne eigene Monitore antwortet "status": null statt up.
POST braucht monitor:create und einen name. Die optionalen Felder provider, address und notes gehören Ihnen — das Produkt wertet sie nicht aus. Ein Name, der auf einen vorhandenen fällt — Groß- und Kleinschreibung und ein abschließender Punkt werden ignoriert — antwortet 409.
Parameter und Antworten
GET /hosts
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListHostsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
POST /hosts
| Name | Ort | Typ |
|---|---|---|
name | body | string |
provider | body | string |
address | body | string |
notes | body | string |
| Antwort | CreatedResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /hosts/{id} · PATCH /hosts/{id} · DELETE /hosts/{id}
Das Detail trägt den Server und seine Monitore, jeder mit pinned markiert und, wenn er das nicht ist, mit alsoOn: den anderen Maschinen, von denen er antwortet — genau das liest man, bevor man eine neu startet. DELETE nimmt den Server außer Dienst, und jeder Monitor darauf läuft weiter: ein Server hat weder einen eigenen Zeitplan noch eine eigene Historie.
Parameter und Antworten
GET /hosts/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | GetHostResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
PATCH /hosts/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
name | body | string |
provider | body | string |
address | body | string |
notes | body | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /hosts/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
POST /hosts/{id}/monitors · DELETE /hosts/{id}/monitors
Ein Monitor auf oder von einem Server, per monitorId im Body oder ?monitorId=. Bewusst keine ganze Liste: auf einem Agenturkonto trägt ein Server Monitore aus mehreren Arbeitsbereichen, und wer „die Liste“ ersetzte, ersetzte Zeilen, die ihm nie gezeigt wurden. Beide Richtungen sind idempotent.
Parameter und Antworten
POST /hosts/{id}/monitors
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
monitorId | body | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /hosts/{id}/monitors
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
monitorId | query | string |
monitorId | body | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /monitors/{id}/hosts · PUT /monitors/{id}/hosts
Die andere Seite derselben Beziehung, und diese ist eine ganze Liste: Diese Verknüpfungen gehören einem einzigen Monitor, am anderen Ende ist also nichts, was ein anderer Arbeitsbereich sehen könnte. Senden Sie hostIds; ein leeres Array ist eine echte Anfrage und heißt, dass der Monitor auf keinem bestimmten Server läuft. Fremde Ids werden verworfen statt abgelehnt. Jede Monitor-Antwort trägt außerdem hosts, leer wenn es keine gibt.
Parameter und Antworten
GET /monitors/{id}/hosts
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | ListMonitorHostsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
PUT /monitors/{id}/hosts
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
hostIds | body | string[] |
| Antwort | ListMonitorHostsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /incidents
Erfordert incident:read. Nimmt ?status= — eines von open, acknowledged, resolved oder suppressed — und ?open=true für die drei, die nicht behoben sind. Ein unbekannter Status wird ignoriert statt abgelehnt, genauso wie ?limit= (Standard 50) bei 200 gedeckelt und nicht zurückgewiesen wird.
Jeder trägt id, monitorId, monitorName, title, cause, status, severity, startedAt, resolvedAt, durationSeconds, acknowledgedAt und rootIncidentId.
rootIncidentId ist das Feld, auf das es ankommt, wenn Sie einen Alarmstrom bauen. Ist es gesetzt, ist dieser Vorfall der Auswirkungsbereich eines anderen — der Datenbankhost ist ausgefallen, und dies ist einer der zwölf Dienste dahinter. Überspringen Sie sie, und Sie bekommen einen Alarm statt dreizehn.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
limit | query | integer |
open | query | boolean |
status | query | string |
| Antwort | ListIncidentsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /incidents/{id}
Ein Vorfall. Erfordert incident:read. Dieselben Felder wie in der Liste, plus workspaceId.
Er gibt den Verlauf des Vorfalls nicht zurück — die Kommentare und Statusänderungen, die im Dashboard zu sehen sind, liegen nicht auf diesem Endpunkt. Wenn Sie sie brauchen, sagen Sie es, dann lassen sie sich ergänzen; sie hier zu dokumentieren, solange es sie nicht gibt, wäre schlimmer als die Lücke.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | GetIncidentResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
PATCH /incidents/{id}
Senden Sie einen status von "acknowledged" oder "resolved", oder einen comment, oder beides. Jedes wird gegen seine eigene Berechtigung geprüft: incident:acknowledge, incident:resolve, incident:comment. Einem Kommentar "publish": true hinzuzufügen stellt ihn auf die Statusseite und erfordert zusätzlich status_page:manage.
# A runbook that fixed the thing itself can close its own incident.
curl -X PATCH https://vitrinaengine.com/api/v1/incidents/$ID \
-H "Authorization: Bearer vte_…" \
-H "Content-Type: application/json" \
-d '{"status": "resolved", "comment": "Restarted by runbook.", "publish": true}'Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
status | body | string |
comment | body | string |
publish | body | boolean |
| Antwort | GetIncidentResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
PUT /incidents/{id}/postmortem
Schreibt oder ersetzt die Nachbetrachtung des Vorfalls. Erfordert incident:resolve, und der Vorfall muss bereits behoben sein — sonst 409 mit dem Code incident_not_resolved. Senden Sie body als Markdown, nach dem Trimmen 1 bis 50.000 Zeichen (postmortem_required, postmortem_too_long). Es gibt eine pro Vorfall, jeder Aufruf ersetzt also die vorherige. Die Antwort ist der Vorfall, so wie GET /incidents/{id} ihn liefert.
GET /incidents/{id} enthält sie als postmortem: { body, authorName, updatedAt } oder null, und die Liste enthält hasPostmortem. Stellen Sie body als Markdown dar und niemals als HTML: Es ist Text, den ein Mensch getippt hat. Eine Nachbetrachtung ist intern und erscheint nie auf einer Statusseite.
curl -X PUT https://vitrinaengine.com/api/v1/incidents/$ID/postmortem \
-H "Authorization: Bearer vte_…" \
-H "Content-Type: application/json" \
-d '{"body": "## What happened\n\nThe connection pool ran dry after a deploy."}'Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
body | body | string |
| Antwort | GetIncidentResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /probes
Die eigenen privaten Sonden Ihrer Organisation: id, name, lastSeenAt, version, hostname, monitorCount, revoked und createdAt. Erfordert agent:read. Genau das bietet die Sondenauswahl eines Monitors an.
Es gibt kein Regionsfeld, und es wird keins geben. Sie wählen eine Sonde nach Namen; wo eine Prüfung dahinter läuft, entscheiden und ändern wir. Widerrufene Sonden erscheinen mit revoked: true und erhalten keine Arbeit mehr, bieten Sie sie also nicht an.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListProbesResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /monitors/{id}/push-url
Die Ping-URL eines Heartbeat-Monitors, erneut angezeigt. Erfordert monitor:read. url ist null für eine Art, die nicht angepingt wird, und für ein Token, das sich nicht mehr entschlüsseln lässt — der Monitor arbeitet weiter, und ein im Dashboard erneuertes Token liefert eine URL, die angezeigt werden kann.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | GetPushUrlResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /organizations · PUT /organizations/active
Die Organisationen, denen die angemeldete Person angehört, jeweils mit ihrer dortigen role und active bei der aktuell genutzten, sowie der Wechsel zwischen ihnen. Senden Sie organizationId; die Antwort ist die nun genutzte Mitgliedschaft.
Nur mit angemeldeter Sitzung. Ein Schlüssel gehört zu genau einer Mitgliedschaft und erhält 403 mit session_required. Der Wechsel betrifft jede Sitzung dieser Person, auch das Dashboard, und eine Organisation, der sie nicht angehört, ergibt 404.
Parameter und Antworten
GET /organizations
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListOrganizationsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
PUT /organizations/active
| Name | Ort | Typ |
|---|---|---|
organizationId | body | string |
| Antwort | ActiveOrganizationResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
POST /sms/enrolment · POST /sms/enrolment/confirm
Registrieren Sie Ihre eigene Mobilnummer für SMS-Warnungen: Senden Sie phone (optional name), und wir schicken einen sechsstelligen Code dorthin; senden Sie diesen code an die zweite Route, um zu bestätigen. Erfordert notification_channel:manage und eine angemeldete Sitzung — eine Nummer fügt die Person hinzu, die das Telefon hält, nie ein Schlüssel.
Die Nummer wird unbestätigt gespeichert und erhält nichts, bis der Code zurückkommt. Eine erneute Registrierung ersetzt Ihre bisherige Nummer. Ablehnungen: sms_not_included (402, der Tarif enthält kein SMS-Kontingent), not_a_phone_number, sms_country_unsupported, sms_route_not_open, verification_code_not_sent (502; erneut aufrufen für einen neuen Code), verification_code_malformed und verification_code_incorrect. Ein erfolgreicher Start liefert country und caveat — sender-replaced, registration-pending, unverified oder null —, was man zeigen sollte, bevor sich jemand auf die Nummer verlässt.
Parameter und Antworten
POST /sms/enrolment
| Name | Ort | Typ |
|---|---|---|
phone | body | string |
name | body | string |
| Antwort | SmsEnrolmentResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
POST /sms/enrolment/confirm
| Name | Ort | Typ |
|---|---|---|
code | body | string |
| Antwort | SmsConfirmedResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
POST /channels/{id}/confirmation
Sendet die Bestätigungsnachricht eines E-Mail-Kanals erneut. Erfordert notification_channel:manage. Jeder Aufruf erzeugt einen neuen Link, der vorherige funktioniert dann nicht mehr. sent: false heißt, es gab nichts zu senden — die Adresse hat bereits bestätigt —, und eine bestätigte Adresse wird auf diesem Weg nie erneut angeschrieben. Lehnt der Mailanbieter den Versand ab, lautet die Antwort 502 mit confirmation_not_sent.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | ChannelConfirmationResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
PATCH /workspaces/{id}
Benennt einen Arbeitsbereich um. Erfordert workspace:update. name ist Pflicht (1 bis 80 Zeichen), clientReference optional — null löscht sie. Der Slug ändert sich nie, denn er steht in Statusseiten-URLs. Die Antwort ist der Arbeitsbereich in seinem neuen Zustand.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
name | body | string |
clientReference | body | requests.NullableString |
| Antwort | UpdatedWorkspaceResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
POST /sourcemaps
Laden Sie eine Source Map hoch, damit minifizierte Aufruflisten aufgelöst werden. Erfordert monitor:create. Verlangt projectRef (eine Zahl) und filename sowie die Map selbst, entweder als map (JSON) oder als mapGzipBase64. Optional: debugId und release.
Senden Sie eine debug id oder ein release. Eine Map ohne beides lässt sich keiner Aufrufliste zuordnen und liegt dann nutzlos herum. Zugeordnet wird zuerst über debugId, dann über release und Dateiname.
Maps werden beim Lesen eines Problems aufgelöst, nicht beim Hochladen; eine Map, die nach den Fehlern ankommt, hilft also trotzdem — und das ist die übliche Reihenfolge.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
projectRef | body | integer |
filename | body | string |
debugId | body | string |
release | body | string |
map | body | string |
mapGzipBase64 | body | string |
| Antwort | UploadedSourceMapResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 300 pro Stunde |
POST /symbols
Dasselbe für eine native App: Laden Sie ein iOS-.dSYM oder ein Android-R8-mapping.txt hoch, damit Absturz-Aufruflisten aufgelöst werden. Erfordert monitor:create. Zwanzig Uploads pro Stunde, und zwanzig Builds werden je Projekt aufbewahrt.
Anders als bei /sourcemaps ist der Body die gzip-komprimierte Datei selbst, und die Metadaten stehen in Headern: X-Vitrina-Project-Ref, X-Vitrina-Platform (ios oder android), X-Vitrina-Symbol-Name und X-Vitrina-Release. Ein dSYM ist zig Megabyte groß, und Base64 in einem JSON-Feld kostet ein weiteres Drittel an Übertragung.
Die beiden Plattformen werden unterschiedlich zugeordnet. Ein iOS-Frame nennt die Mach-O-UUID des Images, zu dem er gehört; ein iOS-Upload muss deshalb X-Vitrina-Debug-Ids tragen und wird exakt darüber zugeordnet. R8 gibt keine solche Kennung aus, daher wird ein Android-Mapping allein über das Release zugeordnet — und das muss genau das sein, was die App meldet: <applicationId>@<versionName>+<versionCode>. Eine Ziffer daneben, und Frames werden auf Zeilen aufgelöst, die plausibel aussehen und falsch sind.
Denselben Build erneut hochzuladen ersetzt dessen Symbole, statt fehlzuschlagen; ein wiederholter Release-Job ist also kein Fehler. Wie bei Source Maps geschieht die Auflösung beim Lesen eines Problems.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | UploadedSymbolsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 20 pro Stunde |
GET /errors/projects
Die Fehler-Tracking-Projekte dieses Kontos. Erfordert monitor:read. Jedes trägt ref — die Zahl im DSN — sowie publicKey, unresolved und eventsLast24h. Nur lesend: Ein Projekt wird mit einem Schlüssel angelegt, der ohnehin noch in die Konfiguration einer Anwendung eingefügt werden muss, es gibt hier also nichts, was ein Endpunkt zu Ende bringen würde.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListErrorProjectsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /errors/issues
Gruppierte Fehler, neueste Aktivität zuerst. Erfordert monitor:read. Ein Problem ist ein Fingerabdruck und kein Ereignis, tausend Vorkommen eines Wurfs sind also eine einzige Zeile mit timesSeen auf tausend. ?status= steht standardmäßig auf unresolved und nimmt außerdem resolved, ignored oder all; ?project= filtert nach Projektkennung, ?q= durchsucht Typ, Wert und Verursacher, und ?limit= ist bei 200 gedeckelt. spark sind vierundzwanzig Stundenwerte, ältester zuerst.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
limit | query | integer |
project | query | string |
q | query | string |
status | query | string |
| Antwort | ListIssuesResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /errors/issues/{id}
Ein Problem mit seiner Aufrufliste. Erfordert monitor:read. exceptions ist die Kette des SDK selbst, der geworfene Fehler zuletzt und seine Ursachen davor, und ihre Frames werden gegen jede von Ihnen hochgeladene Source Map aufgelöst — dieselbe Auflösung wie im Dashboard, damit ein Skript und die Person, mit der Sie sprechen, nie auf unterschiedliche Aufruflisten schauen. Lässt sich eine Map nicht anwenden, fällt die Antwort auf die ursprünglichen Frames zurück, statt fehlzuschlagen.
lastEvent trägt mit Absicht zwei Zeitstempel. occurredAt ist das, was das SDK gemeldet hat, und receivedAt, wann die Aufnahme es geschrieben hat; ein Gerät, das offline war, oder eine Warteschlange, die sich gestaut hat, ist genau der Abstand dazwischen.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | GetIssueResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
PATCH /errors/issues/{id}
Beheben, ignorieren oder wieder öffnen: { "status": "resolved" }. Erfordert monitor:update. ignoreHours darf ignored begleiten, um es später wieder aufzuheben, und ist bei 90 Tagen gedeckelt.
Beim Beheben wird festgehalten, in welchem Release es behoben wurde, damit ein Nachzügler aus einem älteren Deployment das Problem nicht wieder öffnet. Hat das SDK kein Release gesendet, gibt es nichts zu vergleichen, und jedes spätere Ereignis öffnet es wieder — ohne die Möglichkeit, einen Nachzügler von einem Rückfall zu unterscheiden, ist die sichere Annahme, dass der Fehler zurück ist.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
status | body | string |
ignoreHours | body | integer |
| Antwort | IssueStatusResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /analytics
Die Websites, die dieses Konto misst. Erfordert monitor:read. Trägt publicId — den Wert, der in das Script-Tag gehört und der von vornherein öffentlich ist — sowie viewsLast24h und trafficAlerting, das wahr ist, solange der Verkehr einer Website unter dem liegt, was diese Stunde üblicherweise sieht.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListAnalyticsSitesResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /analytics/{id}
Die Zahlen einer Website, für eine Tabelle oder einen Bericht. Erfordert monitor:read. ?days= steht standardmäßig auf 7 und ist bei 365 gedeckelt. ?dimensions= nimmt eine kommagetrennte Liste aus path, referrer, country, browser, os, device, utm_source, utm_medium, utm_campaign und event; eine unbekannte ergibt einen 400 und keine leere Antwort, denn ein Tippfehler, der nichts zurückgibt, liest sich wie „kein Verkehr“.
Die Besucherzahl heißt dailyUniqueVisitors, und genau das ist sie. Sie ist die Summe der täglich eindeutigen Besucher und kann nichts anderes sein: Das Geheimnis hinter einem Besucher-Hash wird am Ende seines UTC-Tages vernichtet, wer also an zwei Tagen kam, zählt zweimal, und es gibt keinen Schlüssel, der beides zusammenführen würde. Das ist der Datenschutzentwurf bei der Arbeit und keine Näherung — aber ein Feld namens visitors neben einem Zeitraum von 30 Tagen würde dazu einladen, eine Zahl zu berichten, die etwas anderes bedeutet.
curl "https://vitrinaengine.com/api/v1/analytics/$ID?days=30&dimensions=path,referrer" \
-H "Authorization: Bearer vte_…"Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
days | query | integer |
| Antwort | GetAnalyticsSiteResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /billing
Der Tarif, und wo er abgerechnet wird. Erfordert billing:read. Trägt plan, status, cadence, currentPeriodEnd, cancelAt, addOnPacks und die letzten zwölf Belege.
source ist paddle, apple, manual oder none. Das ist wichtig: Ein in der iOS-App gekauftes Abonnement zu ändern ist Apples Sache, und Tarif, Karte und Kündigung liegen allesamt in den App-Store- Einstellungen der Kundin oder des Kunden und nicht hier. canCheckoutOnWeb und canPurchaseInApp sagen, welche Angebote gefahrlos gezeigt werden können, damit ein Client diese Regel nicht selbst herleiten und in der Richtung falsch machen muss, die jemandem zweimal etwas berechnet.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | GetBillingResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /monitors/{id}/history
Tägliche Verfügbarkeit für einen Monitor. Erfordert monitor:read. Nimmt days, bis zur Aufbewahrungsdauer Ihres Tarifs.
Berechnet aus täglichen Rollups statt aus einzelnen Prüfergebnissen; deshalb antwortet der Endpunkt auch für Zeiträume weiter, deren Rohergebnisse die Aufbewahrung bereits gelöscht hat.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
days | query | integer |
| Antwort | GetMonitorHistoryResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /monitors/{id}/graph · GET /monitors/graphs
Die letzten Stunden eines Monitors, Stunde für Stunde, oder aller Monitore, die dieser Schlüssel sieht, in einer Antwort — das, was das Dashboard in einer Monitorzeile und auf der Monitorseite zeichnet. Erfordert monitor:read. Nimmt hours, standardmäßig 24 und höchstens 168.
Ein uptime-Diagramm trägt den Anteil erfolgreicher Prüfungen je Stunde, null für eine Stunde ohne Prüfung; ein value-Diagramm trägt für die quantitativen Arten seine Messwerte als Reihen mit Einheit. Jede Stunde des Fensters ist enthalten, ob etwas aufgezeichnet wurde oder nicht, damit eine Lücke als Lücke sichtbar bleibt. Messwerte kommen so, wie sie gemessen wurden: Eine raw-Reihe hat keine bekannte Skala — zeichnen Sie sie gegen ihren eigenen Höchstwert und geben Sie diesen Anteil nie als Messwert aus.
Parameter und Antworten
GET /monitors/{id}/graph
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
hours | query | integer |
| Antwort | GetMonitorGraphResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /monitors/graphs
| Name | Ort | Typ |
|---|---|---|
hours | query | integer |
| Antwort | ListMonitorGraphsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /monitors/{id}/channels · PUT /monitors/{id}/channels
Welche Kanäle dieser Monitor alarmiert, und das Setzen ebendieser. Lesen erfordert notification_channel:read; Schreiben erfordert monitor:update.
PUT ersetzt den ganzen Satz — senden Sie jede Kanalkennung, die Sie haben wollen, nicht die, die Sie hinzufügen. Ein leeres Array heißt, dass der Monitor niemanden alarmiert; das kann man wollen, und es aus Versehen zu tun ist schlecht.
Parameter und Antworten
GET /monitors/{id}/channels
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | GetMonitorChannelsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
PUT /monitors/{id}/channels
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
channelIds | body | StringList |
| Antwort | GetMonitorChannelsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /incidents/{id}/events
Der Verlauf eines Vorfalls: Statuswechsel, Bestätigungen, Kommentare, Eskalationsschritte. Erfordert incident:read. Das ist der Verlauf, den GET /incidents/{id} nicht enthält.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | ListIncidentEventsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /channels · POST /channels
Lesen erfordert notification_channel:read; Anlegen erfordert notification_channel:manage. Jeder trägt id, kind, name, target und workspaceId.
secret wird nur beim Anlegen eines Kanals zurückgegeben und nie wieder. Es ist der Signaturschlüssel für einen Webhook; ihn irgendwo abzulegen, wo man ihn zurücklesen kann, machte einen nur zum Lesen berechtigten Schlüssel zu einem Weg, signierte Anfragen zu fälschen.
Sie können die Arten anlegen, die eine Person auch im Dashboard anlegen kann: email, webhook, telegram, slack, teams, discord, pagerduty und jsm. SMS, WhatsApp, Satellit und Push werden von der Person eingerichtet, die sie empfängt, und lassen sich nicht über die API anlegen — genau das macht sie zu einer Einwilligung und nicht zu einem Feld, das jemand ausgefüllt hat.
Ein E-Mail-Kanal wird unbestätigt angelegt und erhält eine einzige Nachricht mit der Frage, ob er Alarme möchte. Bis er zustimmt, wird nichts weiter gesendet; einen über die API anzulegen setzt eine Adresse also nicht von allein auf Ihren Alarmplan.
Parameter und Antworten
GET /channels
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListChannelsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
POST /channels
| Name | Ort | Typ |
|---|---|---|
kind | body | string |
name | body | string |
target | body | string |
workspaceId | body | requests.NullableString |
| Antwort | CreatedChannelResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
PATCH /channels/{id} · DELETE /channels/{id} · POST /channels/{id}/test
Alle erfordern notification_channel:manage. Der Testversand wird für eine Adresse verweigert, die nicht bestätigt hat — sonst wäre er ein unbegrenzter Weg, eine Adresse ohne Einwilligung anzuschreiben, mit einer hilfsbereiten Aufschrift.
Parameter und Antworten
PATCH /channels/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
enabled | body | boolean |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /channels/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
POST /channels/{id}/test
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | TestDeliveryResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /status-pages · POST /status-pages
Lesen erfordert status_page:read; Schreiben erfordert status_page:manage. Jede trägt id, name, slug, visibility, customDomain, domainVerifiedAt, subscribersEnabled, componentCount, workspace und createdAt.
Parameter und Antworten
GET /status-pages
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListStatusPagesResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
POST /status-pages
| Name | Ort | Typ |
|---|---|---|
name | body | string |
workspaceId | body | string |
| Antwort | CreatedResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /status-pages/{id} · PATCH /status-pages/{id} · DELETE /status-pages/{id}
Lesen erfordert status_page:read; Ändern oder Löschen erfordert status_page:manage.
Parameter und Antworten
GET /status-pages/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | GetStatusPageResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
PATCH /status-pages/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
name | body | string |
headline | body | requests.NullableString |
description | body | requests.NullableString |
logoUrl | body | requests.NullableString |
themeAccent | body | string |
language | body | string |
historyDays | body | integer |
showResponseTimes | body | boolean |
showIncidentHistory | body | boolean |
subscribersEnabled | body | boolean |
visibility | body | string |
password | body | requests.NullableString |
customCss | body | requests.NullableString |
hideVitrinaBranding | body | boolean |
groupByHost | body | boolean |
| Antwort | UpdatedStatusPageResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /status-pages/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
POST /status-pages/{id}/components · DELETE /status-pages/{id}/components
Einen Monitor zu einer Seite hinzufügen oder von ihr entfernen. Erfordert status_page:manage.
Der Monitor muss im selben Arbeitsbereich liegen wie die Seite, nicht bloß in derselben Organisation. In einem Agenturkonto ist das es, was verhindert, dass der Monitor eines Kunden auf der Seite eines anderen Kunden veröffentlicht wird.
Parameter und Antworten
POST /status-pages/{id}/components
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
monitorId | body | string |
displayName | body | string |
| Antwort | ComponentAckResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /status-pages/{id}/components
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
component | query | string |
componentId | body | string |
| Antwort | ComponentAckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /workspaces · POST /workspaces · DELETE /workspaces/{id}
Lesen erfordert workspace:read, der Rest jeweils eigene Berechtigungen. Jeder trägt id, name, slug, clientReference und isDefault.
Ein Schlüssel, der zu einem beschränkten Mitglied gehört, sieht nur die Arbeitsbereiche, auf die dieses Mitglied beschränkt ist. Der Standard-Arbeitsbereich kann nicht gelöscht werden.
Parameter und Antworten
GET /workspaces
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListWorkspacesResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
POST /workspaces
| Name | Ort | Typ |
|---|---|---|
name | body | string |
clientReference | body | string |
| Antwort | CreatedResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /workspaces/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /members · POST /members
Lesen erfordert member:read; Einladen erfordert member:invite. Die Antwort führt members und invitations getrennt — eine Einladung, die niemand angenommen hat, hat niemanden hinzugefügt, und beides zusammenzuführen ergäbe eine Platzzahl, die dem widerspricht, was Ihnen berechnet wird.
POST verschickt eine Einladung und legt kein Konto an. Es nimmt eine E-Mail-Adresse, eine Rolle und optional workspaceIds, um die Person zu beschränken.
Parameter und Antworten
GET /members
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListMembersResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
POST /members
| Name | Ort | Typ |
|---|---|---|
email | body | string |
role | body | string |
workspaceIds | body | string[] |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
PATCH /members/{id} · DELETE /members/{id} · DELETE /invitations/{id}
Eine Rolle zu ändern erfordert member:update_role; jemanden zu entfernen erfordert member:remove; eine Einladung zu widerrufen erfordert member:invite.
Ein Mitglied zu entfernen löscht dessen persönliche Alarmkanäle — das Telefon, den privaten Chat, die Mobilnummer — zusammen mit dessen API-Schlüsseln. Gemeinsam genutzte Kanäle bleiben unberührt. Die letzte Eigentümerin oder der letzte Eigentümer kann weder entfernt noch herabgestuft werden.
Parameter und Antworten
PATCH /members/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
role | body | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /members/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /invitations/{id}
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /maintenance · POST /maintenance · DELETE /maintenance
Zeitfenster, in denen niemand alarmiert wird. Standardmäßig laufen die Prüfungen weiter und zeichnen weiter auf, diese Minuten zählen also wie alle anderen in die Verfügbarkeit; steht keepChecking auf false, wird währenddessen gar nicht geprüft, was im Verlauf eine Lücke hinterlässt statt einer Delle. Lesen erfordert incident:read; Schreiben erfordert maintenance:manage.
Trägt title, startsAt, endsAt, timezone, monitorIds, recurrenceRule, keepChecking, showOnStatusPage und notifySubscribers. Ein wiederkehrendes Fenster ist eine Zeile und nicht viele.
Eine Regel wiederholt das Fenster zur selben Uhrzeit in seiner eigenen timezone, ein Fenster über eine Zeitumstellung hinweg bleibt also zur geplanten Stunde. FREQ=DAILY, FREQ=WEEKLY und FREQ=MONTHLY werden aufgelöst, wahlweise mit INTERVAL, COUNT, UNTIL sowie einem BYDAY oder BYMONTHDAY, das den Tag nennt, an dem das Fenster selbst beginnt. Jede andere Regel wird unverändert gespeichert und zurückgegeben und hält Warnungen nur für die erste Wiederkehr zurück — geraten wird nie.
Parameter und Antworten
GET /maintenance
| Name | Ort | Typ |
|---|---|---|
past | query | boolean |
| Antwort | ListMaintenanceResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
POST /maintenance
| Name | Ort | Typ |
|---|---|---|
title | body | string |
description | body | string |
workspaceId | body | string |
monitorIds | body | string[] |
startsAt | body | string |
endsAt | body | string |
recurrenceRule | body | string |
timezone | body | string |
keepChecking | body | boolean |
showOnStatusPage | body | boolean |
notifySubscribers | body | boolean |
| Antwort | CreatedResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /maintenance
| Name | Ort | Typ |
|---|---|---|
id | query | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /on-call
Dienstpläne, Eskalationsrichtlinien, Vertretungen und wer gerade Rufbereitschaft hat. Erfordert oncall:read.
onCallNow wird in dem Moment aufgelöst, in dem Sie fragen, wobei viaOverride sagt, ob es aus der Rotation kam oder daher, dass jemand vertritt. unreachable nennt die Beteiligten, die über keinen Kanal verfügen, der sie tatsächlich erreichen könnte — das ist der Fehler, den man besser vor einem Vorfall findet als während eines solchen.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | GetOnCallResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /agents · POST /agents · DELETE /agents · GET /agents/{id}/metrics
Server-Agenten melden CPU, Arbeitsspeicher und Festplatte von Ihren eigenen Maschinen. Das Einrichten erfordert agent:enroll, das Lesen agent:read, das Entfernen agent:delete.
Beim Einrichten kommt einmalig ein Token zurück. Damit authentifiziert sich der Agent, es ist danach also nie wieder lesbar.
Parameter und Antworten
GET /agents
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListAgentsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
POST /agents
| Name | Ort | Typ |
|---|---|---|
name | body | string |
workspaceId | body | requests.NullableString |
| Antwort | EnrolledAgentResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /agents
| Name | Ort | Typ |
|---|---|---|
id | query | string |
id | body | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /agents/{id}/metrics
| Name | Ort | Typ |
|---|---|---|
id Pflicht | path | string |
hours | query | integer |
limit | query | integer |
| Antwort | GetAgentMetricsResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /api-keys · POST /api-keys · DELETE /api-keys
Lesen erfordert api_key:read; Anlegen und Widerrufen erfordern api_key:manage. Jeder trägt id, name, prefix, scopes, workspaceIds, owner, createdAt, lastUsedAt, expiresAt und revokedAt.
token wird nur beim Anlegen zurückgegeben. prefix ist der anzeigbare Teil, und der ist es, mit dem sich zwei Schlüssel in einer Liste auseinanderhalten lassen, ohne dass einer von beiden lesbar wäre.
Ein Schlüssel erbt die Rolle und die Arbeitsbereichsbeschränkung der Mitgliedschaft, die ihn erstellt hat; ein Schlüssel kann also kein Weg um eine Grenze herum sein, die für seine Urheberin oder seinen Urheber gilt.
Parameter und Antworten
GET /api-keys
Keine deklarierten Parameter oder Body-Felder.
| Antwort | ListApiKeysResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
POST /api-keys
| Name | Ort | Typ |
|---|---|---|
name | body | string |
scopes | body | string[] |
workspaceIds | body | string[] |
expiresInDays | body | requests.NullableInt64 |
| Antwort | CreatedApiKeyResponse |
|---|---|
| Statuscodes | 201 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
DELETE /api-keys
| Name | Ort | Typ |
|---|---|---|
id | query | string |
id | body | string |
| Antwort | AckResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /audit
Konfigurationsänderungen, mit Angabe, wer sie vorgenommen hat und was sich geändert hat. Erfordert audit_log:read, was es ab Business gibt.
Seitenweise über nextBefore statt über Seitenzahlen, damit sich eine Seitengrenze nicht verschiebt, während Sie lesen. Einträge werden in jedem Tarif aufgezeichnet — der Tarif steuert das Lesen, ein Upgrade öffnet also die ganze Historie, statt eine zu beginnen.
Zugangsdaten, Hashes und Geheimnisse werden nie in changes geschrieben.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
limit | query | integer |
| Antwort | ListAuditResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
GET /me
Wer dieser Schlüssel ist, was er erreichen kann und was der Tarif erlaubt. Es ist keine Berechtigung nötig — jeder Schlüssel darf sich selbst beschreiben.
Trägt user, organization, membership(Rolle und Arbeitsbereichsbeschränkung), entitlements (die aufgelösten Tarifgrenzen, mit allen Zusatzpaketen bereits eingerechnet) und usage. Nutzen Sie es, um eine Grenze vor einem Anlegeversuch zu prüfen statt nach einer Ablehnung.
Eine Sitzung erhält zusätzlich organizations mit allen Organisationen, denen die Person angehört. Ein API-Schlüssel nicht: Ein Schlüssel wird gegen eine Mitgliedschaft ausgestellt und ist darauf beschränkt, die anderen aufzuführen würde also Organisationen bewerben, die diese Zugangsdaten nicht erreichen können.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | GetMeResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 120 pro Minute |
DELETE /account
Löscht die Organisation und alles darin. Keine Berechtigungskonstante schützt diesen Endpunkt, denn die Eigentümerschaft ist die Prüfung: Er wird allen verweigert, die nicht Eigentümer sind.
Das ist nicht umkehrbar und keine Pause. Setzen Sie es mit Bedacht ein.
Parameter und Antworten
Keine deklarierten Parameter oder Body-Felder.
| Antwort | AccountDeletedResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
POST /billing/apple/verify
Bestätigt einen In-App-Kauf, der in unserer eigenen mobilen App getätigt wurde. Erfordert billing:manage.
Der Vollständigkeit halber dokumentiert und nicht zur Verwendung: Er ist nur mit einem Beleg aufrufbar, den Apple unserer App ausgestellt hat, eine fremde Integration kann damit also nichts anfangen. Hier aufgeführt, weil eine Route, die existiert und nirgends beschrieben ist, von einer vergessenen nicht zu unterscheiden ist.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
transactionId | body | string |
| Antwort | AppleVerifyResponse |
|---|---|
| Statuscodes | 200 400 401 403 404 429 |
| Ratenbegrenzung | 30 pro Minute |
GET /
Das Verzeichnis. Führt die Routen auf, die diese Installation ausliefert — die maschinenlesbare Fassung dieser Seite, und immer aktuell, denn es wird aus dem erzeugt, was tatsächlich eingehängt ist.
Vorfalls-Feed (RSS und Atom)
Jeder Vorfall in Ihrem Konto als Feed, für einen Reader statt für eine Client-Bibliothek. Die URL legen Sie im Dashboard unter Einstellungen → Benachrichtigungen an:
https://vitrinaengine.com/feeds/incidents/vtf_…/feed.xml
https://vitrinaengine.com/feeds/incidents/vtf_…/atom.xmlDie URL ist das Zugangsmittel. Es gibt keinen Header zu senden: Wer den Link hat, kann jeden Vorfall im Konto lesen, über alle Arbeitsbereiche hinweg. Sie wird im Dashboard jederzeit wieder angezeigt, weil sie in einem Feed-Reader liegt, den jemand irgendwann neu aufsetzt — und sie lässt sich ersetzen oder widerrufen, mit Wirkung ab der nächsten Anfrage statt erst, wenn ein Cache abläuft.
Sie enthält ausschließlich Fakten auf Vorfallsebene: den Namen des Monitors, die Ursache, Schweregrad, Status, Beginn und Ende sowie die als öffentlich markierten Aktualisierungen. Nie eine Nachbetrachtung, nie die Monitor-Konfiguration und nie den Ort, von dem aus geprüft wurde. Die meisten Reader synchronisieren über fremde Server, deshalb ist das Dokument so geschrieben, als verlasse es Ihr Haus — was es tut.
Ein Abruf pro Minute ist vorgesehen. Ab sechzig Anfragen pro Minute für eine URL antwortet sie mit 429; eine URL, die nie gültig war, ersetzt oder widerrufen wurde, antwortet mit 404 — für alle drei Fälle dieselbe Antwort, damit sich damit nicht herausfinden lässt, welche Token einmal echt waren.
Was diese API bewusst nicht zurückgibt
- Das
configeines Monitors. Es kann Zugangsdaten enthalten. - Aus welcher Region eine Prüfung lief. Von wo wir prüfen, entscheiden wir, und wir ändern es, während Sonden aufgestellt und verschoben werden. Es wäre ein Versprechen über unsere Infrastruktur, mit dem Sie nichts anfangen könnten, und es wird auch sonst nirgends im Produkt angezeigt.
Exporting your data
Two routes hand back a file rather than a message, so that taking your data out does not mean paging through a collection endpoint a thousand times. Both are on every plan, the free one included — what a plan changes is how much history there is to export, not whether you may.
GET /export/{entity}
Eine Art von Zeilen, als CSV oder JSON. entity ist eines von monitors, hosts, status-pages, notification-channels, members, incidents, incident-events, postmortems, audit-log, error-issues, uptime-daily, uptime-hourly oder analytics-hourly. Alles andere antwortet mit 404.
format ist csv (Standard) oder json. from und to sind RFC-3339-Zeitstempel. bom stellt einer CSV-Datei eine UTF-8-Bytereihenfolge-Marke voran: Excel braucht sie für Namen mit Sonderzeichen, die meisten Skriptsprachen lesen sie als Teil der ersten Spaltenüberschrift — deshalb ist sie standardmäßig aus.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
entity Pflicht | path | string |
bom | query | boolean |
format | query | string |
from | query | string |
to | query | string |
| Statuscodes | 200 400 401 403 404 429 |
|---|---|
| Ratenbegrenzung | 6 pro Stunde |
GET /export
Alles, was der Schlüssel lesen darf, als ZIP: eine Datei pro Entität plus manifest.json mit dem Inhalt des Archivs, der Zeilenzahl je Datei und den fehlenden Entitäten. Was die Rolle des Schlüssels nicht lesen darf, fehlt, statt die ganze Anfrage abzulehnen — das Manifest sorgt dafür, dass das nicht stillschweigend geschieht.
Parameter und Antworten
| Name | Ort | Typ |
|---|---|---|
bom | query | boolean |
format | query | string |
from | query | string |
to | query | string |
| Statuscodes | 200 400 401 403 404 429 |
|---|---|
| Ratenbegrenzung | 6 pro Stunde |
What an export does not contain
Ein Export enthält nichts, was authentifiziert: keine Kanal-Konfiguration, keine Heartbeat-Token, keine Passwort-Hashes. Die Konfiguration eines Monitors ist enthalten, ohne alles, was nach Zugangsdaten aussieht — Anfrage-Body, Header, SNMP-Community, Postfach-Login. Rohe Prüfergebnisse fehlen ebenfalls: Sie verfallen durch die Aufbewahrungsfrist, deshalb stammt die Verfügbarkeit aus den Rollups.
Size, and the one refusal you may meet
Die stündlichen Reihen sind auf 92 Tage pro Anfrage begrenzt; ein größeres Fenster wird mit export_window_too_wide abgelehnt statt still gekürzt. Eigener Grenzwert: 6 Exporte pro Stunde je Organisation.
Versionierung
Die Version steht im Pfad. Den Antworten werden Felder hinzugefügt — behandeln Sie unbekannte als etwas zu Ignorierendes und nicht als Fehler —, aber aus v1 wird nichts entfernt und ändert darin seine Bedeutung.
Fehlt etwas?
Die Oberfläche ist bewusst klein: Sie deckt eine Wandtafel, eine Zusammenfassung im Chat und ein Deployment-Skript ab, das einen Monitor für die Dauer eines Rollouts stummschaltet. Wenn Sie etwas bauen, das sie nicht erreicht, schreiben Sie an support@vitrinaengine.com — zu wissen, was die Leute wirklich wollen, ist die Art, wie der nächste Endpunkt ausgewählt wird.