Gratis API voor kaartcentrering: PSA en fotometing

Centering Lab is een gratis REST-API voor kaartcentrering, zonder API-sleutel. Op https://centeringlab.com/api/v1 levert ze fotometingen, verhoudingen en PSA-, BGS-, CGC- of SGC-bovengrenzen op basis van alleen centrering. Ze voorspelt geen eindcijfer en controleert geen echtheid. Roep haar aan vanaf je eigen server. OpenAPI.

Snel beginnen

Voer curl uit in je terminal. Beide voorassen zijn opgegeven, maar de achterkant ontbreekt: incomplete is true. PSA 10 is een centreringsgrens, geen voorspelling van het eindcijfer.

POST /api/v1/grade

Verzoek

curl --fail-with-body 'https://centeringlab.com/api/v1/grade' \
  -H 'Content-Type: application/json' \
  --data '{"front_lr":0.55,"front_tb":"50/50","house":"PSA"}'

HTTP 200-antwoord

Uittreksel uit een echt lokaal HTTP-antwoord; extra velden en banden zijn weggelaten. JSON-sleutels en servermeldingen blijven Engels.

{
  "front": {
    "ratios": {
      "lr": 55,
      "tb": 50
    }
  },
  "combined": {
    "PSA": {
      "maximum_grade": 10,
      "source_status": "official"
    }
  },
  "normalizations": [
    {
      "field": "front_lr",
      "input": 0.55,
      "ratio": "55/45",
      "note": "0.55 read as 55/45"
    }
  ],
  "incomplete": true,
  "missing_faces": [
    "back"
  ],
  "disclaimer": "This is a ceiling from centering alone, not a prediction of the final grade."
}

Endpoints en velden

Bekende verhoudingen

POST /grade vereist minstens één van front_lr, front_tb, back_lr, back_tb. Normalisatie naar de grootste kant. Percentages (55), fracties (0.55) en paren met som 100 (55/45) of 1 (0.55/0.45) zijn geldig. Scheidingstekens: /, -, –, —, :, x en spaties; % mag. De losse waarde 1 is dubbelzinnig en wordt geweigerd. L/R of left/right alleen voor *_lr; T/B of top/bottom voor *_tb.

house filtert PSA, BGS, CGC of SGC. normalizations verklaart fractieconversies. missing_axes, missing_faces en incomplete tonen ontbrekende gegevens die de grens kunnen verlagen. combined combineert zijden; limiting_face en limiting_axis tonen de beperking. Elke grens bevat bronnen en bewijsstatus.

Contractvelden (exacte JSON-namen)

