Ga naar inhoud

Gebruik en audit via de API

Het concept achter verbruik, audit en traces staat in Inzicht.

Lees verbruiks- en auditgegevens via de API om verbruik te volgen en activiteit te onderzoeken. Deze endpoints zijn beschikbaar voor elke sleutel, zonder extra capability.

Verbruiksgegevens beslaan de hele organisatie, inclusief andere sleutels en werk van consolegebruikers; filter ze met key_id op één sleutel. Auditgebeurtenissen zijn smaller: een sleutel leest alleen die van zichzelf (Auditgebeurtenissen).

Soorten verbruik

kind Geteld als Geschreven wanneer
model_tokens input_tokens, output_tokens; reasoning_tokens zegt hoeveel van de uitvoertokens het model aan denkwerk besteedde, waar de provider dat meldt (null op een registratie waar dat niet zo is; al onderdeel van output_tokens, dus nooit opgeteld) elke modelaanroep, ook een die een tool of een samenvatting deed
cached_tokens input_tokens: het deel van de invoer van die aanroep dat de provider uit zijn promptcache las een modelaanroep las een deel van zijn invoer uit de cache (promptcaching)
cache_write_tokens input_tokens: het deel van de invoer van die aanroep dat de provider in zijn promptcache schreef een modelaanroep sloeg een deel van zijn invoer op in de cache; van de providers die Core aanroept, melden alleen Claude-modellen dit
embedding_tokens input_tokens er tekst werd ingebed: inlezen, zoeken, geheugen schrijven, de skills of het geheugen van een beurt rangschikken
tool_invocation quantity, met tool_name een tool die Core uitvoerde
retrieval quantity elke zoekstap die een zoekrun uitvoerde
crawl_pages quantity: gecrawlde pagina's een website-connector synchroniseerde
parse_pages quantity pagina's die een documentparseerdienst las voor een inleespipeline
image_generation quantity: 1, met model en tool_name de tool generate_image leverde een afbeelding
audio_transcription quantity: de seconden audio, naar boven afgerond, met model; tool_name als de transcriptietool haar maakte een opname werd getranscribeerd: op POST /audio/transcriptions, door de transcriptietool of voor een input_audio-deel (Audio transcriberen). De prijs noemt één minuut, dus de kosten zijn de seconden maal die prijs, gedeeld door zestig
sandbox_seconds quantity: de seconden dat een computer klaarstond, naar boven afgerond een computer stopte
shared_bytes quantity: de bytes van het verstuurde bestand een deellink werd geopend, één keer per keer dat hij wordt geopend; een weergaveadres openen schrijft geen rij
thread_turn quantity: 1 een beurt die een thread las of schreef, wat hem ook startte
run quantity: 1 een achtergrondrun draaide zijn eerste ronde
agent_turn quantity: 1 een beurt draaide een agent, ook een agent die als tool werd aangeroepen
pseudonymised_turn quantity: 1 een beurt van een sleutel die persoonsgegevens verbergt
compaction_run quantity: 1 een compactieronde vroeg om een samenvatting, één keer per ronde hoeveel het er ook werden
schedule_fire quantity: 1 een planning ging af en zette zijn beurt of runs klaar
task_start quantity: 1 er werd een taak gestart
workflow_run quantity: 1 er werd een workflowrun gestart; wat de stappen laten lopen, wordt gemeten zoals altijd
evaluation_scenario quantity: 1 een evaluatierun begon aan een scenario
improvement_analysis quantity: 1 een verbeteranalyse begon; haar modelaanroepen zijn regels model_tokens zonder sleutel
datastore_write quantity: 1 er werd een datastore-record geschreven
memory_write quantity: 1 er werd een geheugenrecord opgeslagen
file_upload quantity: 1 er werd een bestand geüpload; nooit de bytes

Eén handeling telt op elke meter die ze raakt, elk één keer: een geplande beurt op een thread is een schedule_fire, een run en een thread_turn. Je operator prijst elk gebruik; zonder prijs kost het niets.

Wat je opslaat is geen rij hiervan: dat is een meter, stored_bytes, op GET /usage/summary zelf (hieronder) — gelezen uit je bestanden en artefacten op dit moment, niet opgeteld via een gebeurtenis.

