Ga naar inhoud

Planningen via de API

Het concept achter agents staat in Agents.

Op deze pagina maak je een planning met de API, lees je wat ze opleverde en wijzig of stop je haar. Een planning is werk dat je één keer opslaat en dat Core op een vast moment voor je doet: een verzoek dat Core verstuurt, of een evaluatiesuite die Core laat lopen (verderop). Het meeste van deze pagina gaat over het eerste: elke werkdag om zes uur een samenvatting, maandagochtend een weekoverzicht, of één herinnering op een moment dat jij noemt. Wat er verstuurd wordt is een gewoon responseverzoek, dus alles wat je zelf kunt vragen, kan een planning voor je vragen: vrije invoer, een opgeslagen prompt of een agent.

Je sleutel heeft de capability schedules nodig, en die heeft runs nodig: elke keer dat een planning afgaat is dat een achtergrondbeurt, en je leest het antwoord met GET /responses/{id}, net als bij een beurt die je zelf hebt gevraagd. Hetzelfde doe je met de muis in Planningen in de console.

Een planning maken

curl -s -X POST "$CORE_URL/schedules" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d '{"name": "werkdag-samenvatting",
         "description": "Gisteren, samengevat, voordat iemand binnen is",
         "cron": "0 6 * * 1-5",
         "timezone": "Europe/Amsterdam",
         "request": {"agent": {"id": "agt_5Nj2..."},
                     "input": "Vat gisteren samen in vijf punten."}}'

Een geslaagd verzoek geeft 201 en een Location.

Veld Wat het doet
name uniek binnen je organisatie
cron vijf velden -- minuut, uur, dag van de maand, maand, dag van de week -- gelezen in timezone; 1#1 is de eerste maandag, 5L de laatste vrijdag
timezone een IANA-zonenaam zoals Europe/Amsterdam; UTC als je er geen noemt
at één moment om af te gaan in plaats van een cron; daarna zet de planning zichzelf uit
enabled false slaat hem op zonder hem te laten lopen
kind response (de standaard -- stuur request), evaluation (laat een suite lopen) of workflow (start een workflowrun)
request het verzoek dat elke keer verstuurd wordt, bij kind: "response"
evaluation_id de suite die elke keer gaat lopen, bij kind: "evaluation"
subject_id de persoon voor wie elke beurt is (bouwen voor mensen). Verstuurd met X-Core-Subject voor dezelfde persoon, gelden de attributen die zij opgeeft 30 dagen lang voor elke beurt
labels je eigen indeling, waarop je de lijst kunt filteren

Noem precies één van cron en at. Allebei, of geen van beide, is 422.

Een request mag tool_variables bevatten, de waarden die elke keer meegaan voor de aanroepvariabelen van zijn tools. Een waarde voor een naam die een tool van je organisatie als geheim declareert, wordt versleuteld opgeslagen en nooit teruggelezen: een leesactie laat die naam weg uit request.tool_variables en geeft hem in tool_variable_secrets als {"has_value": true}, en een PATCH waarvan het verzoek de naam weglaat, houdt de opgeslagen waarde.

Een opname in het opgeslagen verzoek noem je met file_id: een inline input_audio-deel wordt geweigerd met 422 op request.input, omdat het schema de opname anders bij elke keer dat het afgaat zou bewaren (Audio transcriberen).

Je sleutel plant als zichzelf. Er is geen veld om een andere sleutel te noemen: de beurten die deze planning afvuurt zijn van jouw sleutel, gaan van jouw budget af en bereiken precies wat jouw sleutel bereikt. Een beheerder die er een aanmaakt in de console kiest wél een sleutel, want een persoon heeft er zelf geen. Een planning die je met de eigen sleutel van een serviceaccount schrijft, gaat af voor het account, met zijn kenmerken (Het account vast werk geven).