input: front_lr, front_tb, back_lr, back_tb, house
output: front, front.ratios, front.ratios.lr, front.ratios.tb, front.missing_axes, front.ceilings, front.ceilings.PSA, front.ceilings.PSA.maximum_grade, front.ceilings.PSA.label, front.ceilings.PSA.rank, front.ceilings.PSA.limiting_face, front.ceilings.PSA.limiting_axis, front.ceilings.PSA.distance_to_next, front.ceilings.PSA.next_grade, front.ceilings.PSA.next_label, front.ceilings.PSA.borderline, front.ceilings.PSA.unconstrained, front.ceilings.PSA.source_status, front.ceilings.PSA.standard_status, front.ceilings.PSA.source, front.ceilings.PSA.sources, front.ceilings.PSA.verified, front.ceilings.PSA.verification, front.ceilings.BGS, front.ceilings.BGS.maximum_grade, front.ceilings.BGS.label, front.ceilings.BGS.rank, front.ceilings.BGS.limiting_face, front.ceilings.BGS.limiting_axis, front.ceilings.BGS.distance_to_next, front.ceilings.BGS.next_grade, front.ceilings.BGS.next_label, front.ceilings.BGS.borderline, front.ceilings.BGS.unconstrained, front.ceilings.BGS.source_status, front.ceilings.BGS.standard_status, front.ceilings.BGS.source, front.ceilings.BGS.sources, front.ceilings.BGS.verified, front.ceilings.BGS.verification, front.ceilings.CGC, front.ceilings.CGC.maximum_grade, front.ceilings.CGC.label, front.ceilings.CGC.rank, front.ceilings.CGC.limiting_face, front.ceilings.CGC.limiting_axis, front.ceilings.CGC.distance_to_next, front.ceilings.CGC.next_grade, front.ceilings.CGC.next_label, front.ceilings.CGC.borderline, front.ceilings.CGC.unconstrained, front.ceilings.CGC.source_status, front.ceilings.CGC.standard_status, front.ceilings.CGC.source, front.ceilings.CGC.sources, front.ceilings.CGC.verified, front.ceilings.CGC.verification, front.ceilings.SGC, front.ceilings.SGC.maximum_grade, front.ceilings.SGC.label, front.ceilings.SGC.rank, front.ceilings.SGC.limiting_face, front.ceilings.SGC.limiting_axis, front.ceilings.SGC.distance_to_next, front.ceilings.SGC.next_grade, front.ceilings.SGC.next_label, front.ceilings.SGC.borderline, front.ceilings.SGC.unconstrained, front.ceilings.SGC.source_status, front.ceilings.SGC.standard_status, front.ceilings.SGC.source, front.ceilings.SGC.sources, front.ceilings.SGC.verified, front.ceilings.SGC.verification, back, back.ratios, back.ratios.lr, back.ratios.tb, back.missing_axes, back.ceilings, back.ceilings.PSA, back.ceilings.PSA.maximum_grade, back.ceilings.PSA.label, back.ceilings.PSA.rank, back.ceilings.PSA.limiting_face, back.ceilings.PSA.limiting_axis, back.ceilings.PSA.distance_to_next, back.ceilings.PSA.next_grade, back.ceilings.PSA.next_label, back.ceilings.PSA.borderline, back.ceilings.PSA.unconstrained, back.ceilings.PSA.source_status, back.ceilings.PSA.standard_status, back.ceilings.PSA.source, back.ceilings.PSA.sources, back.ceilings.PSA.verified, back.ceilings.PSA.verification, back.ceilings.BGS, back.ceilings.BGS.maximum_grade, back.ceilings.BGS.label, back.ceilings.BGS.rank, back.ceilings.BGS.limiting_face, back.ceilings.BGS.limiting_axis, back.ceilings.BGS.distance_to_next, back.ceilings.BGS.next_grade, back.ceilings.BGS.next_label, back.ceilings.BGS.borderline, back.ceilings.BGS.unconstrained, back.ceilings.BGS.source_status, back.ceilings.BGS.standard_status, back.ceilings.BGS.source, back.ceilings.BGS.sources, back.ceilings.BGS.verified, back.ceilings.BGS.verification, back.ceilings.CGC, back.ceilings.CGC.maximum_grade, back.ceilings.CGC.label, back.ceilings.CGC.rank, back.ceilings.CGC.limiting_face, back.ceilings.CGC.limiting_axis, back.ceilings.CGC.distance_to_next, back.ceilings.CGC.next_grade, back.ceilings.CGC.next_label, back.ceilings.CGC.borderline, back.ceilings.CGC.unconstrained, back.ceilings.CGC.source_status, back.ceilings.CGC.standard_status, back.ceilings.CGC.source, back.ceilings.CGC.sources, back.ceilings.CGC.verified, back.ceilings.CGC.verification, back.ceilings.SGC, back.ceilings.SGC.maximum_grade, back.ceilings.SGC.label, back.ceilings.SGC.rank, back.ceilings.SGC.limiting_face, back.ceilings.SGC.limiting_axis, back.ceilings.SGC.distance_to_next, back.ceilings.SGC.next_grade, back.ceilings.SGC.next_label, back.ceilings.SGC.borderline, back.ceilings.SGC.unconstrained, back.ceilings.SGC.source_status, back.ceilings.SGC.standard_status, back.ceilings.SGC.source, back.ceilings.SGC.sources, back.ceilings.SGC.verified, back.ceilings.SGC.verification, combined, combined.PSA, combined.PSA.maximum_grade, combined.PSA.label, combined.PSA.rank, combined.PSA.limiting_face, combined.PSA.limiting_axis, combined.PSA.distance_to_next, combined.PSA.next_grade, combined.PSA.next_label, combined.PSA.borderline, combined.PSA.unconstrained, combined.PSA.source_status, combined.PSA.standard_status, combined.PSA.source, combined.PSA.sources, combined.PSA.verified, combined.PSA.verification, combined.BGS, combined.BGS.maximum_grade, combined.BGS.label, combined.BGS.rank, combined.BGS.limiting_face, combined.BGS.limiting_axis, combined.BGS.distance_to_next, combined.BGS.next_grade, combined.BGS.next_label, combined.BGS.borderline, combined.BGS.unconstrained, combined.BGS.source_status, combined.BGS.standard_status, combined.BGS.source, combined.BGS.sources, combined.BGS.verified, combined.BGS.verification, combined.CGC, combined.CGC.maximum_grade, combined.CGC.label, combined.CGC.rank, combined.CGC.limiting_face, combined.CGC.limiting_axis, combined.CGC.distance_to_next, combined.CGC.next_grade, combined.CGC.next_label, combined.CGC.borderline, combined.CGC.unconstrained, combined.CGC.source_status, combined.CGC.standard_status, combined.CGC.source, combined.CGC.sources, combined.CGC.verified, combined.CGC.verification, combined.SGC, combined.SGC.maximum_grade, combined.SGC.label, combined.SGC.rank, combined.SGC.limiting_face, combined.SGC.limiting_axis, combined.SGC.distance_to_next, combined.SGC.next_grade, combined.SGC.next_label, combined.SGC.borderline, combined.SGC.unconstrained, combined.SGC.source_status, combined.SGC.standard_status, combined.SGC.source, combined.SGC.sources, combined.SGC.verified, combined.SGC.verification, normalizations, normalizations[].field, normalizations[].input, normalizations[].ratio, normalizations[].note, incomplete, missing_faces, summary, disclaimer

