Ga naar inhoud

Serviceaccounts via de API

Het concept achter agents staat in Agents.

Een serviceaccount is een identiteit die je organisatie aan een agent geeft, zodat die kan werken zonder dat er iemand bij is: volgens een planning, als er een gebeurtenis binnenkomt, of als je applicatie hem werk geeft. Op deze pagina maak je een account, bepaal je wie het werk mag geven, geef je het vast werk, lees je terug wat het deed, en pauzeer of verwijder je het.

Een account heeft een naam, de agent die het draait, kenmerken die je organisatie instelt, één eigen API-sleutel en een gereserveerd subject-id, sa:<naam>. Alles wat het account doet, wordt op dat subject-id vastgelegd en beslist op grond van zijn kenmerken, ook als niemand het werk startte. Neem het account acme-planner, dat de agent planner draait met department: ["planning"]. Een planning start de agent elke maandagochtend. Die beurt draait voor sa:acme-planner met department: planning, dus een regel die je organisatie over department schreef, laat hem de bronnen van planning lezen en die van HR niet.

De voorbeelden gebruiken drie sleutels:

Variabele Sleutel Waarvoor
$CORE_KEY een sleutel van je organisatie met management accounts maken, wijzigen, pauzeren en lezen
$ACCOUNT_KEY de eigen sleutel van het account, die je één keer terugkrijgt als je het account maakt het vaste werk van het account, zoals zijn planningen
$APP_KEY de sleutel van de backend van je applicatie, op de lijst opdrachtgevers van het account het account werk geven

Voor het maken, lezen, wijzigen, pauzeren en verwijderen van accounts heb je een sleutel met management nodig; een sleutel zonder krijgt 404. Om een account werk te geven moet je sleutel juist op de lijst opdrachtgevers van het account staan. Het resultaat lees je met de sleutel die het werk gaf, met een sleutel met management of met de eigen sleutel van het account. Een subject-token wordt op elke route onder /service-accounts geweigerd, welke sleutel het ook uitgaf.

Een account maken

curl -s -X POST "$CORE_URL/service-accounts" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d '{"name": "acme-planner",
         "agent": "planner",
         "description": "Maakt de weekplanning voor de afdeling planning",
         "attributes": {"department": ["planning"]},
         "instructors": [{"key_id": "key_7Rb2..."}],
         "capabilities": {"runs": {}, "threads": {}, "schedules": {}},
         "monthly_cost_cap_eur": "50"}'

Core antwoordt met 201, het account en in secret de secret van de sleutel van het account. Je krijgt die secret alleen nu te zien; Core bewaart er alleen de hash van. Bewaar hem waar je backend zijn andere sleutels bewaart.

Veld Wat het doet
name uniek binnen je organisatie: kleine letters, cijfers en koppeltekens, hoogstens 63 tekens. Ligt vast zodra het account bestaat, omdat het subject-id sa:<naam> ervan gemaakt wordt
agent de naam van de opgeslagen agent die het account draait. Je organisatie moet een agent met die naam hebben die de sleutel van het account mag gebruiken, anders geeft het aanmaken 422 op agent
description waar het account voor dient
attributes de kenmerken die Core toepast op alles wat het account doet (Kenmerken)
instructors wie het account naast het beheer werk mag geven (Wie het account werk mag geven)
capabilities de capabilities van de sleutel van het account, zoals bij elke sleutel (De sleutel van het account)
policy het policydocument waaronder de sleutel van het account werkt
monthly_cost_cap_eur, monthly_cost_cap_until de maandlimiet van de sleutel van het account, zoals bij elke sleutel (Limiet per maand)

Het antwoord bevat verder id, subject_id (sa:acme-planner), key_id, status (active) en de instellingen van de mailbox. GET /service-accounts geeft je accounts, een pagina tegelijk (Verzoeken), en GET /service-accounts/{id} leest er één.

Met PATCH /service-accounts/{id} wijzig je de agent, de omschrijving, de kenmerken, de lijst opdrachtgevers en de eigen mailbox van het account. Velden die je weglaat blijven zoals ze zijn; de naam verandert nooit. Kies je een andere agent, dan gaat de regel in de policy van de sleutel die de agent toestaat mee.

Een account kan een eigen mailbox hebben, die Core op nieuwe mail volgt en waarvandaan het verstuurt. Je stelt die in met mailbox, mail_watch en mail_send op dezelfde PATCH, nadat een beheerder de mailbox voor het account heeft gekoppeld (De mailbox van een persoon).

Kenmerken

