Afspraken

Afspraken

De regels die op elk endpoint gelden, hier één keer opgeschreven in plaats van vijfentwintig keer herhaald.

Idempotentie

Endpoints die iets wijzigen accepteren een Idempotency-Key-header. Een verzoek met dezelfde sleutel herhalen speelt het oorspronkelijke antwoord opnieuw af in plaats van het effect te herhalen, dus een nieuwe poging na een time-out kan geen tweede paspoort aanmaken. Sleutels horen bij één organisatie, zodat twee klanten nooit op dezelfde waarde botsen. Test en productie zijn gescheiden: een sleutel die in de ene modus al gebruikt is, wordt in de andere geweigerd in plaats van afgespeeld. Eén uitzondering, en die is een bevoegdheid en geen feit: de ondertekende upload-URL van `POST /documents` wordt bij een herhaling opnieuw uitgegeven zolang het bestand nog ontbreekt, en weggelaten zodra het binnen is — een verlopen URL zou een getrouwe herhaling van niets bruikbaars zijn.

Een sleutel wordt 30 dagen onthouden. Daarna is hij volledig vergeten en wordt een nieuwe poging ermee opnieuw uitgevoerd in plaats van afgespeeld — een afstemmingstaak die later kan draaien, kan dus beter een verse sleutel aanmaken.

Verzoek
curl "https://passportcraft.com/api/v1/organizations/{organization}/passports" \
  -X POST \
  -H "Authorization: Bearer $PASSPORTCRAFT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"category":"textile"}'

Paginering

Verzamelingen worden met een cursor gepagineerd, nooit met een offset. Een offset is onjuist zodra er gelijktijdig geschreven wordt: een record dat tussen twee pagina-opvragingen wordt ingevoegd verschuift alle latere records, en een client slaat rijen over of dupliceert ze zonder het te merken.

Stuur next_cursor terug als cursor om de volgende pagina op te halen. Een cursor codeert de filters waaronder hij is uitgegeven, dus met andere filters wordt hij geweigerd in plaats van beantwoord met een pagina die stilzwijgend iets anders betekent.

Antwoord
{
  "object": "list",
  "data": [],
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOC0wMVQxNDowMzoyMi41MDFaIn0"
}

Voorwaardelijke schrijfacties

Het lezen van een paspoort levert een ETag op met de versie erin. Stuur die terug als If-Match bij een PATCH en de schrijfactie wordt geweigerd als het paspoort intussen is gewijzigd — de enige manier om lezen, wijzigen en schrijven veilig te maken tegenover een gelijktijdige bewerker.

Verzoek
curl "https://passportcraft.com/api/v1/organizations/{organization}/passports/{id}" \
  -X PATCH \
  -H "Authorization: Bearer $PASSPORTCRAFT_API_KEY" \
  -H "If-Match: \"4\"" \
  -H "Content-Type: application/json" \
  -d '{"data":{"recycled_content_percentage":38}}'

Snelheidslimieten

Bij elk verzoek met een geldige sleutel lopen drie tellers tegelijk en de smalste beslist. De gepubliceerde cijfers zijn bewust behoedzame beginwaarden, geen fijngeregelde plafonds.

TellerVerzoekenVenster
key_org100060s
organization300060s
credential1000060s
destructive503600s

Elk geteld antwoord draagt RateLimit- en RateLimit-Policy-headers die de teller noemen die het dichtst bij zijn limiet kwam. Een weigering voegt Retry-After toe. Wacht die tijd af in plaats van te gokken.

Een verzoek dat binnenkomt zonder bruikbare sleutel wordt gemeten met een aparte, veel strakkere teller van 60 verzoeken per minuut per clientadres. Voor een geldige sleutel geldt hij nooit.

Omvang van het verzoek

Een verzoeklichaam boven het plafond van zijn endpoint wordt geweigerd met payload_too_large, voordat er iets richting de database wordt gelezen. Het plafond wordt twee keer getoetst: eerst aan de opgegeven Content-Length, wat niets kost, en daarna aan de bytes die werkelijk binnenkomen — zo blijft ook een verzoek zonder opgegeven lengte begrensd.

EndpointsPlafond
Elk endpoint dat één record schrijft256 KiB (262144 bytes)
Bulkimport en eenhedenbatches4 MiB (4194304 bytes)

Het bulkplafond volgt de grootste batch die deze API aanneemt, niet een rond getal: 500 importregels met elk veld van een categorie ingevuld, of 1000 geserialiseerde eenheden. Geen van beide past binnen het standaardplafond, en precies daarom hebben die twee endpoints een eigen plafond.