Contractvelden (exacte JSON-namen)

input: maximum_grade, label, rank, limiting_face, limiting_axis, distance_to_next, next_grade, next_label, borderline, unconstrained, source_status, standard_status, source, sources, verified, verification
output: maximum_grade, label, rank, limiting_face, limiting_axis, distance_to_next, next_grade, next_label, borderline, unconstrained, source_status, standard_status, source, sources, verified, verification

Fotometing

POST /measure vereist face: front of back. Standaard card_size is standard (63×88 mm); small is 59×86 mm. Geef precies één bron: openbare HTTPS-image_url op poort 443 of ruwe image_base64 zonder data-URL-voorvoegsel. Privéadressen, inloggegevens en antwoorden zonder afbeelding worden geweigerd, ook bij omleidingen. REST aanvaardt ook één openaiFileIdRefs van GPT Actions; gebruik normaal URL of base64. Stuur één rasterframe, liefst JPG, PNG of WebP.

HTTP 200 kan status ok, needs-review of failed bevatten; alleen ok heeft ceilings. Controleer code, confidence, warnings, lr en tb. uncertainty_pp en sigma_pp zijn procentpunten; stations_major_percent bevat steekproeven. Bij onzekerheid: nieuwe foto of controle via adjust_url. Het voorbeeld stuurt bewust een kleine effen afbeelding: NO_CARD is een echte mislukking, geen geslaagde meting.

Contractvelden (exacte JSON-namen)