De kenmerken van een account werken als de kenmerken die je applicatie voor een persoon meestuurt in X-Core-Subject (Een subject meesturen op een beurt): je regels vergelijken ze met de labels op modellen, tools, kennisbronnen en andere onderdelen. Het verschil zit in waar ze vandaan komen. De kenmerken van een persoon komen met elk verzoek mee. Die van een account staan op het account zelf, en Core past ze toe op al het werk van het account: elke aanroep met zijn sleutel, elke keer dat een planning afgaat, elke start van een trigger en elke ronde van een achtergrondrun.

  • Een waarde is een tekst of een lijst teksten; "department": "planning" telt als één waarde.
  • Elke naam en waarde moet passen in het vocabulaire van je organisatie, als die er een heeft.
  • Namen die met core. beginnen zijn van Core en worden geweigerd. Core zet core.kind: service_account op elk account, zodat één regel alle accounts tegelijk kan treffen, bijvoorbeeld om elk account weg te houden bij HR-dossiers.
  • PATCH vervangt de kenmerken in hun geheel. Werk dat al loopt gebruikt de nieuwe waarden vanaf zijn volgende ronde.

De sleutel van het account

Het account heeft precies één sleutel. Het is een gewone sleutel: je stuurt hem als bearer-token mee, stelt zijn capabilities, policy en maandlimiet in en roteert hem zoals elke andere. Op een paar punten wijkt hij af.

Twee capabilities zijn niet toegestaan. management en subjects geven 422 op de sleutel van een account. Een account dat de organisatie kan beheren, zou zijn eigen kenmerken en opdrachtgevers kunnen aanpassen, en een account dat subject-tokens kan uitgeven, zou voor mensen kunnen handelen. Geef de sleutel de capabilities die het werk van het account nodig heeft: runs en threads voor achtergrondbeurten (werk dat je het account geeft, is altijd een achtergrondbeurt), en schedules als het eigen planningen bijhoudt.

De sleutel draait alleen de agent van het account. Core zet één regel in de policy van de sleutel die de agent van het account toestaat, en zet settings.agents_required aan. Elke beurt met de sleutel moet dus die agent noemen en draait hem zoals hij is vastgelegd: een beurt die eigen tools, skills, instructions of een eigen prompt toevoegt, geeft 403 (Een agent aanroepen). Een wijziging van de policy die de regel of de instelling weghaalt, geeft 422 op policy.

De sleutel handelt alleen als het account. Elk verzoek met de sleutel van het account is voor sa:<naam>, of het een subject noemt of niet. Een verzoek dat in X-Core-Subject of in user een andere persoon noemt, geeft 403. Een header die het account zelf noemt, mag geen kenmerken meesturen (422), want de kenmerken van het account zijn de opgeslagen kenmerken.

Geen andere sleutel kan als het account handelen. Alleen de eigen sleutel van het account mag een subject-id noemen dat met sa: begint. Elke andere sleutel die er een noemt, in X-Core-Subject, in user of in de subject_id van een planning, krijgt 403. Hetzelfde geldt voor het uitgeven van een subject-token voor een account. Wil je werk voor een account starten, gebruik dan zijn sleutel, of geef het werk zoals hieronder staat.

Pauzeren en verwijderen gaan via het account. De sleutelroutes weigeren de sleutel van een account uit te schakelen, in te schakelen of te verwijderen met 409. Pauzeer, hervat of verwijder in plaats daarvan het account (hieronder), zodat sleutel en account altijd overeenkomen.

Het account vast werk geven

Vast werk is werk dat het account uit zichzelf doet: planningen, en de triggers en webhooks die workflows starten. Schrijf het met de eigen sleutel van het account. Werk dat zo is geschreven, draait voor sa:<naam>, met de kenmerken van het account zoals ze zijn op het moment dat het afgaat, en wordt betaald uit het budget van de sleutel van het account.

Een planningsoverzicht op de eerste maandag van elke maand om negen uur:

curl -s -X POST "$CORE_URL/schedules" \
    -H "Authorization: Bearer $ACCOUNT_KEY" -H "Content-Type: application/json" \
    -d '{"name": "maandplanning",
         "cron": "0 9 * * 1#1",
         "timezone": "Europe/Amsterdam",
         "request": {"agent": {"id": "planner"},
                     "input": "Maak de planning voor deze maand."}}'

Het opgeslagen verzoek noemt de agent van het account, omdat de sleutel er bij elke beurt een eist. subject_id mag je weglaten: de beurt draait hoe dan ook voor sa:acme-planner. 1#1 is de eerste maandag van de maand; Wat een cron-expressie betekent noemt de andere vormen en hoe je ze vooraf bekijkt.