Een lichaam moet binnenkomen als application/json; application/merge-patch+json wordt ook aanvaard. Al het andere wordt geweigerd met unsupported_media_type in plaats van te stranden in de parser — het geval om te kennen is curl -d, dat application/x-www-form-urlencoded stuurt tenzij anders opgegeven. Een lichaam zonder enige Content-Type wordt als JSON gelezen.

HTTP-methoden

Een endpoint beantwoordt alleen de methoden die het documenteert. Elke andere methode wordt geweigerd met method_not_allowed en een Allow-header die de werkende methoden noemt, zodat een client die naar het verkeerde werkwoord grijpt het juiste uit de weigering zelf leert. HEAD werkt overal waar GET werkt, en OPTIONS werkt overal.

Antwoord
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, PATCH, OPTIONS
Content-Type: application/json

{
  "error": {
    "code": "method_not_allowed",
    "documentation_url": "https://passportcraft.com/docs/api/errors#method_not_allowed",
    "request_id": "req_9Fv2KpQ0aXbT4Lmn",
    "details": { "method": "DELETE", "allowed": ["GET", "HEAD", "PATCH", "OPTIONS"] }
  }
}

Ingrijpende handelingen

Een paspoort terugtrekken en er een naar de prullenbak verplaatsen halen allebei een gepubliceerd record uit de markt, dus tellen ze mee voor een apart plafond naast de gewone snelheidslimiet. Een lus van goedkope, correct opgebouwde verzoeken mag geen hele catalogus kunnen uitschakelen.

Een document aan een veld koppelen

Sommige url-velden accepteren een geüpload bestand in plaats van een link — bijvoorbeeld een testrapport of een conformiteitsverklaring. Upload eerst het bestand en laat het veld er vervolgens naar verwijzen door de document-id naar de bijbehorende sleutel van dat veld in `data` te schrijven. Het veld zelf mag leeg blijven: een veld dat documenten accepteert geldt als ingevuld zodra er een document aan hangt, dus een paspoort met een lege url kan nog steeds worden gevalideerd en gepubliceerd.

U hoeft die sleutel nooit zelf samen te stellen. Een veld dat documenten accepteert draagt twee attributen in het categorieschema: `document_types`, met de toegestane soorten, en `document_id_key`, met de precieze sleutel die u moet schrijven. Lees de sleutel uit het schema in plaats van uit te gaan van de naamgevingsregel; dat is de enige ondersteunde manier. De bijbehorende sleutel is een eigenschap van het veld en geen zelfstandig veld, en verschijnt daarom nooit in de lijst `fields` van het schema.

Eén regel die het schema niet voor u uitschrijft: de `access_tier` van het document moet gelijk zijn aan die van het veld. Een openbaar document kan geen veld van niveau ‘authority’ vervullen; de koppeling wordt geweigerd met `access_tier_mismatch`, omdat een document met een afwijkend niveau niet zou worden getoond waar het veld wel wordt getoond. Maak het document aan met de `access_tier` die de velddescriptor vermeldt.

Verzoek
curl "https://passportcraft.com/api/v1/organizations/{organization}/passports/{id}" \
  -X PATCH \
  -H "Authorization: Bearer $PASSPORTCRAFT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"data":{"conformity_declaration_url__document_id":"doc_123"}}'

Maak de bijbehorende sleutel leeg om het document los te koppelen; het bestand blijft in uw bibliotheek totdat u het verwijdert. Verwijdert u een document waar nog een veld naar verwijst, dan meldt het antwoord wat er is losgekoppeld, en die melding bereikt alleen de aanroeper die het verzoek deed.

De `upload_state` van een document is `ready`, `pending` of `unknown`. `unknown` betekent dat we niet konden vaststellen of de bytes in de opslag staan: ofwel gaf de opslag geen antwoord, ofwel viel de rij voorbij de 25 documenten zonder bytes die één verzoek controleert. Beschouw het als onbepaald, niet als afwezig: bij publiceren leidt `unknown` tot `storage_unavailable` in plaats van de melding dat een bestand ontbreekt, en een latere leesactie geeft doorgaans uitsluitsel.

Verzoek-identificaties

Elk antwoord draagt een Request-Id-header, bij succes net zo goed als bij een fout. Noem hem in een supportvraag en precies die aanroep is terug te vinden.

De gebeurtenissenstroom bewaart 30 dagen geschiedenis. Een koppeling die minder vaak opvraagt mist wijzigingen en kan beter afstemmen tegen de paspoortenlijst.

Afspraken — PassportCraft-API | PassportCraft