input: face, card_size, image_url, image_base64, openaiFileIdRefs, openaiFileIdRefs[].name, openaiFileIdRefs[].id, openaiFileIdRefs[].mime_type, openaiFileIdRefs[].download_link
output: status, code, face, card_size, lr, lr.ratio, lr.major_percent, lr.minor_percent, lr.uncertainty_pp, lr.sigma_pp, lr.worst_station_px, lr.stations_major_percent, tb, tb.ratio, tb.major_percent, tb.minor_percent, tb.uncertainty_pp, tb.sigma_pp, tb.worst_station_px, tb.stations_major_percent, confidence, warnings, ceilings, ceilings.PSA, ceilings.PSA.maximum_grade, ceilings.PSA.label, ceilings.PSA.rank, ceilings.PSA.limiting_face, ceilings.PSA.limiting_axis, ceilings.PSA.distance_to_next, ceilings.PSA.next_grade, ceilings.PSA.next_label, ceilings.PSA.borderline, ceilings.PSA.unconstrained, ceilings.PSA.source_status, ceilings.PSA.standard_status, ceilings.PSA.source, ceilings.PSA.sources, ceilings.PSA.verified, ceilings.PSA.verification, ceilings.BGS, ceilings.BGS.maximum_grade, ceilings.BGS.label, ceilings.BGS.rank, ceilings.BGS.limiting_face, ceilings.BGS.limiting_axis, ceilings.BGS.distance_to_next, ceilings.BGS.next_grade, ceilings.BGS.next_label, ceilings.BGS.borderline, ceilings.BGS.unconstrained, ceilings.BGS.source_status, ceilings.BGS.standard_status, ceilings.BGS.source, ceilings.BGS.sources, ceilings.BGS.verified, ceilings.BGS.verification, ceilings.CGC, ceilings.CGC.maximum_grade, ceilings.CGC.label, ceilings.CGC.rank, ceilings.CGC.limiting_face, ceilings.CGC.limiting_axis, ceilings.CGC.distance_to_next, ceilings.CGC.next_grade, ceilings.CGC.next_label, ceilings.CGC.borderline, ceilings.CGC.unconstrained, ceilings.CGC.source_status, ceilings.CGC.standard_status, ceilings.CGC.source, ceilings.CGC.sources, ceilings.CGC.verified, ceilings.CGC.verification, ceilings.SGC, ceilings.SGC.maximum_grade, ceilings.SGC.label, ceilings.SGC.rank, ceilings.SGC.limiting_face, ceilings.SGC.limiting_axis, ceilings.SGC.distance_to_next, ceilings.SGC.next_grade, ceilings.SGC.next_label, ceilings.SGC.borderline, ceilings.SGC.unconstrained, ceilings.SGC.source_status, ceilings.SGC.standard_status, ceilings.SGC.source, ceilings.SGC.sources, ceilings.SGC.verified, ceilings.SGC.verification, adjust_url, advice, elapsed_ms, image_bytes, summary, disclaimer

POST /api/v1/measure

Verzoek

curl --fail-with-body 'https://centeringlab.com/api/v1/measure' \
  -H 'Content-Type: application/json' \
  --data '{"face":"front","card_size":"standard","image_base64":"iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAAD0lEQVQImWNQwAEYhpYEAGFPGAHjXOFDAAAAAElFTkSuQmCC"}'

HTTP 200-antwoord

Uittreksel uit een echt lokaal HTTP-antwoord; extra velden en banden zijn weggelaten. JSON-sleutels en servermeldingen blijven Engels.

{
  "status": "failed",
  "code": "NO_CARD",
  "face": "front",
  "card_size": "standard",
  "lr": null,
  "tb": null,
  "confidence": null,
  "warnings": [],
  "ceilings": null,
  "adjust_url": "https://centeringlab.com/"
}

Sla je foto op als card.jpg. Dit antwoord gebruikt de demofoto van de website: onzekerheid geeft needs-review en ceilings is null. Je eigen foto geeft eigen metingen.

POST /api/v1/measure