Een planning die een persoon zelf schrijft, houdt haar attributen 30 dagen vast. Stuur het aanmaken, of een latere PATCH, met de sleutel waaronder de planning loopt en met X-Core-Subject voor dezelfde persoon als subject_id, en de attributen die zij opgeeft gelden voor elke beurt. Je regels over die attributen beslissen haar geplande beurten dan zoals ze haar live beurten beslissen. Elke zulke wijziging door haar laat de 30 dagen opnieuw ingaan, en een die geen attributen opgeeft, haalt ze weg. Een andere sleutel van je organisatie die de planning aan- of uitzet, laat ze staan. subject_attributes_until staat bij elke keer lezen en zegt tot wanneer; het is null als de beurten alleen haar subject_id dragen. Dat geldt voor een planning die zonder haar is geschreven, een die op iemand anders is gericht en een waarvan de 30 dagen voorbij zijn. De attributen zelf lees je nooit terug (Bouwen voor mensen).

Wat een cron-expressie betekent

Vraag het voordat je hem opslaat:

curl -s -X POST "$CORE_URL/schedules/preview" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d '{"cron": "0 6 * * 1-5", "timezone": "Europe/Amsterdam"}'

Je krijgt de volgende vijf momenten waarop de expressie afgaat, in die zone, en er wordt niets opgeslagen. Eén planning lezen geeft de volgende drie, naast al het andere.

Een weekdag kan een plek in de maand krijgen. 1#1 is de eerste maandag, MON#2 de tweede, 5L de laatste vrijdag en L in het veld dag-van-de-maand de laatste dag. Zo bekijk je "de eerste maandag om negen uur":

curl -s -X POST "$CORE_URL/schedules/preview" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d '{"cron": "0 9 * * 1#1", "timezone": "Europe/Amsterdam"}'

1#5 is een vijfde maandag, en die hebben maar sommige maanden; in de andere wordt hij overgeslagen. Voor de laatste maandag van elke maand schrijf je 1L.

Die zone is precies het punt: 0 6 * * * in Europe/Amsterdam is daar zes uur 's ochtends in januari en in juli, en een planning voor half drie gaat af om drie uur in de nacht dat de klok vooruit gaat, in plaats van te worden overgeslagen.

Wat er gebeurt, en wat niet

Op het moment dat je expressie noemt stuurt Core je opgeslagen verzoek als achtergrondbeurt. Vier velden van dat verzoek zijn van de planning zelf en worden geweigerd als je ze meestuurt: stream, background, store en previous_response_id. Een planning maakt altijd een opgeslagen achtergrondrun. thread_id mag wél, en zo schrijf je een doorlopend gesprek: elke keer komt er iets bij op dezelfde thread.

Een planning leest de klok in haar eigen timezone. Gebruikt het verzoek een prompt waarvan een variabele de ingebouwde waarde date, time, datetime of weekday heeft, dan leest Core die in de timezone van de planning, tenzij het opgeslagen verzoek zelf een timezone noemt. Zo'n variabele hoeft niet in het verzoek te staan: Core vult hem in op het moment dat de planning afgaat. Ook bij het opslaan telt hij niet als een ontbrekende waarde.

Drie dingen om te weten voordat je erop vertrouwt:

  • Niets loopt dubbel. Draait de beurt van de vorige keer nog als het volgende moment komt, dan wordt dat moment overgeslagen in plaats van erachter gezet.
  • Er stapelt zich niets op. Lag Core plat over meerdere momenten heen, dan gaat de planning één keer af en pakt daarna de gewone cadans weer op.
  • Een fout zet hem niet uit. Kan de beurt niet gemaakt worden -- je sleutel is ingetrokken, je beleid weigert het model, het maandbudget is op -- dan legt de planning vast waarom en probeert het op het volgende moment opnieuw.

Dat staat op de planning zelf:

{"last_fired_at": "2026-09-23T04:00:00Z",
 "last_response_id": "resp_8Kd1...",
 "last_outcome": "fired",
 "last_error": null,
 "next_run_at": "2026-09-24T04:00:00Z"}

last_outcome is fired, skipped of failed, en last_error is één kort woord, nooit een zin:

