Bezpłatne API centrowania kart: PSA i pomiar zdjęć

Centering Lab to bezpłatne REST API centrowania kart, bez klucza API. Pod https://centeringlab.com/api/v1 zwraca pomiary zdjęć, proporcje oraz limity PSA, BGS, CGC i SGC wynikające wyłącznie z centrowania. Nie przewiduje oceny końcowej ani nie potwierdza autentyczności kart. Wywołuj je ze swojego serwera. Zdjęcia API trafiają na serwer. OpenAPI.

Szybki start

Uruchom curl w terminalu. Podano obie osie przodu, ale brak tyłu: incomplete ma wartość true. PSA 10 to limit centrowania, nie przewidywanie oceny końcowej.

POST /api/v1/grade

Żądanie

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"}'

Odpowiedź HTTP 200

Fragment rzeczywistej lokalnej odpowiedzi HTTP; pominięto pola i dodatkowe progi. Klucze JSON i komunikaty serwera pozostają po angielsku.

{
  "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."
}

Endpointy i pola

Znane proporcje

POST /grade wymaga przynajmniej jednego z front_lr, front_tb, back_lr, back_tb. Normalizuje do większej strony. Obsługuje procenty (55), ułamki (0.55) i pary sumujące się do 100 (55/45) lub 1 (0.55/0.45). Separatory: /, -, –, —, :, x i spacje; % opcjonalnie. Pojedyncze 1 jest niejednoznaczne i odrzucane. L/R lub left/right tylko dla *_lr; T/B lub top/bottom tylko dla *_tb.

house filtruje PSA, BGS, CGC lub SGC. normalizations wskazuje przeliczenia ułamków. missing_axes, missing_faces i incomplete oznaczają braki, które mogą obniżyć limit. combined łączy strony; limiting_face i limiting_axis wskazują ograniczenie. Każdy limit zawiera źródła i status dowodów.

Pola kontraktu (dokładne nazwy JSON)

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

Pola kontraktu (dokładne nazwy JSON)

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

Pomiar zdjęcia

POST /measure wymaga face: front lub back. Domyślny card_size to standard (63×88 mm); small to 59×86 mm. Dokładnie jedno źródło: publiczny HTTPS image_url na porcie 443 albo image_base64 bez prefiksu data-URL. Prywatne adresy, dane logowania i odpowiedzi niebędące obrazem są odrzucane także w przekierowaniach. REST akceptuje też jeden openaiFileIdRefs od runtime GPT Actions; zwykłe integracje korzystają z URL lub base64. Wyślij pojedynczą klatkę rastrową, najlepiej JPG, PNG lub WebP.

HTTP 200 może mieć status ok, needs-review lub failed; tylko ok zawiera ceilings. Sprawdź code, confidence, warnings, lr i tb. uncertainty_pp i sigma_pp są w punktach procentowych; stations_major_percent zawiera próbki. Przy niepewności zrób nowe zdjęcie lub sprawdź adjust_url. Przykład celowo wysyła mały jednolity obraz: NO_CARD to rzeczywista porażka, nie udany pomiar.

Pola kontraktu (dokładne nazwy JSON)

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

Żądanie

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

Odpowiedź HTTP 200

Fragment rzeczywistej lokalnej odpowiedzi HTTP; pominięto pola i dodatkowe progi. Klucze JSON i komunikaty serwera pozostają po angielsku.

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

Zapisz zdjęcie jako card.jpg. Ta odpowiedź używa zdjęcia demonstracyjnego strony: niepewność powoduje needs-review, a ceilings to null. Twoje zdjęcie da własne pomiary.

POST /api/v1/measure

Żądanie

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

Odpowiedź HTTP 200

Fragment rzeczywistej lokalnej odpowiedzi HTTP; pominięto pola i dodatkowe progi. Klucze JSON i komunikaty serwera pozostają po angielsku.

{
  "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/"
}

Standardy i źródła