Verzoek

python3 - <<'PY' > measure.json
import base64, json
from pathlib import Path
print(json.dumps({
    'face': 'front', 'card_size': 'standard',
    'image_base64': base64.b64encode(Path('card.jpg').read_bytes()).decode('ascii'),
}))
PY
curl --fail-with-body 'https://centeringlab.com/api/v1/measure' \
  -H 'Content-Type: application/json' \
  --data-binary @measure.json

HTTP 200-antwoord

Uittreksel uit een echt lokaal HTTP-antwoord; extra velden en banden zijn weggelaten. JSON-sleutels en servermeldingen blijven Engels.

{
  "status": "needs-review",
  "code": "HIGH_UNCERTAINTY",
  "face": "front",
  "card_size": "standard",
  "lr": {
    "ratio": "56/44",
    "major_percent": 55.54242922739353,
    "minor_percent": 44.45757077260647,
    "uncertainty_pp": 5.1,
    "sigma_pp": 2.3393336872317274,
    "worst_station_px": 350.163778228702,
    "stations_major_percent": [
      55.54242922739353,
      54.38358480163707,
      53.25627521942576
    ]
  },
  "tb": {
    "ratio": "52/48",
    "major_percent": 52.059885599520676,
    "minor_percent": 47.940114400479324,
    "uncertainty_pp": 6.4,
    "sigma_pp": 2.9286347555409855,
    "worst_station_px": 250.03684789689908,
    "stations_major_percent": [
      52.059885599520676,
      51.766308753028554,
      51.468031630625774
    ]
  },
  "confidence": 0.8603421926529179,
  "warnings": [
    "GET_CLOSER"
  ],
  "ceilings": null,
  "adjust_url": "https://centeringlab.com/"
}

Normen en bronnen

GET /standards aanvaardt optionele house en face. official, interpreted en approximate zijn bewijsstatussen, geen nauwkeurigheidsgaranties. bands[].status geldt per band; source, sources, verified en verification geven de herkomst. TAG is uitgesloten. SGC publiceert geen tabel voor achterkantcentrering: de banden zijn leeg en alleen de achterkant geeft geen SGC-grens.

Contractvelden (exacte JSON-namen)

input: house, face
output: standards, standards[].house, standards[].face, standards[].bands, standards[].bands[].value, standards[].bands[].label, standards[].bands[].rank, standards[].bands[].loose, standards[].bands[].tight, standards[].bands[].status, standards[].source, standards[].sources, standards[].status, standards[].verified, standards[].verification, standards[].note, rounding_rule, tag_note, summary, disclaimer

GET /api/v1/standards?house=PSA&face=front

Verzoek

curl --fail-with-body 'https://centeringlab.com/api/v1/standards?house=PSA&face=front'

HTTP 200-antwoord

Uittreksel uit een echt lokaal HTTP-antwoord; extra velden en banden zijn weggelaten. JSON-sleutels en servermeldingen blijven Engels.

{
  "standards": [
    {
      "house": "PSA",
      "face": "front",
      "bands": [
        {
          "value": 10,
          "label": "GEM MT",
          "rank": 100,
          "loose": 55,
          "status": "official"
        }
      ],
      "status": "official",
      "source": "https://www.psacard.com/gradingstandards",
      "note": "Published percentage thresholds. Only the listed centering bands are used; no missing grades are invented."
    }
  ],
  "tag_note": "TAG is excluded because its centering assessment is proprietary and is not represented by these public percentage bands."
}

Status en schema

GET /health levert status, naam, versie en disclaimer. GET /openapi.json levert OpenAPI 3.1.0. Het meetschema is bedoeld voor GPT Actions (URL of runtime-bestandsverwijzing); REST aanvaardt ook base64 volgens de velden hierboven.

GET /api/v1/health

Verzoek

curl --fail-with-body 'https://centeringlab.com/api/v1/health'

HTTP 200-antwoord

