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 zetcore.kind: service_accountop elk account, zodat één regel alle accounts tegelijk kan treffen, bijvoorbeeld om elk account weg te houden bij HR-dossiers. PATCHvervangt 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) totto(niet inbegrepen). Zonder beide is het de lopende kalendermaand in UTC, en een grens die je weglaat wordt uit die maand ingevuld. Eentodie niet nafromligt, geeft422opto. - De kosten zijn berekend tegen de prijzen die golden toen elke beurt draaide;
unpricedtelt het verbruik waarvoor geen prijs gold, en dat telt als nul mee incost_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
failedvast metservice_account_paused. - Het account werk geven geeft
409metreason_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 |