Al het andere aan de planning werkt zoals in Planningen via de API: wanneer ze afgaat, haar last_error, nu laten lopen, en de lijst van wat ze opleverde. Zolang het account gepauzeerd is, legt elke keer dat ze afgaat failed vast met service_account_paused; de planning blijft aan en gaat weer af op het eerste moment nadat je het account hervat.

Een beheerder in de beheerconsole zet hetzelfde vaste werk op door de sleutel van het account te kiezen als de sleutel waarmee de planning draait.

Wie het account werk mag geven

Een account werk geven, of opdracht geven, betekent een beurt of een workflowrun in de wachtrij zetten die daarna draait onder de sleutel van het account, voor sa:<naam>, met de kenmerken van het account. Wie erom vroeg, hoeft zelf niet te kunnen bereiken wat het account bereikt.

Werk dat je een account geeft, draait met de rechten van het account, wie er ook om vroeg. Wie een account opdracht mag geven, kan dus bij alles wat het account kan bereiken, ook bij wat hij zelf niet kan bereiken. Zet op de lijst alleen sleutels of personen die je de rechten van het account zelf zou toevertrouwen.

instructors bevat hoogstens 32 opdrachtgevers. Elk is een van deze twee:

Opdrachtgever Wie opdracht mag geven
{"key_id": "key_7Rb2..."} elk verzoek met die sleutel, welke persoon het ook noemt, als het er een noemt
{"key_id": "key_7Rb2...", "subject_id": "anna"} alleen verzoeken met die sleutel die de persoon anna noemen

Een persoon zonder sleutel is nooit een opdrachtgever. De sleutel is het deel van het verzoek dat Core heeft gecontroleerd; de persoon is wat de sleutel zegt. Een opdrachtgever die alleen een persoon noemt, zou elke sleutel laten beweren dat hij namens haar komt.

Een lege lijst betekent dat alleen het beheer het account opdracht mag geven: sleutels met management en de beheerders van je organisatie in de beheerconsole. Zij mogen dat altijd, omdat ze de lijst toch kunnen aanpassen.

Elke sleutel op de lijst moet een sleutel van je organisatie zijn die zelf niet van een account is, en geen opdrachtgever mag het subject-id van een account noemen. Een opdrachtgever die daartegen ingaat, geeft 422 op instructors[<i>].key_id of instructors[<i>].subject_id. Een PATCH met instructors vervangt de hele lijst.

Het account een beurt geven

De backend van je applicatie geeft het account een beurt met de eigen sleutel van de backend, niet die van het account. De body is die van POST /responses:

curl -s -X POST "$CORE_URL/service-accounts/sva_4Kp9.../responses" \
    -H "Authorization: Bearer $APP_KEY" -H "Content-Type: application/json" \
    -H 'X-Core-Subject: {"id": "anna"}' \
    -H "Idempotency-Key: planverzoek-2026-10-23-anna" \
    -d '{"input": "Anna vraagt volgende week twee dagen vrij; plan daaromheen."}'

Core antwoordt met 201, een Location-header en het antwoord met "status": "queued". De beurt draait altijd als opgeslagen achtergrondrun onder de sleutel van het account, voor sa:acme-planner; Core zet background en store zelf en negeert stream en user. Noemt de body geen agent, dan draait de eigen agent van het account.

De persoon in X-Core-Subject is degene die het vraagt: Core toetst haar aan de lijst opdrachtgevers en legt haar naast je sleutel vast als opdrachtgever. Zij is niet het subject van de beurt; dat is het account. Stuur je dezelfde Idempotency-Key nog eens, dan geeft Core de beurt terug die het al in de wachtrij zette, in plaats van een tweede te maken.

Status Wat het betekent Wat je doet
403 deze sleutel, of deze sleutel voor deze persoon, staat niet op de lijst opdrachtgevers voeg een opdrachtgever toe, of gebruik een sleutel die op de lijst staat
409 met reason_code: "service_account_paused" het account is gepauzeerd hervat het eerst
409 de sleutel van het account kan niet handelen, omdat het account wordt verwijderd niets; het account verdwijnt
404 je organisatie heeft geen account met dit id controleer het id

Lees het resultaat op het adres uit Location:

curl -s "$CORE_URL/service-accounts/sva_4Kp9.../responses/resp_9Tm3..." \
    -H "Authorization: Bearer $APP_KEY" -H 'X-Core-Subject: {"id": "anna"}'

Het antwoord is hetzelfde als bij GET /responses/{id}. Je krijgt het met de sleutel die de beurt gaf, voor de persoon die die noemde, met een sleutel met management, en met de eigen sleutel van het account. Elke andere aanvrager krijgt 404.

