Fouten, paginering en herhalen¶
Core gebruikt in de hele API hetzelfde foutformaat en paginering met cursors. Met request-id's kun je problemen terugzoeken. Met een idempotentiesleutel kun je bij een herhaling een afgeronde aanroep terugvinden.
Het verzoekformaat is dat van OpenAI¶
De body van POST /responses is die van OpenAI's Responses-API. Een client die je vandaag naar
OpenAI stuurt, stuur je ongewijzigd naar Core: je verandert het adres in je
basis-URL en de sleutel in je secret, en verder niets aan wat je verstuurt.
Core neemt in die body ook een paar optionele eigen velden aan, zoals agent, timezone,
tool_search, tool_variables en hosting. Verzoekvelden
noemt ze; een verzoek dat ze weglaat, gedraagt zich zoals bij OpenAI. POST /messages neemt op
dezelfde manier de body van Anthropic met de eigen velden van Core
(Een codeeragent aansluiten).
Wat Core daarbovenop biedt, reist in headers. De belangrijkste is X-Core-Subject, de persoon voor
wie een beurt is: zet die één keer op je client en elk verzoek draagt hem.
client = OpenAI(base_url=CORE_URL, api_key=CORE_KEY, default_headers={"X-Core-Subject": subject_json})
Dat het een header is en geen veld in de body of in de query, is opzet: attributen zijn het deel van
een verzoek dat geen enkele proxy onderweg in een logregel mag zetten. Zie Bouwen voor
personen voor wat je erin zet, en user als je alleen het id kwijt wilt.
| Header | Verstuurd door | Wat hij draagt |
|---|---|---|
X-Core-Subject |
jou | de persoon voor wie een verzoek is, met haar attributen |
Idempotency-Key |
jou | jouw naam voor één poging, zodat een herhaling één keer wordt beantwoord (Idempotentiesleutels) |
If-Match |
jou | de versie die je las, bij een schrijfactie die een policy vervangt (een PATCH /keys/{id}, een PUT of DELETE van de policy van een organisatie) of het werkgeheugen van een gesprek; een opgeslagen versie die sindsdien veranderde, is 409 met reason_code: "stale_version" |
X-Core-Thread-Id |
jou en Core | op /messages, het gesprek waar een opgeslagen beurt bij hoort (Een gesprek voortzetten op /messages) |
X-Core-Previous-Response-Id |
jou en Core | op /messages, het antwoord dat deze beurt voortzet |
X-Core-Check |
Core | bij een beurt die een live check tegenhield, welke check en waarom, zoals stage=input, check="geen-wachtwoorden", code=input_check_failed (Wat je applicatie ontvangt) |
X-Core-Response-Id |
Core | bij een mislukte beurt op /messages, het id van het antwoord dat hij achterliet, voor GET /responses/{id} |
X-Request-Id |
Core | het id van dit verzoek (hieronder) |
Een tweede soort bearer. Naast je sleutel (ack_...) neemt Core in Authorization ook een
subjecttoken (ast_...) aan: je sleutel beperkt tot één persoon voor hoogstens een uur, die je
backend aanvraagt en doorgeeft aan een browser of apparaat dat de sleutel nooit mag hebben
(Een token voor de browser).
De routes waarmee je beheert -- sleutels, prompts, skills, kennis -- volgen de afspraken van Core
zelf: lijsten met een cursor, 204 bij verwijderen, 201 met Location bij opslaan. Die staan
hieronder.
Request-id’s¶
Core voegt X-Request-Id: req_... toe aan antwoorden, ook bij fouten. Core maakt dit id zelf aan en
neemt geen door de aanroeper gekozen waarde over. Bewaar het in je logs en vermeld het bij
probleemmeldingen. Hetzelfde id staat in het foutantwoord en de bijbehorende registraties in Core.
Fouten die ontstaan voordat het verzoek Core bereikt, kunnen een request-id missen.
Foutformaat¶
HTTP-fouten gebruiken het formaat application/problem+json, op elke route behalve de vijf
modelroutes die hieronder staan:
{
"type": "about:blank",
"title": "Not Found",
"status": 404,
"detail": "The prompt was not found.",
"request_id": "req_5Tn8..."
}
type zegt welke soort fout dit is. Publiceert je omgeving deze handleiding, dan is het het adres
van die soort in de foutcatalogus, zoals
https://docs.example.nl/en/reference/errors/#not-found; anders is het about:blank. De
catalogus somt elke soort op, met wat je eraan doet.
Validatiefouten (422) bevatten ook een lijst errors:
{
"status": 422,
"errors": [{ "field": "tools.0.type", "message": "This tool type is not available for this key.", "type": "value_error" }]
}
Elke vermelding wijst een afgekeurd veld aan. Begint field met body., dan kon Core het verzoek
niet verwerken, bijvoorbeeld door een ontbrekend veld of een verkeerd type. Een veld zonder dit
voorvoegsel, zoals collection_ids of config.nodes[2].type, betekent dat het verzoek leesbaar was
maar Core de waarde heeft afgekeurd.
De modelroutes antwoorden met de fout van de leverancier¶
POST /responses, GET /responses/{id}, POST /responses/{id}/tool_outputs,
POST /responses/{id}/cancel en POST /messages geven fouten in de vorm die de clientbibliotheek
leest van de API waarmee ze compatibel zijn. Een SDK van OpenAI of Anthropic die je op Core richt,
werpt dus dezelfde uitzondering als bij de leverancier zelf, met jouw foutmelding en het
betrokken veld erin.
De vier /responses-routes antwoorden met het foutobject van OpenAI:
{
"error": {
"message": "The agent fixes this field; send no value of your own, or the same one.",
"type": "invalid_request_error",
"param": "temperature",
"code": "invalid_request"
}
}
param noemt het veld waar de weigering over gaat, zonder het voorvoegsel body. dat de lijst
errors van Core zelf gebruikt. code is de eigen code van Core voor die weigering, bijvoorbeeld
invalid_request, policy_denied of usage_cap_exceeded.
POST /messages antwoordt met het foutobject van Anthropic. Dat heeft geen veld voor een
parameter, dus de naam van het veld staat vooraan in de melding:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "temperature: The agent fixes this field; send no value of your own, or the same one."
},
"request_id": "req_5Tn8..."
}
Deze vijf routes antwoorden nooit 422. Een verzoek dat ze weigeren -- een veld dat ze niet
kunnen inwilligen, een veld dat ontbreekt, een waarde die het veld niet toelaat -- is 400, de
status waarmee beide leveranciers een body afkeuren. Elke andere route van Core houdt
422 met de lijst errors. Welke vorm je leest, volgt dus uit de route die je aanriep en niet uit
wat er misging.
De statussen zelf staan in de tabel hieronder, en WWW-Authenticate en Retry-After gaan op
dezelfde manier mee. Een ontbrekende of ongeldige sleutel weigert Core op deze routes zelf, dus die
401 komt ook in de vorm van de leverancier binnen, met WWW-Authenticate: Bearer.
Enkele antwoorden komen op deze vijf routes nog steeds als problem+json binnen. Een onverwachte
500 is er één. De andere komen van de gateway vóór Core, nog voordat Core het verzoek ziet: de
eigen snelheidslimiet van de gateway (429) en zijn tijdslimiet
(408) op alle vijf, en een body groter dan 1 MiB (413) op POST /responses/{id}/cancel, dat
geen body van die omvang nodig heeft. De antwoorden van de gateway dragen de titel van hun status
en geen X-Request-Id; daaraan herken je ze tegenover de antwoorden van Core zelf. Op de
drie routes die een gesprek meedragen -- POST /responses, POST /messages en
POST /responses/{id}/tool_outputs -- weigert Core een te grote body zelf, met 413 in de vorm van
de leverancier: ze nemen tot 8 MiB aan, tenzij jouw installatie een andere grens heeft ingesteld, en
de melding noemt die grens. Een body boven 1 MiB wordt alleen gelezen voor een geldige sleutel; met
een ontbrekende of onjuiste sleutel volgt 401 zonder dat de body wordt gelezen. POST /messages
antwoordt daarnaast 500 in de envelop van Anthropic, met type: api_error, als een
beurt mislukt bij het model, bij pseudonimisering of op gestructureerde uitvoer; alleen een 500 die
niemand voorzag is problem+json.
HTTP-statuscodes¶
| Status | Betekenis | Actie |
|---|---|---|
400 |
Een modelroute heeft het verzoek geweigerd (hierboven). | Lees error.message en het veld in error.param. |
401 |
Authenticatie is mislukt. | Controleer de secret van de API-sleutel. |
403 |
Het beleid weigert toegang, de bewerking staat niet open voor jouw rol, of de organisatie of een organisatie erboven is opgeschort; een opschorting draagt reason_code: "organisation_suspended" |
Lees detail en los de beperking op. |
404 |
De resource is niet beschikbaar of de capability is uitgeschakeld. | Controleer GET /key en daarna het resource-id. |
408 |
Het verzoek was na 300 seconden nog niet volledig aangekomen; dit antwoord komt van de gateway (tijdslimiet). | Stuur een kleinere body, of verstuur hem over een snellere verbinding. |
409 |
De bewerking past niet bij de huidige toestand, of je organisatie wordt nog ingericht of wordt verwijderd (The tenant is not ready.). |
Lees detail; controleer op dubbele namen of een ongeldige statusovergang. Verwijder je iets dat nog in gebruik is, dan staat erbij wat het gebruikt (hieronder). Is de organisatie nog niet klaar, probeer het dan later opnieuw. |
413 |
Het verzoek of de upload is te groot. | Verklein de inhoud. |
429 |
Een maandlimiet van je is bereikt, je verstuurt te veel verzoeken, of je houdt al zoveel tegelijk open als mag (eventstreams, workflowruns of -triggers). | Wacht zo lang als Retry-After zegt als die er is, en herhaal anders met oplopende wachttijden. Een limiet antwoordt met een X-Request-Id-header en een detail dat vertelt welke van de twee limieten het was; de snelheidslimiet aan de rand heeft geen van beide. Zie je maandlimiet. |
422 |
De validatie is mislukt op een andere route dan de vijf hierboven. | Corrigeer de velden in errors. |
500 |
Er is een onverwachte fout opgetreden. | Bewaar het request-id en meld aanhoudende fouten. |
503 |
Een benodigde dienst is niet beschikbaar. | Probeer het opnieuw met steeds langere wachttijden. |
De foutcatalogus splitst deze statussen in de soorten die type noemt: een 429
door een maandlimiet en een door de snelheidslimiet zijn bijvoorbeeld twee soorten.
Een 401 bevat WWW-Authenticate: Bearer. Een 403 betekent dat de authenticatie is geslaagd,
maar de bewerking niet is toegestaan. Een 500 bevat nooit de interne fouttekst.
Iets verwijderen dat nog in gebruik is¶
Core verwijdert niets waar iets anders nog naar verwijst, en er wordt niets mee verwijderd. De
DELETE antwoordt 409 en zegt wat het nog gebruikt, zodat je die verwijzingen kunt weghalen en
het verwijderen opnieuw kunt sturen:
{
"title": "Conflict",
"status": 409,
"detail": "The skill is named by an agent; remove it from the agent first.",
"conflicts": [
{ "where": "agents", "id_or_name": "agent_7Kc2...", "label_or_condition": "helpdesk",
"reason": "links skill skill_3Rt9...", "reason_code": "links_skill", "count": null }
],
"withheld": [{ "where": "agents", "count": 2 }]
}
| Veld | Wat het zegt |
|---|---|
conflicts[].where |
het soort ding dat het gebruikt, zoals agents, indexes, graphs, keys of retrieval tools |
conflicts[].id_or_name, label_or_condition |
zijn id en zijn naam; bij een graaftype in beide de naam van het type |
conflicts[].reason_code |
waarom het in de weg zit, uit een vaste lijst waar je client op kan schakelen: names_tool, names_toolset, delegates_to_agent, links_skill, selects_collection, ingests_with_pipeline, runs_pipeline, fills_graph, injects_memory, extraction_on, has_entities, has_relations, names_routing_config, default_routing_config, outside_vocabulary. De laatste hoort bij de 422 van een vocabulaire dat opgeslagen rijen tegenspreken, nooit bij een verwijdering. reason zegt hetzelfde in een zin voor mensen, en die formulering kan veranderen |
conflicts[].count |
een getal waar een getal bedoeld is: hoeveel entiteiten of relaties van een graaftype een nieuw schema zou laten vallen. Anders null |
withheld |
wat het ding gebruikt en wat je sleutel niet mag lezen, geteld per soort (agents, indexes, graphs, keys), zonder id of naam |
conflicts bevat hoogstens de eerste twintig; zijn er meer, dan eindigt detail met More are not
listed. Het verwijderen van een routeringsconfiguratie is de uitzondering: dat noemt tot honderd
sleutels die haar nog noemen, en detail zegt daar niet of er meer zijn. Een agent, een index of een graaf die het beleid van je sleutel hem niet laat lezen, of een
sleutel als de jouwe de capability management mist, wordt nooit genoemd: het wordt geteld in
withheld, en een telling daar is exact zolang niet meer dan honderd dingen van die soort het ding
gebruiken. Een zoektool wordt altijd genoemd. Een verwijdering kan dus 409 antwoorden
met een lege conflicts; vraag iemand die die dingen wel kan lezen om de verwijzing weg te halen.
Dit geldt voor een skill die een agent koppelt, een agent die een andere agent als tool aanroept, een toolset, een connector, een MCP-server, een zoektool of een alias die een agent noemt, een collectie die een index selecteert, een pipeline die een index, een graaf of een zoektool gebruikt, een index waaruit een sleutel geheugen inspuit of waarvoor geheugenextractie aanstaat, en een graafschema dat een type weglaat waar de graaf nog feiten van bevat. Alleen de nieuwste versie van een agent telt.
Tijdslimiet voor een verzoek¶
De gateway geeft elk verzoek 300 seconden om volledig aan te komen, body inbegrepen, en antwoordt
408 als dat niet lukt. Alleen een grote body over een trage verbinding komt in de buurt van die
grens. Een modelaanroep (POST /responses, POST /messages, POST /responses/{id}/tool_outputs)
neemt standaard tot 8 MiB aan, en daarvoor is een uploadsnelheid van ongeveer 0,2 Mbit/s nodig om
op tijd aan te komen; een upload naar POST /files neemt standaard tot 25 MiB aan, en daarvoor is
ongeveer 0,7 Mbit/s nodig. Een nieuwe poging loopt tegen dezelfde grens aan, tenzij de body kleiner
is of de verbinding sneller.
Limieten op vrije tekst¶
Een veld dat vrije tekst aanneemt heeft een limiet, en een verzoek daarboven wordt geweigerd met
422, met de naam van het veld en de limiet in de melding:
| Veld | Limiet |
|---|---|
instructions van een agent, en template van een promptversie |
262.144 tekens |
Een waarde in de config van een abonnement |
16.384 tekens |
metadata van een collectie of een bron |
64 paren, sleutels van hoogstens 128 en waarden van hoogstens 2.048 tekens |
Het request van een schedule |
256 KiB, geserialiseerd |
tool_variables van een verzoek (aanroepvariabelen) |
64 namen, een string van hoogstens 4.096 tekens (8.192 voor een geheim), 64 KiB in totaal; 400 op POST /responses en POST /messages |
query van een zoekopdracht |
4.096 tekens |
Ook de instructions en de input van een beurt hebben een limiet, die op
POST /responses met 400 wordt geweigerd: Limieten.
Op POST /messages gelden dezelfde 262.144 tekens voor system; een langere wordt geweigerd met
400, met system als veld.
Paginering met cursors¶
Lijst-endpoints geven items terug en een cursor voor de volgende pagina:
{ "items": [...], "next_cursor": "eyJ2IjoxLCJr..." }
Stuur next_cursor mee als queryparameter cursor. Met limit stel je het aantal items per pagina
in. Als next_cursor null is, heb je het einde bereikt.
curl -s "$CORE_URL/threads?limit=50" -H "Authorization: Bearer $CORE_KEY"
curl -s "$CORE_URL/threads?limit=50&cursor=eyJ2IjoxLCJr..." -H "Authorization: Bearer $CORE_KEY"
Gebruik de cursor ongewijzigd. Het formaat heeft een versie en kan veranderen. Paginering met een offset wordt niet ondersteund. Cursors voorkomen dat paginagrenzen verschuiven wanneer er nieuwe records worden toegevoegd.
Een lijst sorteren¶
Een lijst die te sorteren is, kent sort, de naam van een kolom, en order: asc of desc. De
kolommen die een lijst aanbiedt zijn name, created_at en updated_at, voor zover de resource ze
heeft; de API-referentie noemt ze per route. Een kolom die de route niet aanbiedt geeft een 422
met query.sort. Met sort zonder order loopt de lijst oplopend. Met geen van beide houdt hij
zijn gebruikelijke volgorde: nieuwste eerst bij schedules en evaluations, oudste eerst bij de rest;
alleen order leest die lijst in de richting die je noemt. De versielijsten van agents en prompts
kennen order ook, zonder sort: ze lopen oudste eerst, en order=desc leest ze nieuwste eerst. De versielijsten van toolsets,
tool-aliassen, MCP-servers en API-, mail- en SQL-connectors lopen nieuwste eerst, en order=asc
leest ze oudste eerst.
curl -s "$CORE_URL/skills?sort=name&order=asc&limit=50" -H "Authorization: Bearer $CORE_KEY"
Rijen met dezelfde waarde in de gesorteerde kolom komen in een vaste volgorde, zodat er van de ene
pagina naar de andere geen rij wordt overgeslagen of dubbel getoond. Namen worden vergeleken zoals
de database tekst vergelijkt, dus hoofdlettergevoelig. Een cursor geldt alleen voor de sort en
order waarmee hij is uitgegeven: stuur je hem met een andere, dan volgt een 422 met
query.cursor. Begin dus opnieuw zonder cursor als je een van beide wijzigt.
Idempotentiesleutels¶
Stuur een header Idempotency-Key mee met POST /responses en gebruik dezelfde waarde bij een
herhaling. Zodra Core het oorspronkelijke resultaat heeft vastgelegd, kan het de herhaling
herkennen:
| Oorspronkelijk antwoord | Herhaling met dezelfde sleutel |
|---|---|
Opgeslagen (201) |
200 met het opgeslagen antwoord; geen extra modelaanroep |
Niet opgeslagen (200) |
409; er is geen opgeslagen antwoord om terug te geven |
Laat opslag ingeschakeld als je het antwoord na een verbindingsfout wilt kunnen ophalen. Core kan een afgeronde aanroep zonder opslag herkennen, maar de uitvoer niet teruggeven.
Stuur geen gelijktijdige verzoeken met dezelfde sleutel. Als een herhaling aankomt voordat de eerste
aanroep is vastgelegd, kunnen beide verzoeken het model aanroepen en verbruik opleveren. De
conflicterende schrijfactie geeft 409. Idempotentie garandeert dus niet precies één aanroep naar
de modelleverancier.
Verzoeken herhalen¶
Gebruik voor modelaanroepen eerst de hierboven beschreven idempotentie:
| Situatie | Afhandeling |
|---|---|
503 of een verbindingsfout zonder antwoord |
Probeer het opnieuw met steeds langere wachttijden. |
500 |
Probeer het opnieuw met langere wachttijden; meld het request-id als de fout blijft optreden. |
Een weigering door de snelheidslimiet vóór Core, zonder X-Request-Id |
Wacht voordat je opnieuw probeert. Elke credential heeft een eigen limiet. |
Andere 4xx |
Corrigeer het verzoek of de rechten voordat je opnieuw probeert. |
Antwoord met status: failed |
Bekijk de fout in het antwoord. Een nieuwe modelpoging is een nieuwe beurt en kan extra verbruik opleveren. |
Core beperkt het aantal herhalingen naar de modelleverancier. Een aanroep die een time-out geeft, kan al uitvoer hebben opgeleverd waarvoor kosten worden gerekend.
Herkomst van resources¶
Skills, prompts en hun versies, tools, MCP-servers, bestanden, kennisbronnen, indexen, pipelines en
retrieval-tools bevatten created_by. Daarin staat het id van de sleutel die de resource aanmaakte,
of operator: gevolgd door de identiteit van de consolegebruiker.
Gebruik dit veld voor herkomstinformatie en sortering. De organisatie is eigenaar; created_by
verleent of beperkt geen toegang. Andere sleutels van de organisatie kunnen de resources gebruiken
voor zover hun capabilities en beleid dat toestaan.
API-referentie¶
De API-referentie wijst je de twee verkenners van je installatie: ReDoc om elke route met zijn verzoek- en antwoordvorm te lezen, Swagger UI om er een uit te proberen met je sleutel. In het deel Basis-URL staat het adres waarop je elke route aanroept.