GET /standards przyjmuje opcjonalne house i face. official, interpreted i approximate opisują dowody, nie gwarancje dokładności. bands[].status dotyczy progu; source, sources, verified i verification podają pochodzenie. TAG jest wykluczony. SGC nie publikuje tabeli centrowania tyłu: progi są puste, a sam tył nie określa limitu SGC.

Pola kontraktu (dokładne nazwy JSON)

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

Żądanie

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

Odpowiedź HTTP 200

Fragment rzeczywistej lokalnej odpowiedzi HTTP; pominięto pola i dodatkowe progi. Klucze JSON i komunikaty serwera pozostają po angielsku.

{
  "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."
}

Stan i schemat

GET /health zwraca stan, nazwę, wersję i disclaimer. GET /openapi.json zwraca OpenAPI 3.1.0. Schemat pomiaru służy GPT Actions (URL lub referencja pliku runtime); REST przyjmuje też base64 według pól powyżej.

GET /api/v1/health

Żądanie

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

Odpowiedź HTTP 200

Fragment rzeczywistej lokalnej odpowiedzi HTTP; pominięto pola i dodatkowe progi. Klucze JSON i komunikaty serwera pozostają po angielsku.

{
  "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

Żądanie

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

Odpowiedź HTTP 200

Fragment rzeczywistej lokalnej odpowiedzi HTTP; pominięto pola i dodatkowe progi. Klucze JSON i komunikaty serwera pozostają po angielsku.

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

JavaScript i Python

Używaj fetch w Node po stronie serwera. Przykłady wysyłają żądanie ze szybkiego startu. Python korzysta z biblioteki standardowej. Sprawdzaj błędy HTTP oraz status pomiaru także przy 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

Błędy i ponawianie

Błędy HTTP zawierają status, code, message i disclaimer. Tabela obejmuje REST, bez błędów protokołu MCP i prywatnych statystyk. UNSUPPORTED_ENCODING to 415 dla skompresowanego JSON i 400 dla skompresowanej odpowiedzi obrazu. Kody detektora przychodzą z HTTP 200.

KodHTTPZnaczenieCo zrobić
BODY_TOO_LARGE413Przekroczony rozmiarZmniejsz bajty lub piksele; base64 wlicza się w limit treści JSON.
EMPTY_IMAGE400Nie można zdekodować obrazuWyślij pojedynczy obsługiwany raster, najlepiej JPG, PNG lub WebP; usuń prefiks data-URL z base64.
IMAGE_DNS_FAILED400URL odrzucony lub niedostępnyUżyj publicznego obrazu HTTPS na porcie 443 bez danych logowania; sprawdź DNS, przekierowania i odpowiedź.
IMAGE_DOWNLOAD_FAILED400URL odrzucony lub niedostępnyUżyj publicznego obrazu HTTPS na porcie 443 bez danych logowania; sprawdź DNS, przekierowania i odpowiedź.
IMAGE_DOWNLOAD_TIMEOUT504Przekroczony czasUżyj mniejszego obrazu lub szybszego hosta; ewentualnie skorzystaj ze strony.
IMAGE_REDIRECT_LIMIT400URL odrzucony lub niedostępnyUżyj publicznego obrazu HTTPS na porcie 443 bez danych logowania; sprawdź DNS, przekierowania i odpowiedź.
IMAGE_TOO_LARGE413Przekroczony rozmiarZmniejsz bajty lub piksele; base64 wlicza się w limit treści JSON.
IMAGE_TOO_MANY_PIXELS413Przekroczony rozmiarZmniejsz bajty lub piksele; base64 wlicza się w limit treści JSON.
INTERNAL_ERROR500Błąd serwera lub workeraPoczekaj, zmniejsz zdjęcie lub użyj strony.
INVALID_ARGUMENTS400Nieprawidłowe żądanie lub proporcjaPopraw pola; wyślij prawidłowy nieskompresowany JSON.
INVALID_BASE64400Nie można zdekodować obrazuWyślij pojedynczy obsługiwany raster, najlepiej JPG, PNG lub WebP; usuń prefiks data-URL z base64.
INVALID_BODY400Nieprawidłowe żądanie lub proporcjaPopraw pola; wyślij prawidłowy nieskompresowany JSON.
INVALID_HOST403Odrzucony host lub originWywołuj centeringlab.com ze swojego serwera, nie z przeglądarki innej strony.
INVALID_HTTP400Nieprawidłowe żądanie lub proporcjaPopraw pola; wyślij prawidłowy nieskompresowany JSON.
INVALID_IMAGE400Nie można zdekodować obrazuWyślij pojedynczy obsługiwany raster, najlepiej JPG, PNG lub WebP; usuń prefiks data-URL z base64.
INVALID_IMAGE_URL400URL odrzucony lub niedostępnyUżyj publicznego obrazu HTTPS na porcie 443 bez danych logowania; sprawdź DNS, przekierowania i odpowiedź.
INVALID_INPUT400Nieprawidłowe żądanie lub proporcjaPopraw pola; wyślij prawidłowy nieskompresowany JSON.
INVALID_JSON400Nieprawidłowe żądanie lub proporcjaPopraw pola; wyślij prawidłowy nieskompresowany JSON.
INVALID_ORIGIN403Odrzucony host lub originWywołuj centeringlab.com ze swojego serwera, nie z przeglądarki innej strony.
INVALID_RATIO400Nieprawidłowe żądanie lub proporcjaPopraw pola; wyślij prawidłowy nieskompresowany JSON.
JSON_REQUIRED415Nieprawidłowe żądanie lub proporcjaPopraw pola; wyślij prawidłowy nieskompresowany JSON.
MEASURE_QUEUE_FULL503Usługa zajętaPrzestrzegaj Retry-After i zwiększaj odstępy między próbami.
MEASURE_TIMEOUT504Przekroczony czasUżyj mniejszego obrazu lub szybszego hosta; ewentualnie skorzystaj ze strony.
MEASURE_WORKER_FAILED500Błąd serwera lub workeraPoczekaj, zmniejsz zdjęcie lub użyj strony.
METHOD_NOT_ALLOWED405Niedostępna ścieżka lub metodaUżyj opisanych endpointów i metod.
NOT_AN_IMAGE400URL odrzucony lub niedostępnyUżyj publicznego obrazu HTTPS na porcie 443 bez danych logowania; sprawdź DNS, przekierowania i odpowiedź.
NOT_FOUND404Niedostępna ścieżka lub metodaUżyj opisanych endpointów i metod.
RATE_LIMIT_CAPACITY503Usługa zajętaPrzestrzegaj Retry-After i zwiększaj odstępy między próbami.
RATE_LIMIT_DAY429Wyczerpany limit żądańPoczekaj Retry-After sekund; limit dzienny odnawia się o północy UTC.
RATE_LIMIT_MINUTE429Wyczerpany limit żądańPoczekaj Retry-After sekund; limit dzienny odnawia się o północy UTC.
REQUEST_CANCELLED499Anulowane żądaniePonów tylko jeśli wynik jest nadal potrzebny.
REQUEST_CAPACITY503Usługa zajętaPrzestrzegaj Retry-After i zwiększaj odstępy między próbami.
UNSAFE_IMAGE_URL400URL odrzucony lub niedostępnyUżyj publicznego obrazu HTTPS na porcie 443 bez danych logowania; sprawdź DNS, przekierowania i odpowiedź.
UNSUPPORTED_ENCODING400 / 415Nieprawidłowe żądanie lub proporcjaPopraw pola; wyślij prawidłowy nieskompresowany JSON.
UNSUPPORTED_IMAGE400Nie można zdekodować obrazuWyślij pojedynczy obsługiwany raster, najlepiej JPG, PNG lub WebP; usuń prefiks data-URL z base64.

Kody detektora: HIGH_UNCERTAINTY, NEEDS_REVIEW, LOW_CONFIDENCE, NO_MEASUREMENT, NO_CARD, CARD_TOO_SMALL, CARD_CUT_OFF, NO_PRINTED_BORDER. failed i needs-review nie zawierają limitów gradingu. Fotografuj całą kartę z góry, bez koszulki, na ciemnej płaskiej powierzchni albo użyj ręcznego edytora strony.

Limity użycia

Limity są na IP, współdzielone w odpowiednich grupach. Grade i standards dzielą licznik minutowy; health i OpenAPI drugi. Stałe okna minutowe i dni UTC; brak limitu dziennego dla prostych/protokolarnych wywołań. Base64 zwiększa bajty i wlicza się w JSON: cały limit obrazu może się nie zmieścić.

LimitAktualna wartość
POST /measure · IP20 na minutę; 200 na dzień UTC
POST /grade + GET /standards · IP120 na minutę; Brak limitu dziennego w limiterze
GET /health + GET /openapi.json · IP120 na minutę; Brak limitu dziennego w limiterze
Treść JSON12 MiB (12582912 bytes)
Bajty zdekodowanego obrazu15 MiB (15728640 bytes)
Zdekodowane piksele (wszystkie klatki)40000000
Pomiar wraz z kolejką15 s
Pobieranie obrazu10 s
Aktywne pomiary2
Pomiary w kolejce8
Trwające żądania HTTP16

429 i 503 pojemności zawierają Retry-After w sekundach. Pełna kolejka pomiaru i REQUEST_CAPACITY: 5 sekund; pojemność limitera: 60. Przestrzegaj nagłówka, zwiększając przerwy. Pojemność współdzielona bez rezerwacji dla klienta i bez SLA dostępności lub czasu odpowiedzi.

Przeglądarka, CORS i prywatność

Przeglądarka innej strony dostaje 403 INVALID_ORIGIN: użyj backendu. Klucz nie jest potrzebny i nie otwiera CORS. Zdjęcia API trafiają na serwer, są przetwarzane tylko w pamięci i nie trafiają na dysk. Strona przetwarza lokalnie. Brak logów pojedynczych żądań: tylko zagregowane liczniki według endpointu/tool i kodu wyniku. Prywatność i regulamin.

MCP i dalsze informacje

https://centeringlab.com/mcp daje klientom AI te same trzy narzędzia i silnik. REST oferuje bezpośrednie wywołania HTTP. Zobacz AI i MCP, jak działa pomiar i o Centering Lab.

Pytania o API

Czy API centrowania kart jest bezpłatne dla programistów?

Tak. Wszystkie endpointy są bezpłatne, bez konta i płatnego planu. Obowiązują limity; API nie potwierdza autentyczności ani nie przewiduje oceny końcowej.

Czy integracje REST potrzebują klucza API?

Nie. Wysyłaj prawidłowe żądania ze swojego serwera; ograniczenie origin przeglądarki nadal obowiązuje.

Jakie limity ma to API centrowania?

Pomiar: 20 na minutę i 200 na dzień UTC na IP. Grade i standards dzielą 120 na minutę na IP. Przestrzegaj Retry-After oraz limitów rozmiaru i pojemności.

Czy REST API zapisuje przesłane zdjęcia?

Nie. Trafiają na serwer, ale są przetwarzane tylko w pamięci. Brak logów żądań, tylko zagregowane liczniki i kody. Zdjęcia strony zostają na urządzeniu.

Czy inna strona może wywołać API bezpośrednio z przeglądarki?

Nie. Otrzyma 403 INVALID_ORIGIN. Wywołuj ze swojego backendu, bez klucza API.

Czym różni się to REST API od MCP?

REST używa endpointów HTTP; MCP oferuje trzy narzędzia klientom AI. Wspólny silnik i standardy. API/MCP przetwarzają zdjęcia na serwerze, strona lokalnie.