Of start een workflowrun met POST /service-accounts/{id}/workflow_runs en een body met workflow_id, en eventueel version, input, variables en labels. Daarvoor geldt dezelfde lijst opdrachtgevers; het antwoord is 202 met de run, die voor sa:<naam> draait. De sleutel van het account moet naast runs en threads ook workflows hebben, dus zet eerst "workflows": {} bij zijn capabilities; zonder geeft het starten 422 op run_as_key_id. Volg hem met GET /workflow_runs/{id}.

De runs van het account opvragen

GET /service-accounts/{id}/responses geeft de runs van het account, de nieuwste eerst: elke opgeslagen beurt die voor sa:<naam> draaide, of die nu gegeven werd, door een planning werd gestart, met de eigen sleutel van het account begon of door een stap van zijn workflowruns werd gedraaid, voor zover je sleutel ze mag zien onder de regels van je organisatie voor gesprekken. Daarmee bouw je een werkvoorraad of een overzicht van wat het account doet, zonder zelf een index bij te houden.

curl -s "$CORE_URL/service-accounts/sva_4Kp9.../responses?status=requires_action&status=failed" \
    -H "Authorization: Bearer $CORE_KEY"

De lijst vraagt een sleutel met management en threads; een sleutel zonder een van beide krijgt 404. De eigen sleutel van het account heeft nooit management en krijgt hier dus 404. Een beheerder van je organisatie leest dezelfde lijst via GET /tenants/{tenant_id}/service-accounts/{account_id}/responses.

Parameter Beperkt de lijst tot
status runs in die toestand: queued, in_progress, requires_action, completed, failed, cancelled of incomplete. Herhaal de parameter om meerdere toestanden tegelijk op te vragen
schedule_id runs die die planning startte
from runs gemaakt op of na dit moment
to runs gemaakt vóór dit moment. Zonder from of to heeft de lijst aan die kant geen tijdsgrens; een to die niet na from ligt, geeft 422 op to
limit, cursor een pagina tegelijk (Verzoeken)
{"items": [
  {"id": "resp_9Tm3...",
   "status": "requires_action",
   "created_at": "2026-10-23T08:14:02Z",
   "completed_at": null,
   "thread_id": "thr_2Hc8...",
   "schedule_id": null,
   "instructed_by_key_id": "key_7Rb2...",
   "instructed_by_subject_id": "anna"}],
 "next_cursor": null}

instructed_by_key_id en instructed_by_subject_id noemen wie de run gaf; ze zijn allebei null voor werk dat niemand gaf, zoals een planning die afging. schedule_id noemt de planning die de run startte, en is null voor andere runs en zodra die planning is verwijderd. De uitvoer staat niet in een item: lees een run volledig met GET /responses/{id}.

Een run op requires_action wacht op het resultaat van een tool die je applicatie zelf uitvoert. Stuur de resultaten in met de sleutel van het account, zoals bij elke achtergrondrun (Toolresultaten indienen).

De trace van een antwoord openen

De beurten van het account schrijven in gesprekken zoals elke opgeslagen beurt, en je leest ze met GET /threads/{thread_id}/items. Elk item dat een beurt schreef heeft een response_id, het id van de beurt die het schreef. Met dat id vraag je de modelaanroepen van de beurt op (Een trace lezen):

curl -s "$CORE_URL/responses/resp_9Tm3.../trace" -H "Authorization: Bearer $CORE_KEY"

Elk item geeft het id, de tijden, de status en het tokengebruik van een aanroep, en de tools die het antwoord van die aanroep liet draaien; tekst van prompt of antwoord staat er niet in. Wil je zien wat er naar het model ging en wat het antwoordde, open dan één aanroep met GET /traces/{call_id}. Core legt elke keer dat iemand dat leest vast in het auditlogboek.

Een item dat je applicatie zelf toevoegde, heeft "response_id": null en geen trace. Een sleutel die geen persoon noemt, leest de traces van de beurten van het account zoals hij elke beurt van je organisatie leest.

Het overzicht lezen

