Data API
Die Endpunkte, mit denen der Browser-Code einer App Datenbank, Dateien, Runs, Sessions und Freigaben ihres Environments liest und ändert und Retrieval durchsucht. Die Zugriffsregeln der App filtern jede Anfrage.
Auf dieser Seite
Jeder Pfad liegt auf dem eigenen Host der App unter /_connic/. Anfragen tragen deshalb die Session des Besuchers und brauchen keinen API Key. Jede Anfrage liest oder ändert die Daten des Environments der App und durchläuft ihre Zugriffsregeln: Die Spalte Regel unten nennt die Regel, die gilt. Datenanfragen starten keine Agent-Runs.
Anfragen
- Nur die eigenen Seiten der App können diese Pfade nutzen. Anfragen von anderen Websites lehnt connic mit 403 ab; maßgeblich sind die Header
OriginundSec-Fetch-Site, die Browser senden. - Jede Anfrage außer GET, auch Lesezugriffe wie
find, muss denOriginder App undcontent-type: application/jsonsenden. Das gilt auch für Anfragen ohne Body, etwa um einen Run abzubrechen oder eine Session zu löschen. - Bodys sind JSON-Objekte bis 1 MiB. Unbekannte Felder werden abgelehnt.
- Antworten sind JSON und werden nie gecacht. Fehler haben die Form
{"error": "..."}; siehe Fehler. - Verlangt die App eine Anmeldung, bekommt eine Anfrage ohne gültige Session ein 401. Schick den Besucher dann zu
/_connic/login?return=<path>.
async function connic(path, body) {
const response = await fetch(`/_connic/${path}`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body ?? {}),
});
if (response.status === 401) {
location.assign(`/_connic/login?return=${encodeURIComponent(location.pathname)}`);
}
const result = await response.json();
if (!response.ok) throw new Error(result.error);
return result;
}
const { documents, total } = await connic("db/tickets/find", {
filter: { status: "open" },
sort: { _created_at: -1 },
limit: 20,
});Die Beispiele auf dieser Seite nutzen diese Hilfsfunktion connic().
Der Besucher
GET /_connic/me liefert den Besucher und die App. Dafür braucht es keine Regel. In einer öffentlichen App ist id die Besucher-ID des Browsers, email und name sind null, und signed_in ist false.
{
"user": {
"id": "8d2f6c1a-4b7e-4f0a-9c3d-2e5b7a9f1c64",
"email": "ada@example.com",
"name": "Ada Lovelace",
"groups": ["support"],
"signed_in": true
},
"app": {"key": "portal", "name": "Support portal"}
}Datenbank
| Anfrage | Body oder Query | Antwort | Regel |
|---|---|---|---|
| POST /_connic/db/<collection>/find | {filter?, sort?, limit?, skip?, fields?} | {documents, count, total} | read |
| POST /_connic/db/<collection>/count | {filter?} | {count} | read |
| POST /_connic/db/<collection>/insert | {document} oder {documents}, bis zu 50 | 201 {inserted, inserted_count} | insert |
| POST /_connic/db/<collection>/update | {filter, update} | {updated} | update |
| POST /_connic/db/<collection>/delete | {filter} | {deleted} | delete |
- Filter nutzen die Operatoren der Database Tools:
$eq,$ne,$gt,$gte,$lt,$lte,$in,$nin,$and,$or,$not,$nor,$exists,$contains,$elemMatch,$regexund$near. Die Systemfelder heißen_id,_created_atund_updated_at. findliefert standardmäßig 25 Dokumente und mitlimitbis zu 100.sortordnet Feldern1oder-1zu,skipblättert durch die Ergebnisse, undfieldslistet die Felder, die zurückkommen.countist die Zahl der gelieferten Dokumente,totaldie Zahl der erlaubten Dokumente, die passen.updateunddeletebrauchen einen nicht leerenfilter.updatesetzt Felder der obersten Ebene und entfernt Felder mitnull, wie db_update.- Inserts bekommen die
set-Felder der Regeln.insertedlistet die gespeicherten Dokumente mit ihren Systemfeldern.
Dateien
| Anfrage | Body oder Query | Antwort | Regel |
|---|---|---|---|
| POST /_connic/files/list | {folder, filter?, limit?, cursor?} | {folder, folders, files, count, total, next_cursor} | read |
| POST /_connic/files/download | {path} | {url, expires_at} | read |
| POST /_connic/files/upload | {path, size, mime_type?, metadata?} | 201, siehe Datei hochladen | write |
| POST /_connic/files/update | {path, new_path?, metadata?} | Die Datei | update |
| POST /_connic/files/delete | {path} | {deleted} | delete |
listzeigt einen Ordner: die Dateien, die der Besucher lesen darf, und die Unterordner mit lesbaren Dateien; siehe Ordner. Standard sind 25 Dateien, höchstens 100; übergibnext_cursoralscursorfür die nächste Seite. Filter nehmen die Operatoren der Datenbank auf_path,_folder,_name,_size,_mime_type,_created_at,_updated_atund Metadaten-Keys.updateverschiebt oder benennt eine Datei mitnew_pathum und führtmetadatamit den Metadaten der Datei zusammen;nullentfernt einen Key. Das Verschieben auf einen belegten Pfad scheitert.- Dateien haben die Felder, die unter Dateien beschrieben sind.
Datei hochladen
Uploads laufen in Teilen, bis zu 1 GiB pro Datei. Die Regel write prüft Pfad, Größe, MIME-Typ und Metadaten, bevor der Upload beginnt.
POST /_connic/files/uploadmit Pfad und Größe, optional mitmime_typeundmetadata. Ohnemime_typeleitet connic den Typ aus dem Dateinamen ab.Schicke jeden Teil mit
PUT <upload_url>/parts/<n>?token=<token>, nummeriert ab 1. Jeder Teil außer dem letzten ist genaupart_byteslang.Schließe mit
POST <upload_url>/complete?token=<token>ab. Die Antwort ist die gespeicherte Datei. Um abzubrechen, schicke stattdessenDELETE <upload_url>?token=<token>.
{
"upload_id": "5f1d8a2c-7b3e-4c9a-a1d4-0e6b2f8c9d31",
"path": "attachments/screenshot.png",
"size": 48213,
"part_bytes": 16777216,
"part_count": 1,
"upload_url": "/_connic/files/transfer/uploads/5f1d8a2c-7b3e-4c9a-a1d4-0e6b2f8c9d31",
"token": "...",
"expires_at": "2026-10-29T10:30:00+00:00"
}const file = input.files[0];
const upload = await connic("files/upload", {
path: `attachments/${file.name}`,
size: file.size,
metadata: { ticket_id: ticketId },
});
const token = encodeURIComponent(upload.token);
for (let part = 1; part <= upload.part_count; part++) {
const start = (part - 1) * upload.part_bytes;
await fetch(`${upload.upload_url}/parts/${part}?token=${token}`, {
method: "PUT",
body: file.slice(start, start + upload.part_bytes),
});
}
const stored = await fetch(`${upload.upload_url}/complete?token=${token}`, { method: "POST" })
.then((response) => response.json());upload_url ist ein Pfad auf dem Host der App, die Content-Security-Policy muss also nicht angepasst werden. Anfragen für Teile brauchen einen Header Content-Length, den Browser bei Blob-Bodys setzen, dürfen bis zu 17 MiB groß sein und müssen vom Origin der App kommen. Der Upload läuft zu expires_at ab. Ein Upload ersetzt nie eine Datei: Ist der Pfad belegt, wird die Datei unter einem nummerierten Namen gespeichert, etwa screenshot (2).png.
Datei herunterladen
POST /_connic/files/download liefert einen Link auf dem Host der App, /_connic/files/transfer/download?token=<token>, der bis expires_at funktioniert. Nutze ihn als Linkziel oder rufe ihn mit fetch ab; er unterstützt Range-Anfragen. Er funktioniert auf den eigenen Seiten der App, als Lesezeichen und als eingetippte Adresse und antwortet mit 403, wenn eine andere Website ihn öffnet.
Verlangt die App eine Anmeldung, brauchen auch Übertragungen unter /_connic/files/transfer/ die Session des Besuchers.
Retrieval
| Anfrage | Body oder Query | Antwort | Regel |
|---|---|---|---|
| POST /_connic/retrieval/search | {namespace, query, limit?, min_score?} | {results}, beste Treffer zuerst | search |
const { results } = await connic("retrieval/search", {
namespace: "help",
query: "Wie ändere ich meine Rechnungsadresse?",
limit: 5,
});{
"results": [
{
"entry_id": "invoice-address",
"namespace": "help.billing",
"content": "Um die Rechnungsadresse zu ändern, öffne die Einstellungen und wähle Abrechnung...",
"score": 0.81,
"metadata": {"title": "Rechnungsadresse ändern", "url": "https://help.example.com/billing/invoice-address"}
}
]
}namespacemuss ein Namespace aus access.retrieval sein oder darunter liegen. Die Suche umfasst diesen Namespace und alle Namespaces darunter, etwahelp.billingbei einer Suche inhelp.queryist Text in natürlicher Sprache mit bis zu 1.000 Zeichen.limitist standardmäßig 5 und höchstens 20.min_score, von 0 bis 1 und standardmäßig 0,3, lässt schwächere Treffer weg.- Jedes Ergebnis ist eine passende Textstelle eines Eintrags:
contentist ihr Text,scoreihre Relevanz von 0 bis 1 undmetadatadie Metadaten des Eintrags, etwa ein Titel oder eine URL zum Verlinken. - Wer einen Namespace durchsuchen darf, kann Inhalt und Metadaten jedes Eintrags darin lesen. Inhalte, die nicht jeder Besucher sehen darf, gehören in einen Namespace, den die App nicht nennt.
- Für eine Suche während der Eingabe warte, bis der Besucher eine Pause macht, bevor du suchst; siehe Limits.
Runs
| Anfrage | Body oder Query | Antwort | Regel |
|---|---|---|---|
| GET /_connic/runs | ?agent, ?status, ?limit, ?cursor | {runs, next_cursor}, neueste zuerst | read |
| GET /_connic/runs/stats | ?agent, ?days (1 bis 90, Standard 7) | {days, total, statuses, average_duration_ms, daily} | read |
| GET /_connic/runs/<id> | Der Run | read | |
| POST /_connic/runs/<id>/cancel | Kein Body | Der Run | cancel |
{
"id": "3c7e9a10-2f4b-4d8e-b6a1-9e0c5d2f7a48",
"agent": "support",
"status": "completed",
"input": "{\"message\": \"Wo ist meine Bestellung?\"}",
"output": "Deine Bestellung ist am Montag rausgegangen.",
"error": null,
"context": {"app": {"id": "…", "key": "portal"}, "end_user": {"id": "…", "signed_in": true}},
"queued_at": "2026-10-29T09:12:03.120000Z",
"started_at": "2026-10-29T09:12:03.410000Z",
"ended_at": "2026-10-29T09:12:05.260000Z",
"duration_ms": 1850
}- Die Liste liefert standardmäßig 25 Runs und mit
limitbis zu 100; übergibnext_cursoralscursorfür ältere Runs.statusfiltert nach einem Run-Status wiecompleted. inputundoutputsind der gespeicherte Text. Parse ihn, wenn er JSON enthält.- Die Statistik umfasst Runs, die in den letzten
daysUTC-Tagen in die Warteschlange kamen:statuseszählt Runs pro Status, unddailylistet{day, runs}für jeden Tag.
Sessions
| Anfrage | Body oder Query | Antwort | Regel |
|---|---|---|---|
| GET /_connic/sessions/<id> | {session, events} | read | |
| DELETE /_connic/sessions/<id> | Kein Body | {"deleted": true} | delete |
Eine Session ist der Gesprächsverlauf eines Agenten mit persistenter Session. Ihre ID lautet session-<agent>-<key>, wobei key der Wert von session.key des Agenten ist, etwa session-support-42 für Gespräch 42. session hat id, agent, state, created_at und updated_at; events listet die gespeicherten Ereignisse des Gesprächs.
Freigaben
| Anfrage | Body oder Query | Antwort | Regel |
|---|---|---|---|
| GET /_connic/approvals | ?status: pending, approved, rejected oder timeout | {approvals}, offene zuerst, bis zu 100 | read |
| POST /_connic/approvals/<id>/decide | {approved, message?, response?} | Die Freigabe | decide |
{
"id": "a8b1c2d3-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
"run_id": "3c7e9a10-2f4b-4d8e-b6a1-9e0c5d2f7a48",
"agent": "billing",
"tool": "issue_refund",
"params": {"order_id": "A-1042", "amount": 120},
"message": "120 EUR für Bestellung A-1042 erstatten?",
"response_label": null,
"status": "pending",
"created_at": "2026-10-29T09:14:00.000000Z",
"resolved_at": null,
"reason": null
}approved ist true oder false, und message ist eine optionale Begründung. Freigaben, die eine Eingabe verlangen, erkennbar an response_label, brauchen zusätzlich response. connic hält den Besucher als Entscheider fest, mit E-Mail-Adresse, Name oder, bei öffentlichen Apps, dem Namen der App. Siehe Approvals.
Fehler
| Status | Bedeutung |
|---|---|
| 400 | Body oder Query sind ungültig, mit dem Feld in der Meldung, etwa {"error": "limit: Input should be less than or equal to 100"}. Ebenso unbekannte Felder, ein Filter, den die Datenbank ablehnt, und ein Update eines set-Felds. |
| 401 | {"error": "Sign-in required"}: Die App verlangt eine Anmeldung, und der Besucher hat keine gültige Session. Schick ihn zu /_connic/login. |
| 403 | {"error": "Access denied"}: Die Regeln erlauben die Operation nicht. {"error": "Only same-origin JSON requests are allowed"}: Die Anfrage kam von einer anderen Website, oder eine Anfrage, die kein GET ist, kam ohne content-type: application/json. Dateiübertragungen antworten mit {"error": "Only same-origin requests are allowed"}. |
| 404 | Der Run, die Datei, die Session oder die Freigabe existiert nicht oder die Regeln erlauben sie nicht, etwa {"error": "Run not found"}. {"error": "App not found"}, wenn die App nicht mehr ausgeliefert wird. |
| 405 | Falsche Methode für den Pfad. Der Body ist {"detail": "Method Not Allowed"}. |
| 411 | Eine Dateiübertragung mit Body, aber ohne Content-Length. |
| 413 | Der Body ist größer als 1 MiB, oder eine Anfrage einer Dateiübertragung ist größer als 17 MiB. |
| 429 | {"error": "Too many requests. Try again in a minute."} Siehe Limits. |
| 500 | Eine Zugriffsregel hat für diesen Besucher einen zu großen Datenbankfilter ergeben; siehe So wirken die Regeln. |
| 502 | connic konnte die Anfrage nicht abschließen. Versuche es noch einmal. |
Limits
- Jeder Besucher kann pro Minute 300 Lese- und 60 Schreibanfragen sowie 30 Retrieval-Suchen senden. Angemeldete Besucher zählen pro Konto, öffentliche pro IP-Adresse.
- Jede App kann pro Minute 6.000 Lese- und 1.200 Schreibanfragen sowie 600 Retrieval-Suchen über alle Besucher annehmen.
- Listen liefern bis zu 100 Einträge pro Anfrage, Inserts nehmen bis zu 50 Dokumente, und Run-Statistiken umfassen bis zu 90 Tage.
Schreibzugriffe erscheinen im Audit Log des Projekts mit der App und der ID des Besuchers. Jede Anfrage zählt in den Statistiken der App als Datenanfrage, eine abgelehnte zusätzlich als abgelehnte Anfrage.