Uittreksel uit een echt lokaal HTTP-antwoord; extra velden en banden zijn weggelaten. JSON-sleutels en servermeldingen blijven Engels.

{
  "status": "ok",
  "name": "centering-lab",
  "version": "1.1.2",
  "disclaimer": "This is a ceiling from centering alone, not a prediction of the final grade."
}

GET /api/v1/openapi.json

Verzoek

curl --fail-with-body 'https://centeringlab.com/api/v1/openapi.json'

HTTP 200-antwoord

Uittreksel uit een echt lokaal HTTP-antwoord; extra velden en banden zijn weggelaten. JSON-sleutels en servermeldingen blijven Engels.

{
  "openapi": "3.1.0",
  "info": {
    "title": "Centering Lab API",
    "version": "1.1.2"
  },
  "servers": [
    {
      "url": "https://centeringlab.com"
    }
  ]
}

JavaScript en Python

Gebruik Node-fetch op de server. Beide voorbeelden sturen hetzelfde startverzoek. Python gebruikt de standaardbibliotheek. Controleer HTTP-fouten en bij metingen ook status ondanks HTTP 200.

JavaScript · Node

const response = await fetch('https://centeringlab.com/api/v1/grade', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({"front_lr":0.55,"front_tb":"50/50","house":"PSA"}),
});
const result = await response.json();
if (!response.ok) throw new Error(result.code + ': ' + result.message);
console.log(result);

Python · urllib

import json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request = Request(
    'https://centeringlab.com/api/v1/grade',
    data=json.dumps({"front_lr":0.55,"front_tb":"50/50","house":"PSA"}).encode('utf-8'),
    headers={'Content-Type': 'application/json'},
    method='POST',
)
try:
    with urlopen(request, timeout=20) as response:
        print(json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))
    raise

Fouten en opnieuw proberen

HTTP-fouten bevatten status, code, message en disclaimer. De tabel geldt voor REST, zonder MCP-protocolfouten of privéstatis­tieken. UNSUPPORTED_ENCODING is 415 bij gecomprimeerde JSON en 400 bij gecomprimeerde afbeeldingsantwoorden. Detectorcodes komen met HTTP 200.