last_error Wat de uitvoering tegenhield
key_revoked de sleutel waarmee de planning afgaat is verwijderd of verlopen; kies een sleutel die werkt
key_disabled de sleutel waarmee de planning afgaat is uitgeschakeld; schakel hem weer in met POST /keys/{key_id}/enable
service_account_paused de sleutel is van een serviceaccount dat gepauzeerd is; hervat het account
tenant_unavailable je organisatie is opgeschort of wordt verwijderd
no_key_to_run_as de suite die deze planning laat lopen noemt geen sleutel meer
evaluation_gone de suite is verwijderd terwijl de uitvoering werd voorbereid
subject_erased de persoon voor wie de planning is, is gewist, waardoor hij uit staat
tool_variables_unreadable de opgeslagen geheime toolvariabelen konden niet worden geopend; stuur ze opnieuw met een PATCH
policy_refused het beleid van je organisatie weigerde de beurt
cap_exceeded de sleutel bereikte zijn maandlimiet
target_gone iets wat de planning noemt, zoals de agent of de workflow, bestaat niet meer
request_invalid het opgeslagen verzoek is niet meer geldig
capability_withdrawn de sleutel verloor een mogelijkheid die de uitvoering nodig heeft
too_many_open je organisatie heeft al zoveel open runs als de installatie toestaat

Een agent op de klok meten

Een planning kan ook een run van een evaluatiesuite in de wachtrij zetten in plaats van een beurt te versturen. Zet kind: "evaluation" en noem de suite; er is geen request, want wat er loopt zijn de gesprekken van de suite zelf:

curl -s -X POST "$CORE_URL/schedules" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d '{"name": "nachtelijke-kwaliteit",
         "cron": "0 3 * * *",
         "timezone": "Europe/Amsterdam",
         "kind": "evaluation",
         "evaluation_id": "ev_7Hq1..."}'

Elke keer dat hij afgaat komt er één run per agent die de suite meet in de wachtrij -- precies wat POST /evaluations/{id}/runs ook doet, met dezelfde klokregels als elke andere planning: een gemiste nacht gaat één keer af in plaats van in te halen, en een suite waarvan de run nog loopt wordt overgeslagen in plaats van twee keer gemeten.

De runs lopen als de sleutel van de suite, niet als de jouwe. Elke evaluatierun loopt als de sleutel die de suite noemt, dus die moet er zijn: een suite zonder run_as_key_id geeft 409 bij het schrijven van de planning, en een sleutel die daarna wordt leeggehaald laat de planning falen met no_key_to_run_as in last_error tot je hem opnieuw zet.

Lees wat hij heeft gedaan via de lijst van de suite zelf, beperkt tot deze planning:

curl -s "$CORE_URL/evaluations/ev_7Hq1.../runs?schedule_id=sch_3Qp8..." \
    -H "Authorization: Bearer $CORE_KEY"

Elke run noemt schedule_id en fired_for, het moment dat aan de beurt was. Deze soort met de hand laten lopen geeft de ids van de runs terug in plaats van de planning: {"object": "schedule.evaluation_fire", "kind": "evaluation", "run_ids": ["evr_..."]}.

De soort ligt vast zodra hij geschreven is -- de geschiedenis van een planning hoort bij één soort, dus PATCH met kind is 422 en het antwoord is: schrijf de andere planning. De suite verwijderen verwijdert de planningen die ervoor stonden; de runs die ze in de wachtrij zetten blijven.

Een workflow op de klok starten

Een planning kan ook een run van een workflow starten in plaats van een beurt te versturen. Zet kind: "workflow", noem de workflow bij zijn naam en geef de invoer waarmee elke run begint; je sleutel heeft naast schedules ook workflows nodig:

curl -s -X POST "$CORE_URL/schedules" \
    -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
    -d '{"name": "ochtend-intake",
         "cron": "0 6 * * 1-5",
         "timezone": "Europe/Amsterdam",
         "kind": "workflow",
         "workflow": "intake",
         "workflow_input": {"source": "mailbox"}}'

