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_idenactor. Consoleactiviteiten hebben een legekey_iden vermelden de persoon inactor. - 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, hebbennull.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 opPOST /responsesinhelpermeegaf, op elke rij die die beurt schreef, die van haar tools en de beurten van agents die ze aanriep inbegrepen; ofassist.<helper>voor een helper van Core zelf, zoalsassist.json_schema. Werk dat geen helper deed, en elke rij van voordat rijen de helper noemden, hebbennull.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_idop de rij,GET /usage?subject=<id>voor de rijen van één persoon,GET /usage/by-subjectvoor 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_tokensis een korting, geen kostenpost. De groepmodel_tokensbracht 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_tokensis een toeslag. Invoer in de cache van een provider schrijven kost meer dan die invoer één keer versturen, en de groepmodel_tokensrekende 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 incached_tokensernaast. unpricedtelt de rijen waarvoor geen prijs bestond. Die kosten nul, dus een groep met eenunpricedboven 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.