Houd bij het lezen van verbruik rekening met het volgende:

  • Een hybride zoekopdracht registreert twee zoekeenheden, één per zoekstap. De verbruiksregistraties vermelden de verantwoordelijke stap.
  • Bij een sleutel staat het sleutel-id in key_id en actor. Consoleactiviteiten hebben een lege key_id en vermelden de persoon in actor.
  • Een rij die een beurt op een agent schreef, noemt die agent in agent. Een agent die als tool wordt aangeroepen, noemt zichzelf op de rijen van zijn eigen beurt, en de rijen van de aanroepende beurt, de aanroep van de tool inbegrepen, noemen de aanroeper. De rijen van een tool noemen de agent wiens beurt hem aanriep. Een beurt zonder agent, en elke rij van voordat rijen de agent noemden, hebben null. GET /usage?agent=<naam> toont de rijen van één agent, en de samenvatting splitst elke groep erop.
  • Een rij waarvoor een helper het werk deed, noemt die in helper: de naam die een beurt op POST /responses in helper meegaf, op elke rij die die beurt schreef, die van haar tools en de beurten van agents die ze aanriep inbegrepen; of assist.<helper> voor een helper van Core zelf, zoals assist.json_schema. Werk dat geen helper deed, en elke rij van voordat rijen de helper noemden, hebben null. GET /usage?helper=<naam> toont de rijen van één helper op precies die naam, en de samenvatting splitst elke groep erop.
  • Een aanroep die een subject noemt, wordt onder dat id gemeten: subject_id op de rij, GET /usage?subject=<id> voor de rijen van één persoon, GET /usage/by-subject voor de totalen van iedereen tegelijk. Core bewaart geen naam, e-mailadres of attribuut bij het id -- alleen wat je applicatie ervoor meestuurde (Subjects).

Verbruik opvragen

curl -s "$CORE_URL/usage?from=2026-09-01T00:00:00Z&to=2026-10-01T00:00:00Z&kind=model_tokens" \
    -H "Authorization: Bearer $CORE_KEY"
Aanroep Antwoordt Neemt
GET /usage losse rijen, elk met wat die kostte, met cursor gepagineerd kind, key_id, agent, helper, subject, request_id, response_id, from, to
GET /usage/summary één rij per groep (kind, model, tool_name, agent, helper), met wat die kostte, zonder paginering; dit is het totaal van je organisatie, over de huidige UTC-kalendermaand tenzij je from of to noemt key_id, request_id, response_id, thread_id, from, to, interval=day
GET /usage/by-subject één rij per persoon waar je verbruik een subject_id voor draagt, met wat elk kostte plus diens eigen threads_created/messages_appended, gesorteerd op kosten aflopend, afgekapt op limit (standaard 50, maximaal 500); subjects zegt hoeveel het er echt waren key_id, from, to, limit, by_kind; geweigerd aan een subjecttoken
GET /usage/caps de limieten die deze maand gelden en wat daartegen is verbruikt niets; zie je maandlimiet
GET /tenants/{id}/prices de prijzen waartegen je verbruik wordt berekend, elk in de valuta die zijn currency noemt, met cursor gepagineerd kind, model, tool_name; een console-aanroep, niet die van een sleutel

GET /usage/by-subject toont alleen mensen met een beprijsde aanroep binnen het venster: iemand die alleen een thread aanmaakte of een bericht kreeg toegevoegd, zonder beprijsde aanroep in het venster, staat niet in deze lijst. De eigen threads_created/messages_appended van de samenvatting tellen die persoon wel mee — die twee totalen worden rechtstreeks over je threads en hun items gelezen, nooit uit deze lijst per persoon.