CodeHTTPBetekenisWat te doen
BODY_TOO_LARGE413Te grootVerminder bytes of pixels; base64 telt mee voor de JSON-body.
EMPTY_IMAGE400Afbeelding niet te decoderenStuur één ondersteunde rasterafbeelding, liefst JPG, PNG of WebP; verwijder het data-URL-voorvoegsel.
IMAGE_DNS_FAILED400Afbeeldings-URL geweigerd of onbereikbaarGebruik een openbare HTTPS-afbeelding op poort 443 zonder inloggegevens; controleer DNS, omleidingen en antwoord.
IMAGE_DOWNLOAD_FAILED400Afbeeldings-URL geweigerd of onbereikbaarGebruik een openbare HTTPS-afbeelding op poort 443 zonder inloggegevens; controleer DNS, omleidingen en antwoord.
IMAGE_DOWNLOAD_TIMEOUT504Tijdslimiet bereiktGebruik een kleinere afbeelding of snellere host; gebruik eventueel de website.
IMAGE_REDIRECT_LIMIT400Afbeeldings-URL geweigerd of onbereikbaarGebruik een openbare HTTPS-afbeelding op poort 443 zonder inloggegevens; controleer DNS, omleidingen en antwoord.
IMAGE_TOO_LARGE413Te grootVerminder bytes of pixels; base64 telt mee voor de JSON-body.
IMAGE_TOO_MANY_PIXELS413Te grootVerminder bytes of pixels; base64 telt mee voor de JSON-body.
INTERNAL_ERROR500Server- of workerfoutWacht en probeer opnieuw, verklein de foto of gebruik de website.
INVALID_ARGUMENTS400Ongeldig verzoek of verhoudingCorrigeer de velden; stuur geldige, ongecomprimeerde JSON.
INVALID_BASE64400Afbeelding niet te decoderenStuur één ondersteunde rasterafbeelding, liefst JPG, PNG of WebP; verwijder het data-URL-voorvoegsel.
INVALID_BODY400Ongeldig verzoek of verhoudingCorrigeer de velden; stuur geldige, ongecomprimeerde JSON.
INVALID_HOST403Host of browseroorsprong geweigerdRoep centeringlab.com aan vanaf je server, niet vanuit de browser van een andere website.
INVALID_HTTP400Ongeldig verzoek of verhoudingCorrigeer de velden; stuur geldige, ongecomprimeerde JSON.
INVALID_IMAGE400Afbeelding niet te decoderenStuur één ondersteunde rasterafbeelding, liefst JPG, PNG of WebP; verwijder het data-URL-voorvoegsel.
INVALID_IMAGE_URL400Afbeeldings-URL geweigerd of onbereikbaarGebruik een openbare HTTPS-afbeelding op poort 443 zonder inloggegevens; controleer DNS, omleidingen en antwoord.
INVALID_INPUT400Ongeldig verzoek of verhoudingCorrigeer de velden; stuur geldige, ongecomprimeerde JSON.
INVALID_JSON400Ongeldig verzoek of verhoudingCorrigeer de velden; stuur geldige, ongecomprimeerde JSON.
INVALID_ORIGIN403Host of browseroorsprong geweigerdRoep centeringlab.com aan vanaf je server, niet vanuit de browser van een andere website.
INVALID_RATIO400Ongeldig verzoek of verhoudingCorrigeer de velden; stuur geldige, ongecomprimeerde JSON.
JSON_REQUIRED415Ongeldig verzoek of verhoudingCorrigeer de velden; stuur geldige, ongecomprimeerde JSON.
MEASURE_QUEUE_FULL503Dienst volRespecteer Retry-After en wacht steeds langer tussen pogingen.
MEASURE_TIMEOUT504Tijdslimiet bereiktGebruik een kleinere afbeelding of snellere host; gebruik eventueel de website.
MEASURE_WORKER_FAILED500Server- of workerfoutWacht en probeer opnieuw, verklein de foto of gebruik de website.
METHOD_NOT_ALLOWED405Route of methode niet beschikbaarGebruik de gedocumenteerde endpoints en methoden.
NOT_AN_IMAGE400Afbeeldings-URL geweigerd of onbereikbaarGebruik een openbare HTTPS-afbeelding op poort 443 zonder inloggegevens; controleer DNS, omleidingen en antwoord.
NOT_FOUND404Route of methode niet beschikbaarGebruik de gedocumenteerde endpoints en methoden.
RATE_LIMIT_CAPACITY503Dienst volRespecteer Retry-After en wacht steeds langer tussen pogingen.
RATE_LIMIT_DAY429Quotum bereiktRespecteer Retry-After in seconden; het dagquotum herstart om middernacht UTC.
RATE_LIMIT_MINUTE429Quotum bereiktRespecteer Retry-After in seconden; het dagquotum herstart om middernacht UTC.
REQUEST_CANCELLED499Verzoek afgebrokenProbeer alleen opnieuw als het resultaat nog nodig is.
REQUEST_CAPACITY503Dienst volRespecteer Retry-After en wacht steeds langer tussen pogingen.
UNSAFE_IMAGE_URL400Afbeeldings-URL geweigerd of onbereikbaarGebruik een openbare HTTPS-afbeelding op poort 443 zonder inloggegevens; controleer DNS, omleidingen en antwoord.
UNSUPPORTED_ENCODING400 / 415Ongeldig verzoek of verhoudingCorrigeer de velden; stuur geldige, ongecomprimeerde JSON.
UNSUPPORTED_IMAGE400Afbeelding niet te decoderenStuur één ondersteunde rasterafbeelding, liefst JPG, PNG of WebP; verwijder het data-URL-voorvoegsel.

