API-brug
Lær at bruge API-nøgler til at køre apps programmatisk.
Adgang
- Udvikler, Administrator: Kan oprette og bruge API-nøgler. Anmelder-rollen har ikke adgang — API-nøgler er byggeværktøj.
Forudsætninger
- En aktiv API-nøgle (se API-nøgler)
- En udgivet app du har adgang til
Kør app via API
Endpoint
POST /api/v1/apps/{app_id}/run
Headers
Authorization: Bearer sk_din_api_nøgle
Content-Type: application/json
Request body
{
"inputs": {
"input_felt_1": "værdi",
"input_felt_2": 123
}
}
Fil-inputs
Inputs af typen file sendes som et JSON-objekt med tre felter:
{
"inputs": {
"document": {
"filename": "rapport.pdf",
"mime_type": "application/pdf",
"data": "<base64-kodet indhold>"
}
}
}
| Felt | Beskrivelse |
|---|---|
filename | Det originale filnavn (f.eks. "rapport.pdf") |
mime_type | Filens MIME-type (f.eks. "application/pdf") |
data | Filens indhold, base64-kodet (uden data: prefix) |
Response
Svaret indeholder to felter: execution_id og results.
{
"execution_id": "3f9c1b8a-2c47-4f0e-9c1f-8d2a5b7e4c10",
"results": {
"output_felt": "resultat"
}
}
execution_id er kørslens id — brug det til at slå kørslen op under Kørselslog (se Kørselslog).
Fil-outputs ligger inde i results i samme format som fil-inputs:
{
"execution_id": "3f9c1b8a-2c47-4f0e-9c1f-8d2a5b7e4c10",
"results": {
"dokument": {
"filename": "resultat.pdf",
"mime_type": "application/pdf",
"data": "<base64-kodet indhold>"
}
}
}
Når kørslen venter på godkendelse
Har appen et godkendelsestrin, kan kørslen stoppe
undervejs og vente på, at en person tager stilling under
Godkendelser. Så svarer /run ikke med et resultat, men med
statuskoden 202 Accepted og samme svar som /run-async:
{
"execution_id": "3f1c...",
"status": "PAUSED",
"approval": {
"approval_id": "9b2e...",
"title": "Skal brevet sendes?",
"expires_at": "2026-09-10T09:00:00Z",
"status": "PENDING",
"approver_names": [],
"approver_team_name": "Økonomi"
},
"poll_after_seconds": 5
}
Kørslen er ikke fejlet — den venter. Spørg til den med
GET /apps/{app_id}/runs/{execution_id} (se Spørg til kørslen),
gerne med det interval, poll_after_seconds angiver. Godkendes den, fortsætter
kørslen og ender som COMPLETED; afvises den, eller udløber fristen, ender den som
FAILED. Et program, der kalder /run, skal altså kunne håndtere et 202-svar.
Asynkron kørsel
Lange kørsler - OCR af store PDF'er, løkker, AI-kæder - kan nå at løbe ind i timeout hos din klient eller proxy, mens et almindeligt kald venter på svaret. Start i stedet kørslen asynkront: du får et kørsels-id med det samme og spørger til resultatet bagefter.
Start kørslen
POST /api/v1/apps/{app_id}/run-async
Headers og request body er præcis de samme som ved /run - også fil-inputs.
Svaret kommer med det samme, med statuskoden 202 Accepted:
{
"execution_id": "3f1c...",
"status": "PENDING"
}
Alle afvisninger er de samme som ved /run (401, 404, 410, 422), så en 202 betyder,
at kørslen faktisk er sat i gang. Selve inputtet valideres dog først under kørslen: et
forkert udfyldt felt bliver derfor til en kørsel med status FAILED og den samme
forklaring, som /run ville have svaret 422 med.
Spørg til kørslen
GET /api/v1/apps/{app_id}/runs/{execution_id}
{
"execution_id": "3f1c...",
"status": "COMPLETED",
"results": {
"output_felt": "resultat"
},
"error": null,
"started_at": "2026-09-07T09:00:01Z",
"completed_at": "2026-09-07T09:02:44Z",
"total_nodes": 7,
"completed_nodes": 7
}
| Status | Betydning |
|---|---|
PENDING | Kørslen er accepteret, men er ikke begyndt endnu |
RUNNING | Kørslen er i gang |
COMPLETED | Kørslen er færdig - results indeholder svaret |
FAILED | Kørslen fejlede - error forklarer hvorfor. Også når en godkendelse blev afvist eller udløb |
PAUSED | Kørslen venter på en godkendelse - approval viser hvilken, og poll_after_seconds hvor ofte du bør spørge |
CANCELLED | Kørslen blev annulleret og bliver ikke færdig |
results er nøjagtig det samme, som /run ville have svaret med - også filer, der
returneres i samme { filename, mime_type, data }-format.
Kørslen kan kun hentes af den, der startede den: en API-nøgle kan læse sine egne
asynkrone kørsler, men får 403, hvis den spørger til en kørsel, en anden har startet.
Kender appen ikke kørslen, er svaret 404.
Eksempel med cURL
# 1. Start kørslen
EXECUTION_ID=$(curl -s -X POST "https://din-server.dk/api/v1/apps/{app_id}/run-async" \
-H "Authorization: Bearer sk_din_api_nøgle" \
-H "Content-Type: application/json" \
-d '{"inputs": {"tekst": "Hej verden"}}' | jq -r .execution_id)
# 2. Spørg til kørslen
curl "https://din-server.dk/api/v1/apps/{app_id}/runs/$EXECUTION_ID" \
-H "Authorization: Bearer sk_din_api_nøgle"
Eksempel med Python
import time
import requests
BASE = "https://din-server.dk/api/v1"
HEADERS = {"Authorization": "Bearer sk_din_api_nøgle"}
accepted = requests.post(
f"{BASE}/apps/{app_id}/run-async",
headers=HEADERS,
json={"inputs": {"tekst": "Hej verden"}},
)
execution_id = accepted.json()["execution_id"]
while True:
run = requests.get(f"{BASE}/apps/{app_id}/runs/{execution_id}", headers=HEADERS).json()
if run["status"] in ("COMPLETED", "FAILED", "CANCELLED"):
break
time.sleep(2)
if run["status"] == "COMPLETED":
print(run["results"])
else:
print("Kørslen fejlede:", run["error"])
Kørslen lever i den server, der tog imod kaldet. Bliver serveren genstartet eller
opdateret midt i en kørsel, bliver kørslen ikke genoptaget - den bliver stående som
PENDING eller RUNNING. Start den forfra, hvis en kørsel ikke er blevet færdig
inden for det, du forventer.
Streaming-kørsel
For at modtage real-time opdateringer under kørsel:
Endpoint
POST /api/v1/apps/{app_id}/run-stream
Headers
Authorization: Bearer sk_din_api_nøgle
Accept: text/event-stream
Content-Type: application/json
SSE Events
Du modtager følgende event-typer:
| Event | Beskrivelse |
|---|---|
node_start | En byggeklods starter |
node_complete | En byggeklods er færdig |
node_error | En byggeklods fejlede |
node_skipped | En byggeklods blev sprunget over (f.eks. en gren der ikke blev valgt) |
flow_complete | Hele flowet er færdigt. Felter: results, execution_id |
flow_error | Flowet fejlede. Felter: error, error_type, traceback, execution_id |
Kører flowet en løkke, får du desuden disse events undervejs:
| Event | Beskrivelse |
|---|---|
loop_start | Løkken går i gang |
loop_iteration_start | En gentagelse starter |
loop_iteration_complete | En gentagelse er færdig |
loop_iteration_error | En gentagelse fejlede |
loop_break | Løkken blev afbrudt før tid |
loop_continue | En gentagelse blev sprunget over |
loop_complete | Løkken er færdig med alle gentagelser |
node_start bærer feltet resolved_inputs med de input, byggeklodsen fik, sådan som de bliver gemt i kørselshistorikken — ikke nødvendigvis selve værdierne:
- En værdi, der kommer uændret fra en tidligere byggeklods, står som en henvisning:
{"__input_ref__": {"node": "<id>", "handle": "<udgang>"}}. Værdien er den, du allerede har fået i den byggeklods'node_complete-event (result, eller nøglenhandlei den, nårhandleikke erresult). - En meget stor værdi står som
{"__truncated__": true, "size_bytes": …, "preview": "…"}.
Brug node_complete og flow_complete, når du skal bruge selve resultaterne.
Kørselshistorikken er uændret for dig: GET /executions/{id} slår henvisningerne op i samme kørsels egne rækker (aldrig på tværs af kørsler) og serverer node_executions[].inputs som værdier, afkortet som et almindeligt input. Vil du selv slå dem op, giver ?hydrate=false dig rækkerne, som de er gemt — med henvisninger. Kørslens inputs_format er 2, når rækkerne kan indeholde henvisninger, og null for ældre kørsler, hvor alt står inline.
Linjer der starter med : er keepalive-kommentarer, som serveren sender under lange pauser, så forbindelsen ikke lukkes. Din klient skal ignorere dem.
Find appens endpoint og feltnavne
Du behøver ikke gætte hverken adressen eller feltnavnene — appen viser dem selv.
- Åbn appen fra Apps.
- Vælg fanen API (adressen bliver
/apps/{app_id}?tab=api).
Fanen indeholder:
- Endpoint & autentifikation — POST-endpointet med en Kopiér-knap, en note om at bruge din personlige API-nøgle med link til Udviklerværktøjer → API-nøgler, og en tæller der viser antal kald i alt.
- Input-felter og Output-felter — feltnavn, type og mærkatet påkrævet på de felter, der skal med.
- Eksempel på request og Eksempel på response — færdige eksempler på headers, JSON-body, cURL og svaret.