Wat elke persoon verbruikte, per soort. Voeg by_kind=true toe en elke rij, unattributed ook, draagt by_kind: één regel per soort verbruik waarvan de persoon rijen had, gesorteerd op soort, elk met input_tokens, output_tokens, quantity (afbeeldingen, aanroepen, pagina's, seconden), cost_eur en unpriced, die samen de cijfers van de rij zelf vormen. Zo toon je de embedding-tokens of het aantal afbeeldingen van één persoon apart. Zonder de parameter is by_kind null. Core kent geen limiet per persoon: een platform dat zijn gebruikers aan redelijk gebruik houdt, leest deze lijst en de verbruiksgebeurtenissen op zijn stroom, en grijpt zelf in.

curl -s "$CORE_URL/usage/by-subject?by_kind=true" -H "Authorization: Bearer $CORE_KEY"

Gebruik ISO-tijdstippen met tijdzone voor from en to. Ze filteren op created_at, inclusief from en exclusief to. Gebruik het samenvattingsendpoint voor organisatietotalen zonder alle afzonderlijke verbruiksrecords op te halen. Zonder from en zonder to beslaan de samenvatting en GET /usage/by-subject de huidige UTC-kalendermaand; noem een van beide om een ander venster te lezen. Beperkt tot een request_id is de samenvatting wat die ene aanroep kostte, inclusief een agent die hij als tool aanriep; een geneste agentbeurt heeft een eigen response_id, dus een hele aanroep is request_id.

Beperkt tot een thread_id is de samenvatting wat één gesprek kostte: de rijen van elk antwoord dat in die thread liep, zodat een chat zijn eigen verbruik kan tonen. Er horen enkele beperkingen bij. De samenvatting wordt gelezen uit de eigen verbruiksrijen van je organisatie, zoals een lezing per persoon. Een thread die je verwijderde geeft geen groepen, omdat zijn antwoorden hem vergeten (de kosten zitten zonder filter nog in je totalen). Een geneste agentbeurt die buiten de thread liep zit er niet bij; vraag om zijn request_id als dat wel moet. De opgeslagen bytes en de tellingen van threads en berichten naast de groepen worden niet tot de thread beperkt. Een subject-token leest alleen de rijen van haar eigen persoon binnen de thread: de thread_id van een ander geeft geen groepen, nooit het verbruik van die persoon.

Wat je verbruik kostte

Elke groep in GET /usage/summary draagt naast de aantallen een cost_eur, en de samenvatting als geheel draagt het totaal. Bedragen zijn in euro en komen als exacte decimale strings — nooit als floats — dus tel ze op met een decimaal type en rond pas af waar je ze toont. Een bedrag staat altijd voluit in cijfers, zoals 0.0000001, en nooit met een exponent.

Ook elke rij in GET /usage draagt een cost_eur: wat die ene rij kostte, tegen de eigen prijs van je organisatie die gold toen de rij werd vastgelegd, precies zo berekend als de samenvatting de groep berekent waar de rij in valt. Het is null waar geen prijs de rij dekt: de rij die de samenvatting in unpriced telt.

De samenvatting draagt ook stored_bytes: wat je bestanden en artefacten op dit moment bevatten, opgeteld uit hun blobs op het ogenblik dat de samenvatting werd opgebouwd — geen totaal over het venster dat from/to afbakenen, die hier niet op van toepassing zijn.

Naast de kosten draagt de samenvatting threads_created en messages_appended: hoeveel gesprekken en hoeveel berichten binnen het venster vielen, rechtstreeks geteld over je threads en hun items, nooit beprijsd of als verbruiksrij bewaard. Een "bericht" is een item van het type message — van welke kant ook — nooit een toolaanroep, het resultaat ervan, een redeneerblok of een weigering: dat is hoe een beurt werkte, niet wat er gezegd werd. Beide filteren op key_id, op dezelfde manier als items.

{
  "items": [
    { "kind": "model_tokens", "model": "gpt-5.6-sol", "input_tokens": 1200000,
      "output_tokens": 90000, "reasoning_tokens": 30000, "quantity": 0, "cost_eur": "3.90",
      "unpriced": 0 },
    { "kind": "cached_tokens", "model": "gpt-5.6-sol", "input_tokens": 400000,
      "output_tokens": 0, "reasoning_tokens": 0, "quantity": 0, "cost_eur": "-0.90", "unpriced": 0 },
    { "kind": "model_tokens", "model": "claude-sonnet-5", "input_tokens": 800000,
      "output_tokens": 40000, "reasoning_tokens": 0, "quantity": 0, "cost_eur": "3.00",
      "unpriced": 0 },
    { "kind": "cache_write_tokens", "model": "claude-sonnet-5", "input_tokens": 200000,
      "output_tokens": 0, "reasoning_tokens": 0, "quantity": 0, "cost_eur": "0.15", "unpriced": 0 }
  ],
  "cost_eur": "6.15",
  "stored_bytes": 41943040,
  "threads_created": 214,
  "messages_appended": 1780
}

Drie dingen zijn daarbij goed om te weten:

  • Een groep cached_tokens is een korting, geen kostenpost. De groep model_tokens bracht de hele invoer al tegen het volle tarief in rekening; de cachegroep draagt het verschil dat het goedkopere cachetarief waard is, en dat is nul of negatief. Tel de groepen op en het totaal is wat de periode werkelijk kostte.
  • Een groep cache_write_tokens is een toeslag. Invoer in de cache van een provider schrijven kost meer dan die invoer één keer versturen, en de groep model_tokens rekende die tokens tegen het gewone invoertarief. De cache-schrijfgroep draagt wat het cache-schrijftarief van het model daar bovenop doet, en dat is nul of positief: nul als de prijs geen cache-schrijftarief noemt. Het totaal telt nog steeds op tot wat de periode kostte. Een cache-item dat geen latere aanroep teruglas, zie je hier als kosten zonder korting in cached_tokens ernaast.
  • unpriced telt de rijen waarvoor geen prijs bestond. Die kosten nul, dus een groep met een unpriced boven nul is een ondergrens en niet het hele bedrag. Vraag je operator om het onderwerp te beprijzen; verbruik dat al is vastgelegd wordt opnieuw berekend zodra de prijs bestaat, want kosten worden bij het lezen bepaald en nooit op de registratie bewaard.

Prijzen gelden per model, per tool en per eenheid, en elke prijs geldt vanaf een tijdstip — een prijswijziging binnen je venster splitst de kosten dus in plaats van alles opnieuw te beprijzen. Je organisatie betaalt de prijs van de omgeving of een eigen afwijkende prijs; GET /models laat zien welke van de twee (een model kiezen).

Elk bedrag hier is in euro. Een prijs in een andere valuta wordt omgerekend met de referentiekoers van de Europese Centrale Bank: in een maand die je operator heeft afgesloten met de koers die bij het afsluiten werd vastgelegd, in elke andere maand met de nieuwste koers. De kosten van een open maand veranderen dus wanneer er een nieuwe koers is, en die van een afgesloten maand nooit meer. Heeft Core voor een valuta geen koers, dan telt een rij tegen zo'n prijs als unpriced (Een prijs in een andere valuta).

Een reeks per dag

Geef interval=day mee, samen met from en to, en de samenvatting draagt ook series: één UsageDailyTotal per UTC-kalenderdag in dat venster, met cost_eur, unpriced, threads_created, messages_appended en by_kind — de kosten van die dag per soort verbruik, één {kind, cost_eur, unpriced} per soort met regels, op soort gesorteerd en samen de cost_eur van die dag. Een dag zonder verbruik is een rij op nul zonder soorten, nooit een gat — zo teken je meteen een lijn- of gestapelde staafgrafiek. De reeks telt op tot hetzelfde totaal als cost_eur van de samenvatting zelf. from en to zijn dan verplicht samen — "elke dag die er ooit geweest is" is geen reeks — en het venster is begrensd op 366 UTC-dagen; buiten die grenzen antwoordt Core 422 op het veld to. Zonder interval is series null, de kleinere draad die elke bestaande aanroeper al leest.

curl -s "$CORE_URL/usage/summary?interval=day&from=2026-09-01T00:00:00Z&to=2026-10-01T00:00:00Z" \
    -H "Authorization: Bearer $CORE_KEY"
{
  "items": [ ... ],
  "cost_eur": "6.15",
  "stored_bytes": 41943040,
  "threads_created": 214,
  "messages_appended": 1780,
  "series": [
    { "day": "2026-09-01", "cost_eur": "0.12", "unpriced": 0, "threads_created": 9, "messages_appended": 62,
      "by_kind": [ { "kind": "embedding_tokens", "cost_eur": "0.02", "unpriced": 0 },
                   { "kind": "model_tokens", "cost_eur": "0.10", "unpriced": 0 } ] },
    { "day": "2026-09-02", "cost_eur": "0", "unpriced": 0, "threads_created": 0, "messages_appended": 0,
      "by_kind": [] }
  ]
}

Je maandlimiet

Je organisatie, en elke sleutel ervan, kan een maandlimiet in euro krijgen, geteld per kalendermaand in UTC vanaf de eerste van de maand om 00:00:00Z. Een beheerder van de organisatie boven de jouwe stelt de limiet van je organisatie in, of Artific als er niets boven de jouwe hangt. De limiet van een sleutel stellen de beheerders van je organisatie in, of een andere sleutel met management, nooit de sleutel zelf. Die andere sleutel kan er een zijn die de begrensde sleutel zonder limiet registreerde, dus het harde plafond boven een sleutel met management is de limiet van je organisatie. Een limiet van 0 betekent niets meer dat geld kost tot de maand omslaat.

Een limiet houdt tegen wat geld kost, en wat geld kan kosten. Zodra het verbruik de limiet heeft bereikt, wordt een aanroep op een model met een prijs boven nul geweigerd, en ook een aanroep op een model waar helemaal geen prijs voor bestaat: wat die kost is onbekend, en onbekend is niet gratis. Een aanroep op een model met prijs nul wordt nog steeds beantwoord, bij een limiet van 0 en bij elke andere, en een tool zonder prijs blijft gratis.

De limiet telt geld over alles wat een prijs heeft: tokens, gegenereerde afbeeldingen, toolaanroepen, retrieval, parsen, crawlen, computertijd en de bytes die een deellink verstuurde — je beurten, je achtergrondruns, je evaluaties en het werk dat consolegebruikers starten. Wat je opslaat hoort daar niet bij — stored_bytes is een meter, geen beprijsde verbruiksregel — dus dat telt nooit mee tegen deze limiet. Er is geen limiet in tokens: een token is op elk model een ander bedrag waard, en een budget is waar je echt op kunt plannen. Een registratie waarvoor geen prijs bestaat, kost nul tegen de limiet — daarom vertelt het antwoord hieronder ook hoeveel zulke registraties de periode bevat.

curl -s "$CORE_URL/usage/caps" -H "Authorization: Bearer $CORE_KEY"
{
  "period_start": "2026-09-01T00:00:00Z",
  "period_end": "2026-10-01T00:00:00Z",
  "unpriced": 0,
  "tenant": { "cost_cap_eur": "250.00", "cost_cap_until": null, "cost_eur": "241.07" },
  "tenant_cost_cap_counts": "branch",
  "tenant_branch_cost_eur": "248.90",
  "keys": [
    { "key_id": "key_01H...", "cost_cap_eur": null, "cost_cap_until": null, "cost_eur": "12.40" }
  ]
}

tenant is de limiet van je organisatie en wat die heeft verbruikt; keys bevat je eigen sleutel en geen andere. Een cost_cap_eur van null betekent geen limiet. cost_cap_until is gevuld als de limiet alleen voor deze maand geldt, en null voor een limiet die van maand tot maand blijft staan. GET /key toont dezelfde gegevens voor je sleutel apart.

Een limiet voor alleen deze maand. Wie een limiet mag instellen, kan die met de maand laten aflopen door monthly_cost_cap_until mee te sturen: de limiet vervalt dan vanzelf aan het begin van de volgende maand, en niemand hoeft hem terug te zetten. De enige waarde die wordt aangenomen is het einde van de huidige maand, de eerste van volgende maand om 00:00:00Z (hetzelfde moment als period_end hierboven); elke andere geeft 422 met het veld erbij, net als een einde zonder limiet om te beëindigen. Een platform dat een van zijn organisaties bij detectie stopzet voor de rest van de maand, stuurt:

curl -s -X PATCH "$CORE_URL/organisations/$ORGANISATION_ID" \
  -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
  -d '{"monthly_cost_cap_eur": "0", "monthly_cost_cap_until": "2026-11-01T00:00:00Z"}'

Hetzelfde veld werkt op een sleutel, bij POST en PATCH van de sleutel, en op de sleutel van een serviceaccount bij het aanmaken van het account. Pas je alleen het bedrag aan, zonder het veld, dan blijft een limiet voor alleen deze maand zo; null sturen laat de limiet blijven staan, en de limiet opheffen wist ook het einde. Zodra de maand om is, telt de limiet nergens meer -- hij houdt niets tegen en niemand krijgt er nog mail over -- terwijl de organisatie of sleutel hem met zijn einde blijft tonen tot iemand hem opnieuw schrijft. Een organisatie kan haar eigen limiet niet laten aflopen, net zoals ze hem niet kan opheffen: haar eigen beheerders krijgen 403.

De limiet van een organisatie telt de organisaties eronder mee, tenzij anders is gekozen. tenant_cost_cap_counts zegt welke van de twee geldt: bij branch wordt de limiet gewogen tegen wat je organisatie en elke organisatie eronder heeft verbruikt, en tenant_branch_cost_eur is dat bedrag, met wat een verwijderde organisatie eronder deze maand verbruikte zolang de limiet dat blijft tellen; bij own alleen tegen tenant.cost_eur, en is tenant_branch_cost_eur null, net als waar geen limiet is ingesteld en voor een sleutel zonder de capability management. Een organisatie die onder een andere bovenliggende organisatie wordt geplaatst, neemt mee wat ze deze maand heeft verbruikt: vanaf de verplaatsing telt dat voor de limiet van de nieuwe bovenliggende organisatie en niet meer voor die van de oude. Een limiet boven je geldt ook voor jou: heeft een organisatie boven de jouwe haar limiet bereikt, dan worden ook jouw aanroepen die geld kosten geweigerd, wat je eigen limiet ook zegt. Dit antwoord toont de limieten boven je niet.

Als een limiet is bereikt, antwoorden POST /responses en POST /responses/{id}/tool_outputs met 429, een Retry-After-header met het aantal seconden tot de maand omslaat, en een detail dat vertelt welke limiet je tegenhield — die van je sleutel, die van je organisatie of die van een organisatie boven de jouwe. Ze worden in die volgorde gewogen: eerst die van je sleutel, dan die van je organisatie, dan die erboven. Er wordt niets weggeschreven: geen response, geen gesprek, geen run in de wachtrij. Een achtergrondrun die tussen twee rondes een limiet bereikt, eindigt failed met de code usage_cap_exceeded en behoudt wat al gedaan was.

Een beurt kan een limiet bereiken terwijl hij loopt. Core weegt de limieten opnieuw voor elke modelaanroep en voor elke toolaanroep die een prijs heeft, en daar stopt de beurt: de response eindigt incomplete met incomplete_details.reason: "usage_cap_exceeded", een stream sluit met response.incomplete, en POST /messages antwoordt met stop_reason: "pause_turn". Wat de beurt tot dan toe heeft opgeleverd staat in de response en wordt in rekening gebracht. De regel achter de twee eindes: geweigerd voordat er iets was opgeleverd, eindigt de ronde van een achtergrondrun de run failed met de code usage_cap_exceeded; gestopt nadat er iets was opgeleverd, eindigt een beurt of een run incomplete met de reden usage_cap_exceeded. Een taak waarvan de run door een limiet is gestopt, mislukt in beide gevallen met usage_cap_exceeded. Een tool die geld kost wordt niet uitgevoerd en zijn resultaat bevat de zin van de limiet; een tool die niets kost loopt gewoon.

Dezelfde 429 krijg je op een zoekopdracht die je vraag embedt met een embeddingmodel dat geld kost -- POST /knowledge/indexes/{id}/search, POST /memory/stores/{id}/search en POST /knowledge/retrieval-tools/{id}/query -- en op POST /tools/{name}/call voor een tool die geld zou kosten. Een zoekopdracht waarvan alle embeddingmodellen niets kosten, krijgt gewoon antwoord, maar de embedding-tokens worden wel geteld. Het MCP-endpoint van een toolset heeft geen status om te geven; daar staat de zin van de limiet in het resultaat van de tool.

Een limiet wordt gewogen tegen wat er is uitgegeven, niet tegen wat een aanroep gaat uitgeven. Eén beurt gaat dus hooguit over zijn limiet heen met de stap die hem passeerde, en beurten die op hetzelfde moment lopen kunnen er samen overheen gaan met wat ze onderweg hebben: elke beurt ziet zijn eigen verbruik en wat al in rekening was gebracht toen hij begon, niet wat de andere op dat moment uitgeven. Zie een limiet als een plafond met die marge, niet als een exacte afrekening.

Auditgebeurtenissen

curl -s "$CORE_URL/audit/events?request_id=req_5Tn8..." -H "Authorization: Bearer $CORE_KEY"

GET /audit/events geeft alleen de gebeurtenissen die je eigen sleutel heeft veroorzaakt: wat de aanroepen van die sleutel deden, en wat de achtergrondverwerking van Core op verzoek van die sleutel deed, zoals een geplande run of het wissen van een persoon. Gebeurtenissen van andere sleutels, en wat mensen in de console deden, staan er niet in. Elke gebeurtenis bevat het request_id van de oorspronkelijke aanroep.

Veld Bevat
event wat er gebeurde: response.created, tool.executed, policy.decision, prompt.rendered, skill.loaded, file.created, artifact.produced, memory.written, ...
actor het id van je sleutel; worker als de achtergrondverwerking van Core iets deed waar je sleutel om vroeg; of subscription:<id> als een abonnement dat je sleutel afsloot zijn kopieën synchroniseerde
key_id het id van je sleutel
request_id, response_id waar het bij hoorde
axis, decision, reason bij een policy.decision: welke as, allowed of denied, en waarom
refs id's, namen, versies en aantallen
origin core voor wat Core vastlegde, product voor wat een product dat op Core is gebouwd leverde (hieronder)
product, product_name bij een gebeurtenis van een product: de naamruimte en de naam ervan bij levering; leeg bij die van Core zelf

Filter auditgebeurtenissen met event, request_id, response_id, subject (de rijen van één persoon, op het id waarmee je applicatie die persoon noemde), origin (core of product) en product (de gebeurtenissen van één product, op zijn naamruimte).

Het volledige auditspoor van de organisatie lees je op twee plekken. Een sleutel met management leest het op GET /organisations/{je eigen id}/audit/events, met dezelfde filters en velden (daar noemt key_id de sleutel achter elke gebeurtenis, en is het leeg als een persoon of Core zelf iets deed), en exporteert het op .../audit/events/export (Organisaties beheren via de API); dat is de route voor een backend, die geen console heeft. Die route antwoordt 403 als de organisatie boven je het auditspoor heeft voorbehouden. Een beheerder leest hetzelfde spoor in de console.

Een export is JSON Lines, één gebeurtenis per regel, de oudste eerst. Breekt een download af, vraag dan opnieuw met after op de id van de laatste volledige regel die je ontving: alleen de gebeurtenissen daarna komen mee, zodat de twee bestanden samen de hele export zijn.

Beleidscontroles registreren zowel toegestane als geweigerde beslissingen. Gebruik deze gebeurtenissen om geblokkeerde pogingen en afgeronde bewerkingen te onderzoeken.

Het veld refs bevat id’s, toolnamen, model-id’s en aantallen. Het bevat geen bestandsnamen, berichten of inhoud van aanroepers. Gespreksinhoud wordt apart opgeslagen.

De eigen gebeurtenissen van je product leveren

Bouw je een product op Core, dan gaat een deel van wat erin gebeurt nooit langs Core: een rol die in je product werd toegekend, een export die iemand downloadde, een doelgroep die je wijzigde. Lever die gebeurtenissen aan het auditspoor van de organisatie en een beheerder leest ze naast die van Core zelf, op dezelfde routes, even lang bewaard en op dezelfde manier te exporteren.

Twee dingen gaan voor. Je operator geeft je product een naam op de organisatie, of op een organisatie erboven: een naamruimte zoals acme en een weergavenaam zoals Acme Workspace, de velden Naamruimte en Weergavenaam bij de gegevens van de organisatie in de console. Alleen een operator kan dat, en elke gebeurtenis die je sleutels leveren begint daarna met die naamruimte. En de sleutel die levert heeft de capability product_events (Capabilities).

curl -s -X POST "$CORE_URL/audit/events" -H "Authorization: Bearer $CORE_KEY" \
  -H "Content-Type: application/json" -d '{
  "events": [{
    "id": "evt_01J9",
    "event": "acme.role.assigned",
    "occurred_at": "2026-10-22T09:30:00Z",
    "subject": "anna",
    "actor": "mem_7",
    "about": {"kind": "role", "id": "rol_42"},
    "request_id": "req_5Tn8...",
    "changes": {"role": {"from": "viewer", "to": "editor"}}
  }]
}'
Veld Bevat
id je eigen id voor de gebeurtenis; lever je hem opnieuw, dan houdt Core de eerste
event je naamruimte en nog minstens twee delen: acme.role.assigned
occurred_at wanneer het gebeurde, met tijdzone; hoogstens vijf minuten voor op de klok van Core en binnen de auditbewaartermijn van de organisatie
about waar het over ging, als soort en jouw id ervoor; geen namen of tekst
subject optioneel: de persoon voor wie het gebeurde, met het id dat je applicatie bij elke andere aanroep gebruikt
actor optioneel: je eigen id voor wie handelde; getoond als acme:mem_7
request_id optioneel: de X-Request-Id van de aanroep waar het bij hoort, zodat één zoekvraag beide vindt; req_ en 26 hoofdletter-ULID-tekens
changes optioneel: de velden die veranderden, hoogstens 32, elk een korte waarde, een korte lijst of {from, to}, samen 2 KiB

