API gratuita per la centratura carte: PSA e foto
Centering Lab è un’API REST gratuita per la centratura delle carte, senza chiave API. Su https://centeringlab.com/api/v1 restituisce misure da foto, rapporti e tetti PSA, BGS, CGC o SGC basati sulla sola centratura. Non prevede il voto finale né autentica carte. Chiamala dal tuo server. OpenAPI.
Avvio rapido
Esegui questo curl nel terminale. Il fronte ha entrambi gli assi; manca il retro, quindi incomplete è true. PSA 10 è un tetto dalla centratura fornita, non una previsione del voto finale.
POST /api/v1/grade
Richiesta
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"}'Risposta HTTP 200
Estratto da una risposta HTTP reale locale; campi omessi e altre fasce non sono mostrati. Chiavi JSON e messaggi del server restano in inglese.
{
"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."
}Endpoint e campi
Rapporti di centratura noti
POST /grade richiede almeno uno fra front_lr, front_tb, back_lr, back_tb. I valori sono normalizzati al lato maggiore. Sono ammessi una percentuale come 55, una frazione come 0.55, coppie con somma 100 (55/45) o 1 (0.55/0.45). Separatori: /, -, –, —, :, x e spazi; % facoltativo. Lo scalare 1 è ambiguo e rifiutato. Suffissi L/R o left/right solo su *_lr; T/B o top/bottom solo su *_tb.
house filtra facoltativamente PSA, BGS, CGC o SGC. normalizations dichiara le conversioni delle frazioni. missing_axes, missing_faces e incomplete segnalano dati mancanti: assi o altra faccia possono abbassare il tetto. combined combina le facce fornite; limiting_face e limiting_axis identificano il vincolo. Ogni tetto include stato e fonti.
Campi del contratto (nomi JSON esatti)
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, disclaimerCampi del contratto (nomi JSON esatti)
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, verificationMisura di una fotografia
POST /measure richiede face: front o back. card_size predefinito è standard (63×88 mm); small è 59×86 mm. Fornisci esattamente una sorgente: image_url HTTPS pubblico sulla porta 443 oppure image_base64 grezzo senza prefisso data-URL. Indirizzi privati, credenziali e risposte non immagine sono rifiutati, anche nei redirect. REST accetta anche un elemento openaiFileIdRefs fornito dal runtime GPT Actions; nelle integrazioni ordinarie usa URL o base64. JPG, PNG e WebP sono scelte pratiche; invia un raster a fotogramma singolo.
Il detector può rispondere HTTP 200 con status ok, needs-review o failed. Solo ok espone ceilings. Controlla code, confidence, warnings, lr e tb; uncertainty_pp e sigma_pp sono in punti percentuali e stations_major_percent contiene i rapporti campionati. Un risultato incerto richiede una nuova foto o verifica manuale su adjust_url. L’esempio invia deliberatamente una piccola immagine uniforme: non viene trovata alcuna carta. È un fallimento reale, non una dimostrazione di misura riuscita.
Campi del contratto (nomi JSON esatti)
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, disclaimerPOST /api/v1/measure
Richiesta
curl --fail-with-body 'https://centeringlab.com/api/v1/measure' \
-H 'Content-Type: application/json' \
--data '{"face":"front","card_size":"standard","image_base64":"iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAAD0lEQVQImWNQwAEYhpYEAGFPGAHjXOFDAAAAAElFTkSuQmCC"}'Risposta HTTP 200
Estratto da una risposta HTTP reale locale; campi omessi e altre fasce non sono mostrati. Chiavi JSON e messaggi del server restano in inglese.
{
"status": "failed",
"code": "NO_CARD",
"face": "front",
"card_size": "standard",
"lr": null,
"tb": null,
"confidence": null,
"warnings": [],
"ceilings": null,
"adjust_url": "https://centeringlab.com/"
}Per una fotografia, salva l’immagine come card.jpg ed esegui quanto segue. La risposta è stata catturata con la foto demo del sito: l’incertezza attiva needs-review e ceilings è null. La tua foto restituirà le proprie misure.
POST /api/v1/measure
Richiesta
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.jsonRisposta HTTP 200
Estratto da una risposta HTTP reale locale; campi omessi e altre fasce non sono mostrati. Chiavi JSON e messaggi del server restano in inglese.
{
"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/"
}Standard pubblicati e fonti
GET /standards accetta query facoltative house e face. official, interpreted e approximate descrivono le prove, non garanzie di accuratezza. bands[].status riguarda la singola fascia; source, sources, verified e verification ne dichiarano la provenienza. TAG è escluso. SGC non pubblica una tabella di centratura del retro: le fasce del retro sono vuote e il solo retro non stabilisce un tetto SGC. Conserva questa distinzione nell’interfaccia.
Campi del contratto (nomi JSON esatti)
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, disclaimerGET /api/v1/standards?house=PSA&face=front
Richiesta
curl --fail-with-body 'https://centeringlab.com/api/v1/standards?house=PSA&face=front'Risposta HTTP 200
Estratto da una risposta HTTP reale locale; campi omessi e altre fasce non sono mostrati. Chiavi JSON e messaggi del server restano in inglese.
{
"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."
}Stato e schema leggibile dalle macchine
GET /health restituisce stato, nome, versione e disclaimer. GET /openapi.json restituisce OpenAPI 3.1.0. Lo schema della richiesta di misura è orientato a GPT Actions (URL o riferimento file runtime); REST accetta anche base64 grezzo come descritto qui. Per integrare byte usa l’elenco esatto dei campi REST sopra.
GET /api/v1/health
Richiesta
curl --fail-with-body 'https://centeringlab.com/api/v1/health'Risposta HTTP 200
Estratto da una risposta HTTP reale locale; campi omessi e altre fasce non sono mostrati. Chiavi JSON e messaggi del server restano in inglese.
{
"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
Richiesta
curl --fail-with-body 'https://centeringlab.com/api/v1/openapi.json'Risposta HTTP 200
Estratto da una risposta HTTP reale locale; campi omessi e altre fasce non sono mostrati. Chiavi JSON e messaggi del server restano in inglese.
{
"openapi": "3.1.0",
"info": {
"title": "Centering Lab API",
"version": "1.1.2"
},
"servers": [
{
"url": "https://centeringlab.com"
}
]
}JavaScript e Python
Usa fetch lato server in Node, non uno script nel browser di un altro sito. Gli esempi inviano la stessa richiesta dell’avvio rapido. Python usa la libreria standard e non richiede pacchetti aggiuntivi. Verifica gli errori HTTP prima di usare i tetti; per le foto controlla anche status con 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))
raiseErrori e nuovi tentativi
Gli errori HTTP contengono status, code, message e disclaimer. La tabella copre trasporto e servizio REST; errori di protocollo MCP e statistiche private sono fuori da questo contratto. UNSUPPORTED_ENCODING è 415 per JSON compresso, 400 per risposte immagine compresse. I codici del detector arrivano con HTTP 200 e sono elencati a parte.
| Codice | HTTP | Significato | Cosa fare |
|---|---|---|---|
BODY_TOO_LARGE | 413 | Dimensione eccessiva | Riduci byte o pixel; il base64 conta anche nel limite del corpo JSON. |
EMPTY_IMAGE | 400 | Immagine non decodificabile | Invia un solo raster supportato, preferibilmente JPG, PNG o WebP; togli il prefisso data-URL dal base64. |
IMAGE_DNS_FAILED | 400 | URL immagine rifiutato o irraggiungibile | Usa un’immagine HTTPS pubblica sulla porta 443 senza credenziali; verifica DNS, redirect e risposta. |
IMAGE_DOWNLOAD_FAILED | 400 | URL immagine rifiutato o irraggiungibile | Usa un’immagine HTTPS pubblica sulla porta 443 senza credenziali; verifica DNS, redirect e risposta. |
IMAGE_DOWNLOAD_TIMEOUT | 504 | Tempo massimo superato | Prova un’immagine più piccola o un host più rapido; se serve usa il sito. |
IMAGE_REDIRECT_LIMIT | 400 | URL immagine rifiutato o irraggiungibile | Usa un’immagine HTTPS pubblica sulla porta 443 senza credenziali; verifica DNS, redirect e risposta. |
IMAGE_TOO_LARGE | 413 | Dimensione eccessiva | Riduci byte o pixel; il base64 conta anche nel limite del corpo JSON. |
IMAGE_TOO_MANY_PIXELS | 413 | Dimensione eccessiva | Riduci byte o pixel; il base64 conta anche nel limite del corpo JSON. |
INTERNAL_ERROR | 500 | Errore del server o worker | Riprova con attese crescenti, riduci la foto oppure usa il sito. |
INVALID_ARGUMENTS | 400 | Richiesta o rapporto non valido | Correggi i campi indicati; invia JSON valido e non compresso. |
INVALID_BASE64 | 400 | Immagine non decodificabile | Invia un solo raster supportato, preferibilmente JPG, PNG o WebP; togli il prefisso data-URL dal base64. |
INVALID_BODY | 400 | Richiesta o rapporto non valido | Correggi i campi indicati; invia JSON valido e non compresso. |
INVALID_HOST | 403 | Host o origine browser rifiutati | Chiama centeringlab.com dal tuo server; evita il browser di un altro sito. |
INVALID_HTTP | 400 | Richiesta o rapporto non valido | Correggi i campi indicati; invia JSON valido e non compresso. |
INVALID_IMAGE | 400 | Immagine non decodificabile | Invia un solo raster supportato, preferibilmente JPG, PNG o WebP; togli il prefisso data-URL dal base64. |
INVALID_IMAGE_URL | 400 | URL immagine rifiutato o irraggiungibile | Usa un’immagine HTTPS pubblica sulla porta 443 senza credenziali; verifica DNS, redirect e risposta. |
INVALID_INPUT | 400 | Richiesta o rapporto non valido | Correggi i campi indicati; invia JSON valido e non compresso. |
INVALID_JSON | 400 | Richiesta o rapporto non valido | Correggi i campi indicati; invia JSON valido e non compresso. |
INVALID_ORIGIN | 403 | Host o origine browser rifiutati | Chiama centeringlab.com dal tuo server; evita il browser di un altro sito. |
INVALID_RATIO | 400 | Richiesta o rapporto non valido | Correggi i campi indicati; invia JSON valido e non compresso. |
JSON_REQUIRED | 415 | Richiesta o rapporto non valido | Correggi i campi indicati; invia JSON valido e non compresso. |
MEASURE_QUEUE_FULL | 503 | Servizio saturo | Attendi Retry-After e riprova con attese crescenti. |
MEASURE_TIMEOUT | 504 | Tempo massimo superato | Prova un’immagine più piccola o un host più rapido; se serve usa il sito. |
MEASURE_WORKER_FAILED | 500 | Errore del server o worker | Riprova con attese crescenti, riduci la foto oppure usa il sito. |
METHOD_NOT_ALLOWED | 405 | Rotta o metodo non disponibile | Usa endpoint e metodo elencati qui. |
NOT_AN_IMAGE | 400 | URL immagine rifiutato o irraggiungibile | Usa un’immagine HTTPS pubblica sulla porta 443 senza credenziali; verifica DNS, redirect e risposta. |
NOT_FOUND | 404 | Rotta o metodo non disponibile | Usa endpoint e metodo elencati qui. |
RATE_LIMIT_CAPACITY | 503 | Servizio saturo | Attendi Retry-After e riprova con attese crescenti. |
RATE_LIMIT_DAY | 429 | Quota di richieste raggiunta | Attendi Retry-After (secondi); la quota giornaliera si azzera a mezzanotte UTC. |
RATE_LIMIT_MINUTE | 429 | Quota di richieste raggiunta | Attendi Retry-After (secondi); la quota giornaliera si azzera a mezzanotte UTC. |
REQUEST_CANCELLED | 499 | Richiesta annullata | Riprova solo se il client ha ancora bisogno del risultato. |
REQUEST_CAPACITY | 503 | Servizio saturo | Attendi Retry-After e riprova con attese crescenti. |
UNSAFE_IMAGE_URL | 400 | URL immagine rifiutato o irraggiungibile | Usa un’immagine HTTPS pubblica sulla porta 443 senza credenziali; verifica DNS, redirect e risposta. |
UNSUPPORTED_ENCODING | 400 / 415 | Richiesta o rapporto non valido | Correggi i campi indicati; invia JSON valido e non compresso. |
UNSUPPORTED_IMAGE | 400 | Immagine non decodificabile | Invia un solo raster supportato, preferibilmente JPG, PNG o WebP; togli il prefisso data-URL dal base64. |
Esiti del detector: HIGH_UNCERTAINTY, NEEDS_REVIEW, LOW_CONFIDENCE, NO_MEASUREMENT, NO_CARD, CARD_TOO_SMALL, CARD_CUT_OFF, NO_PRINTED_BORDER. Un esito failed o needs-review non ha tetti di grading. Rifai una foto della carta intera dall’alto, senza sleeve, su fondo scuro e piano, oppure usa l’editor manuale del sito. Non presentare un rapporto incerto come voto finale.
Limiti di utilizzo
Le quote sono per IP e condivise con i rispettivi bucket del motore/protocollo. Grade e standards condividono un bucket al minuto; health e OpenAPI un altro. Le finestre sono minuti fissi e giorni UTC. Il limiter attuale non ha quote giornaliere per richieste semplici/protocollo. Il base64 espande i byte e conta nel corpo JSON: l’intero limite dell’immagine potrebbe non entrare in una richiesta base64.
| Limite | Valore attuale |
|---|---|
POST /measure · IP | 20 al minuto; 200 al giorno UTC |
POST /grade + GET /standards · IP | 120 al minuto; Nessuna quota giornaliera nel limiter |
GET /health + GET /openapi.json · IP | 120 al minuto; Nessuna quota giornaliera nel limiter |
Corpo JSON | 12 MiB (12582912 bytes) |
Byte dell’immagine decodificata | 15 MiB (15728640 bytes) |
Pixel decodificati (tutti i fotogrammi) | 40000000 |
Misura, coda inclusa | 15 s |
Download immagine | 10 s |
Misure attive | 2 |
Misure in coda | 8 |
Richieste HTTP in corso | 16 |
Le risposte 429 e 503 per capacità includono Retry-After in secondi. Coda misura piena e REQUEST_CAPACITY usano 5 secondi; capacità del limiter 60 secondi. Rispetta l’header con attese crescenti. La capacità è condivisa dal servizio, non riservata al client. Nessuna disponibilità, tempo di risposta o SLA promessi.
Browser, CORS e privacy
Una chiamata dal browser di un altro sito oggi riceve 403 INVALID_ORIGIN: usa il tuo backend. Non serve una chiave API e aggiungerne una non sblocca le chiamate browser cross-origin. Non costruire un’integrazione solo client contando su CORS permissivo.
Le immagini API arrivano al server, sono elaborate solo in memoria e non sono salvate su disco. Il sito elabora invece le foto sul dispositivo. Nessun log per richiesta: solo conteggi aggregati per endpoint/tool e codice d’esito. Privacy e termini descrivono la politica esistente.
MCP e approfondimenti
I client AI possono usare https://centeringlab.com/mcp: gli stessi tre strumenti e lo stesso motore di centratura. MCP presenta gli strumenti agli assistenti; REST offre chiamate HTTP dirette per la tua applicazione. Leggi AI e configurazione MCP, come funziona la misura e chi siamo.
Domande sull’API
L’API di centratura carte è gratuita per sviluppatori?
Sì. Tutti gli endpoint API di Centering Lab sono gratuiti, senza account o piani a pagamento. Si applicano limiti d’uso; il risultato è un tetto di centratura, non autenticazione o previsione del voto finale.
Serve una chiave per le integrazioni REST?
No. Invia richieste valide dal tuo server agli endpoint documentati; resta applicato il vincolo attuale sulle origini browser.
Quali quote ha l’API di centratura carte?
La misura foto ammette 20 chiamate al minuto e 200 al giorno UTC per IP. Grade e standards condividono 120 chiamate al minuto per IP. Rispetta Retry-After e i limiti di corpo, immagine, pixel e capacità indicati sopra.
L’API REST salva le fotografie inviate?
No. Le foto arrivano al server ma sono elaborate solo in memoria. Nessun log per richiesta; solo conteggi aggregati di utilizzo e codici d’esito. Le foto del sito sono elaborate sul dispositivo.
Un altro sito può chiamare questa API direttamente dal browser?
No. Il controllo attuale restituisce 403 INVALID_ORIGIN per il browser di un altro sito. Chiama l’API dal backend, senza bisogno di chiave API.
Come si differenzia questa API REST dall’endpoint MCP?
REST usa endpoint HTTP diretti; MCP espone tre strumenti ai client AI. Entrambi usano lo stesso motore e gli stessi standard. Le immagini API e MCP arrivano al server; il sito le elabora localmente.
Centering Lab · Aggiornato il