Een workflow die niet bestaat of die het beleid van je sleutel niet toestaat geeft 422 op workflow, en invoer die het invoerschema van de workflow weigert geeft 422 met het veld onder workflow_input. Elke keer dat de planning afgaat start er één run van de nieuwste versie van de workflow, als de sleutel waaronder de planning loopt en voor de persoon in subject_id als de planning er een noemt. Zolang de run die de planning het laatst startte nog open is, wordt de volgende keer overgeslagen in plaats van ernaast gestart: een workflow die op iemands beslissing wacht, houdt zijn planning dus vast tot hij klaar is.

last_run_id op de planning noemt de laatste run, en de lijst van runs is tot deze planning te beperken:

curl -s "$CORE_URL/workflow_runs?trigger_id=sch_3Qp8..." \
    -H "Authorization: Bearer $CORE_KEY"

Elke run heeft "trigger_kind": "schedule" en het id van de planning in trigger_id. Als er geen run kon starten staat de reden in last_error: target_gone als de workflow is verwijderd, request_invalid als de opgeslagen invoer niet meer past, too_many_open als je organisatie zoveel open runs heeft als de installatie toestaat. Met PATCH vervang je workflow_input; de workflow die een planning noemt ligt vast, net als de soort.

Lezen wat hij heeft opgeleverd

curl -s "$CORE_URL/schedules/sch_3Qp8.../responses" -H "Authorization: Bearer $CORE_KEY"

Nieuwste eerst, één regel per beurt die deze planning heeft afgevuurd, elk met het id waarmee je hem volledig leest via GET /responses/{id}. De response zelf is het object van de leverancier en noemt geen planning; deze lijst is de weg terug van een beurt naar de planning die hem afvuurde. Een planning met kind: "evaluation" vuurt geen beurten af, dus voor die is deze lijst leeg -- lees zijn runs via de suite (hierboven).

Een planning nu laten lopen

curl -s -X POST "$CORE_URL/schedules/sch_3Qp8.../run" -H "Authorization: Bearer $CORE_KEY"

202, en de beurt staat in de wachtrij precies zoals de klok hem er had gezet. Het verzet het moment van de planning niet. Draait de vorige beurt nog, dan krijg je 409 -- en dat krijg je ook als de planning helemaal niet kon afgaan: de detail begint dan met dezelfde korte soort die ook in last_error van de planning staat, zoals policy_refused of no_key_to_run_as. Een 202 betekent dus altijd dat er echt iets in de wachtrij staat.

Wijzigen en stoppen

PATCH /schedules/{id} wijzigt wat je meestuurt en berekent het volgende moment opnieuw; je kunt een cron-planning omzetten naar een eenmalige at en terug. "enabled": false zet hem stil zonder hem kwijt te raken -- dat is wat je meestal wilt. DELETE /schedules/{id} verwijdert de planning; de beurten die hij al heeft afgevuurd blijven gewoon staan.

De lijst filteren

curl -s "$CORE_URL/schedules?enabled=true&label=afdeling:salaris" \
    -H "Authorization: Bearer $CORE_KEY"

?label= neemt naam:waarde en mag herhaald worden; herhalen betekent alle genoemde, en een naam herhalen vraagt om al die waarden: ?label=afdeling:verkoop&label=afdeling:financien vindt de planningen die met allebei gelabeld zijn. Een planning waarvan het label meerdere waarden heeft, telt mee als de waarde daar een van is.

Veelgemaakte fouten

Wat je ziet Wat er aan de hand is
422 op cron geen vijf velden, of een expressie die nooit kan afgaan (30 februari)
422 op timezone geen IANA-zonenaam
422 op at in het verleden, of zonder tijdzone-offset
422 op request.model het model staat niet in de catalogus van deze installatie, of er wordt er geen genoemd
404 bij aanmaken de agent of prompt die je noemt bestaat niet, of je sleutel mag er niet bij
409 bij aanmaken je hebt al een planning met die naam, of de suite die je noemt loopt als niemand (run_as_key_id)
422 op evaluation_id geen suite van jou heeft dat id
422 op request je stuurde zowel een request als een evaluation_id, of geen van beide, of een request voor een planning die een suite laat lopen
404 op elke route je sleutel heeft de capability schedules niet