Kopiér feltnavnene direkte fra Input-felter og Output-felter i stedet for at gætte dem. Navnene kommer fra appens opsætning og kan afvige fra det, felterne hedder i brugerfladen.
Begrænsninger
API-nøgler kan kun bruges til at køre apps. De kan ikke:
- Liste agenter
- Oprette agenter
- Liste apps
- Oprette apps
- Ændre brugerdata
- Læse kørselshistorik. Den ene undtagelse er en asynkron kørsel, nøglen selv har startet: den kan hentes med
GET /apps/{app_id}/runs/{execution_id}(se Asynkron kørsel)
Fejlhåndtering
| HTTP Status | Betydning |
|---|---|
202 | Asynkron kørsel accepteret — eller en /run-kørsel, der venter ved et godkendelsestrin ("status": "PAUSED"). Svaret indeholder execution_id |
401 | Ugyldig eller tilbagekaldt API-nøgle — eller ingen adgang til appen (samme svar i begge tilfælde) |
404 | Appen findes ikke |
410 | Appen er ikke aktiv længere (f.eks. arkiveret) |
422 | Manglende eller forkert input |
500 | Serverfejl |
Fejler selve kørslen (typisk 422 fra flowets egen validering eller 500), er detail en forklaring på dansk, og svaret bærer headeren X-Execution-Id med kørslens id, når kørslen nåede at blive registreret. Brug id'et til at slå kørslen op, når du er logget ind i AgentBase: under Kørsler (kræver Udvikler-rollen) eller via GET /api/v1/executions/{id} med et almindeligt login-token (JWT, mindst Anmelder-rollen). API-nøglen selv kan ikke læse kørsler — bortset fra en asynkron kørsel, den selv har startet (se Asynkron kørsel). Headeren mangler, når kørslen aldrig startede — fx når et påkrævet felt mangler.
Eksempel med cURL
curl -X POST "https://din-server.dk/api/v1/apps/{app_id}/run" \
-H "Authorization: Bearer sk_din_api_nøgle" \
-H "Content-Type: application/json" \
-d '{"inputs": {"tekst": "Hej verden"}}'
Eksempel med Python
import requests
response = requests.post(
"https://din-server.dk/api/v1/apps/{app_id}/run",
headers={
"Authorization": "Bearer sk_din_api_nøgle",
"Content-Type": "application/json"
},
json={"inputs": {"tekst": "Hej verden"}}
)
result = response.json()
print(result["results"])
Eksempel med fil-upload (Python)
import base64
import requests
# Indlæs fil og konvertér til base64
with open("dokument.pdf", "rb") as f:
file_data = base64.b64encode(f.read()).decode("utf-8")
response = requests.post(
"https://din-server.dk/api/v1/apps/{app_id}/run",
headers={
"Authorization": "Bearer sk_din_api_nøgle",
"Content-Type": "application/json"
},
json={
"inputs": {
"document": {
"filename": "dokument.pdf",
"mime_type": "application/pdf",
"data": file_data
}
}
}
)
result = response.json()
print(result["results"])