application/problem+json, la forma
estándar de RFC 9457:
{
"type": "urn:rfc:problem:core.forbidden",
"status": 403,
"title": "Forbidden",
"code": "core.forbidden",
"params": { "permission": "core.exports.run" },
"requestId": "5d0c2b7e-8f3a-4c61-9e2d-1b7a4f6c3e90"
}
| Campo | Qué contiene |
|---|---|
code | Qué falló, como <módulo>.<error>. Nunca cambia para el mismo problema: decide por él. |
params | Los valores que lo explican, como el permiso que le falta a la llave. Cada código tiene los suyos. |
title | Un resumen fijo del código, en inglés, igual en cada respuesta, para que lo leas mientras programas. Nunca lo muestres a tus usuarios, y nunca decidas por él. |
status | El estado HTTP, el mismo de la respuesta. Varios códigos comparten un estado. |
type | urn:rfc:problem: y el código. |
requestId | El id de esta llamada. Inclúyelo cuando nos reportes un problema. |
errors | Solo con 422 core.validation_failed: cada campo que la petición tiene mal (abajo). |
Decide por el código
La página de cada operación en la referencia de la API lista los códigos que puede responder, como la de Iniciar una exportación. Leecode, y params cuando el
código los tiene:
curl --silent "https://app.readyforcommerce.com/api/v1/orgs/$RFC_ORG_ID/core/org" \
--header "Authorization: Bearer $RFC_API_KEY" | jq '{code, params, requestId}'
import os
import requests
response = requests.get(
f"https://app.readyforcommerce.com/api/v1/orgs/{os.environ['RFC_ORG_ID']}/core/org",
headers={"Authorization": f"Bearer {os.environ['RFC_API_KEY']}"},
)
if not response.ok:
problem = response.json()
if problem["code"] == "core.forbidden":
print("A la llave le falta", problem["params"]["permission"])
else:
print(problem["code"], problem["requestId"])
<?php
$curl = curl_init('https://app.readyforcommerce.com/api/v1/orgs/' . getenv('RFC_ORG_ID') . '/core/org');
curl_setopt_array($curl, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('RFC_API_KEY')],
CURLOPT_RETURNTRANSFER => true,
]);
$body = json_decode(curl_exec($curl), true);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
if ($body['code'] === 'core.forbidden') {
echo 'A la llave le falta ' . $body['params']['permission'];
} else {
echo $body['code'] . ' ' . $body['requestId'];
}
}
const response = await fetch(
`https://app.readyforcommerce.com/api/v1/orgs/${process.env.RFC_ORG_ID}/core/org`,
{ headers: { Authorization: `Bearer ${process.env.RFC_API_KEY}` } },
);
if (!response.ok) {
const problem = await response.json();
if (problem.code === 'core.forbidden')
console.log('A la llave le falta', problem.params.permission);
else console.log(problem.code, problem.requestId);
}
Una petición con campos mal
422 core.validation_failed lista en errors cada parte de la petición que rechazó:
{
"type": "urn:rfc:problem:core.validation_failed",
"status": 422,
"title": "Validation failed",
"code": "core.validation_failed",
"requestId": "a3e1f9c2-4b7d-4e08-8a6f-2c5d9b1e7f34",
"errors": [
{
"location": "body",
"pointer": "#/name",
"code": "invalid_type",
"params": { "expected": "string" }
}
]
}
locationes la parte de la petición:body,querystring,params(la ruta) oheaders.pointeres un JSON Pointer al campo,#para la parte entera.codedice qué tiene mal, yparamssus límites, comominimumomaximum. El valor que enviaste nunca vuelve.
Los códigos comunes
Estos códigos vienen de lo que recorre cada llamada, o de un tipo de llamada que comparten muchas operaciones; la página de cada operación lista los que puede responder:| Estado | Código | Qué pasó | Qué hacer |
|---|---|---|---|
400 | core.bad_request | No se pudo leer la petición: un cuerpo que no es JSON, o un Idempotency-Key incorrecto. | Corrige la petición. |
401 | core.invalid_credential | La llave es desconocida, está anulada o vencida, o es de otra organización. | Envía una llave vigente de esta organización (Autenticación). |
403 | core.forbidden | A la llave le falta el permiso de params.permission. | Usa una llave que lo tenga: los permisos de una llave existente nunca crecen. |
403 | core.module_not_enabled | Tu organización no activó el módulo al que pertenece la operación; las conexiones de tienda necesitan catalog o pricing. | Alguien que puede activar módulos lo activa en la aplicación. |
403 | core.module_read_only | El módulo de params.module está en solo lectura: tu organización superó su cupo gratis sin tarjeta. Las lecturas, las exportaciones y las eliminaciones siguen pasando. | Alguien que gestiona la facturación agrega una tarjeta en la aplicación, o eliminar registros devuelve el uso a su cupo gratis. |
403 | core.human_only | Solo una persona hace esto, en la aplicación; params.reason dice de qué grupo de acciones. | Hazlo en la aplicación. |
404 | core.not_found, o el del módulo, como core.job_not_found | La ruta no existe, o tu organización no tiene ese registro. | Revisa la ruta y el id. |
409 | core.org_deletion_scheduled | La eliminación de la organización está programada, así que se rechaza cada llamada. | Deja de llamar. La persona dueña puede restaurar la organización en la aplicación hasta que se elimine. |
409 | core.version_conflict | Un cambio enviado con un expectedVersion que el registro ya dejó atrás: alguien lo guardó después de que lo leíste, y no se escribió nada de tu cambio. | Vuelve a leer el registro, aplica tu cambio a lo que tiene ahora y envíalo con su nueva version. |
422 | core.validation_failed | Un campo está mal; errors dice cuál. | Corrige los campos como los describe la página de la operación. |
429 | core.rate_limited | Demasiadas llamadas (Límites de uso). | Espera los segundos que dice Retry-After y vuelve a llamar. |
429 | core.job_limit_reached | Demasiados trabajos sin terminar (Límites de uso). | Espera los segundos que dice Retry-After, o a que termine un trabajo. |
500 | core.internal | Algo falló de nuestro lado. | Reintenta más tarde; si sigue, dinos el requestId. |
503 | core.unavailable, core.surface_disabled | La API no está disponible por un momento, o está en pausa para todos. | Espera los segundos que dice Retry-After y vuelve a llamar. |
Un
4xx que no sea 429 responde lo mismo hasta que cambies la petición o la llave: no lo
repitas sin cambios. Un 429 o un 503 dice cuánto esperar en Retry-After: espera ese tiempo,
nunca en un bucle sin pausa. Para repetir una escritura sin hacerla dos veces, envía un
Idempotency-Key.