Detectorcodes: HIGH_UNCERTAINTY, NEEDS_REVIEW, LOW_CONFIDENCE, NO_MEASUREMENT, NO_CARD, CARD_TOO_SMALL, CARD_CUT_OFF, NO_PRINTED_BORDER. failed en needs-review hebben geen gradinggrenzen. Fotografeer de hele kaart recht van boven, zonder sleeve op een donkere vlakke ondergrond, of gebruik de handmatige website-editor.

Gebruikslimieten

Quota gelden per IP en delen de bijbehorende groepen. Grade en standards delen één minutenteller; health en OpenAPI een andere. Vaste minutenvensters en UTC-dagen; geen dagquotum voor eenvoudige/protocolaanroepen. Base64 vergroot de bytes en telt mee voor JSON: de volledige afbeeldingslimiet past mogelijk niet.

LimietHuidige waarde
POST /measure · IP20 per minuut; 200 per UTC-dag
POST /grade + GET /standards · IP120 per minuut; Geen dagquotum in de limiter
GET /health + GET /openapi.json · IP120 per minuut; Geen dagquotum in de limiter
JSON-body12 MiB (12582912 bytes)
Gedecodeerde afbeeldingsbytes15 MiB (15728640 bytes)
Gedecodeerde pixels (alle frames)40000000
Meting inclusief wachtrij15 s
Afbeeldingsdownload10 s
Actieve metingen2
Metingen in wachtrij8
Lopende HTTP-verzoeken16

429 en capaciteits-503 bevatten Retry-After in seconden. Volle meetwachtrij en REQUEST_CAPACITY: 5 seconden; limitercapaciteit: 60. Respecteer de header met steeds langere wachttijd. Gedeelde capaciteit, zonder reservering per client of SLA voor beschikbaarheid en snelheid.

Browser, CORS en privacy

De browser van een andere website krijgt 403 INVALID_ORIGIN: gebruik je backend. Geen sleutel nodig; een sleutel opent CORS niet. API-foto’s gaan naar de server en worden alleen in geheugen verwerkt, zonder schijfopslag. De website verwerkt lokaal. Geen verzoeklogs: alleen geaggregeerde aantallen per endpoint/tool en resultaatcode. Privacy en voorwaarden.

MCP en meer informatie

https://centeringlab.com/mcp biedt AI-clients dezelfde drie tools en engine. REST biedt directe HTTP-aanroepen. Lees AI en MCP, hoe meten werkt en over Centering Lab.

Vragen over de API

Is de kaartcentrerings-API gratis voor ontwikkelaars?

Ja. Alle endpoints zijn gratis, zonder account of betaald plan. Gebruikslimieten gelden; geen echtheidscontrole of voorspelling van een eindcijfer.

Hebben REST-integraties een API-sleutel nodig?

Nee. Stuur geldige verzoeken vanaf je server; de beperking op browseroorsprongen blijft gelden.

Welke quota heeft deze centrerings-API?

Metingen: 20 per minuut en 200 per UTC-dag per IP. Grade en standards delen 120 per minuut per IP. Respecteer Retry-After en grootte- en capaciteitslimieten.

Bewaart de REST-API ingezonden foto’s?

Nee. Ze bereiken de server, maar worden alleen in geheugen verwerkt. Geen verzoeklogs; alleen geaggregeerde aantallen en codes. Websitefoto’s blijven op het apparaat.

Kan een andere website rechtstreeks vanuit de browser aanroepen?

Nee. Dat geeft 403 INVALID_ORIGIN. Gebruik je backend; geen API-sleutel nodig.

Hoe verschilt deze REST-API van MCP?

REST gebruikt HTTP-endpoints; MCP geeft AI-clients drie tools. Dezelfde engine en normen. API/MCP-foto’s gaan naar de server; de website verwerkt lokaal.