Stuur één tot honderd gebeurtenissen tegelijk. Core controleert ze allemaal voordat het er één vastlegt: één gebeurtenis buiten je naamruimte, te ver in de toekomst of te oud, een id dat twee keer in de levering staat, en niets van die levering wordt bewaard, met een 422 die elk veld noemt. Het antwoord geeft één item per gebeurtenis in de volgorde waarin je ze stuurde, {id, audit_event_id, created}. Lever minstens één keer vanuit je eigen outbox: een id dat Core al heeft antwoordt created: false en houdt de eerste rij, ook als de tweede levering iets anders zegt.

changes mag geen geheim, geen inhoud en geen e-mailadres bevatten. Core weigert de hele levering met een 422 als een sleutel password, passwd, secret, token, credential, api_key, email, mail, content, body, text, message of prompt ergens in zich draagt, dus ook context en email_verified worden geweigerd, en als een waarde op een e-mailadres lijkt. Het noemt in zijn antwoord alleen het veld. Het kan niet alles zien, dus de belofte blijft de jouwe. Lever alleen wat Core niet zelf vastlegt: nooit de aanroepen die je product doet, want die staan al in het spoor.

Je sleutel leest haar eigen leveringen op GET /audit/events?origin=product. Een organisatie zonder productnaam antwoordt 409. Dat doet ook een levering waarvan het eerdere exemplaar werd verwijderd terwijl Core vastlegde: lever opnieuw. Een sleutel zonder de capability krijgt 404, en het subjecttoken van een persoon 403.