curl -s "$CORE_URL/service-accounts/sva_4Kp9.../summary?from=2026-10-01T00:00:00Z" \
    -H "Authorization: Bearer $CORE_KEY"
{"service_account_id": "sva_4Kp9...",
 "subject_id": "sa:acme-planner",
 "from": "2026-10-01T00:00:00Z",
 "to": "2026-11-01T00:00:00Z",
 "turns": 42,
 "cost_eur": "3.18",
 "unpriced": 0,
 "refusals": 1,
 "mails_sent": 0,
 "last_activity_at": "2026-10-22T07:00:04Z",
 "by_instructor": [
   {"instructed_by_key_id": null, "instructed_by_subject_id": null,
    "turns": 30, "cost_eur": "2.40", "unpriced": 0, "refusals": 0,
    "mails_sent": 0, "last_activity_at": "2026-10-22T07:00:04Z"},
   {"instructed_by_key_id": "key_7Rb2...", "instructed_by_subject_id": "anna",
    "turns": 12, "cost_eur": "0.78", "unpriced": 0, "refusals": 1,
    "mails_sent": 0, "last_activity_at": "2026-10-21T14:12:40Z"}]}

Het telt de beurten van het account, wat ze kostten, de weigeringen die Core voor het account vastlegde, de mails die zijn mailbox verstuurde en zijn laatste activiteit, in totaal en per opdrachtgever. Een opdrachtgever null staat voor werk dat niemand gaf: de planningen en triggers van het account, en elke mail die het verstuurde. Het lezen verandert niets.

  • De periode loopt van from (inbegrepen) tot to (niet inbegrepen). Zonder beide is het de lopende kalendermaand in UTC, en een grens die je weglaat wordt uit die maand ingevuld. Een to die niet na from ligt, geeft 422 op to.
  • De kosten zijn berekend tegen de prijzen die golden toen elke beurt draaide; unpriced telt het verbruik waarvoor geen prijs gold, en dat telt als nul mee in cost_eur.

Pauzeren en hervatten

curl -s -X POST "$CORE_URL/service-accounts/sva_4Kp9.../pause" \
    -H "Authorization: Bearer $CORE_KEY"

Pauzeren stopt het account meteen. Gebruik het als de sleutel misschien is uitgelekt of als de agent iets doet wat hij niet hoort te doen:

  • Aanroepen met de sleutel van het account geven 401.
  • Planningen en triggers van het account leggen failed vast met service_account_paused.
  • Het account werk geven geeft 409 met reason_code: "service_account_paused".
  • Werk dat loopt, stopt bij zijn volgende ronde en mislukt met service_account_paused. Een modelaanroep of toolaanroep die al bezig is, wordt eerst afgemaakt.

POST /service-accounts/{id}/resume heft de pauze op. Planningen gaan weer af op hun volgende moment; wat in de tussentijd had moeten afgaan wordt niet ingehaald, en runs die met service_account_paused mislukten starten niet opnieuw. Beide routes geven het account terug; vraag je om de toestand die het al heeft, dan verandert er niets.

Een account verwijderen

curl -s -X DELETE "$CORE_URL/service-accounts/sva_4Kp9..." \
    -H "Authorization: Bearer $CORE_KEY"

Core antwoordt met 202 en de status van het account wordt deleting. De sleutel wordt meteen verwijderd, en daarna wist Core het werk van het account zoals het een persoon wist: planningen en triggers voor het account gaan uit, open workflowruns worden geannuleerd, en zijn gesprekken, antwoorden, geheugen, bestanden, datastore-records, traces en koppelingen worden verwijderd. Audit- en verbruiksgegevens blijven staan, met sa:<naam> erop, zolang hun gewone bewaartermijn loopt. Het account verdwijnt zodra zijn werk weg is; tot die tijd kun je geen nieuw account met dezelfde naam maken.

Liep er nog werk, dan wacht de verwijdering. Verwijder het account nog eens als dat werk klaar is om het af te ronden. Staat je organisatie onder een juridische bewaarplicht, dan weigert Core het verwijderen met 409 voordat er iets verandert. Wil je een account stoppen maar bewaren wat het deed, pauzeer het dan.

Veelgemaakte fouten

Wat je ziet Wat er gebeurde
404 op de accountroutes je sleutel heeft geen management, of het account is niet van je organisatie
422 op agent je organisatie heeft geen agent met die naam die de sleutel van het account mag gebruiken
422 op capabilities.management of capabilities.subjects de sleutel van een account mag geen van beide hebben
422 op attributes een naam die met core. begint, of een naam of waarde buiten je vocabulaire
422 op instructors[<i>].key_id de sleutel is niet van je organisatie, of het is de sleutel van een account
409 bij het aanmaken er bestaat al een account met die naam, of het wordt nog verwijderd
403 op een beurt met de sleutel van het account de beurt noemt een andere persoon, of voegt tools, skills of instructies aan de agent toe
403 met sa:... vanaf een andere sleutel alleen de eigen sleutel van het account mag als het account handelen
409 op POST /keys/{id}/disable de sleutel is van een account; pauzeer het account