Een verzoek terugvinden

Gebruik de antwoordheader X-Request-Id om verbruiks- en auditgegevens van een aanroep te vinden:

curl -s "$CORE_URL/audit/events?request_id=req_5Tn8..." -H "Authorization: Bearer $CORE_KEY"
curl -s "$CORE_URL/usage?request_id=req_5Tn8..." -H "Authorization: Bearer $CORE_KEY"

Bewaar het id bij de verzoeklogs van je applicatie zodat je activiteit en verbruik later kunt terugzoeken.

Verbruik na verwijdering

Bij het verwijderen van een gesprek of bestand blijven de verbruiks- en aanroepauditgegevens bewaard. Verwijdering van de organisatie wist die gegevens. De afzonderlijke beheerauditgeschiedenis blijft bestaan.

Verbruik in de console bekijken

Beheerders kunnen deze gegevens bekijken in de onderdelen Gebruik en Audit, met de beschikbare periode- en sleutelfilters.

Elke rij van een samenvatting draagt tenant_id, de organisatie waar het totaal bij hoort. De beheerdersvariant van deze route neemt daarnaast include_children=true: dan telt ze de organisatie én alles wat eronder hangt in één antwoord op, uit elkaar te halen op datzelfde tenant_id (interval=day samen met include_children antwoordt 422: een reeks per dag over een hele boomstructuur is er nog niet). Zonder management leest je sleutel altijd alleen haar eigen organisatie via deze routes; met management leest ze het verbruik en het spoor van een organisatie eronder op dezelfde manier via /organisations/{id}/... (Organisaties beheren via de API).

Wat je betaalt voor één organisatie onder de jouwe. GET /organisations/{id}/usage/summary van een organisatie onder die van je sleutel draagt paid_eur naast cost_eur, op elk totaal en op de samenvatting: cost_eur is wat die organisatie in rekening wordt gebracht, paid_eur hetzelfde verbruik tegen de prijzen van je eigen organisatie, wat jij ervoor betaalt. Lees het organisatie voor organisatie voor je kosten per klant, zonder de hele tak in één keer op te halen. paid_eur is null op je eigen organisatie, met interval=day, en op de beheerdersroute /tenants/{id}/usage/summary.