Referencia
Errores y reintentos seguros
Los errores usan application/problem+json. Registra code, request_id y X-Request-Id, sin credenciales ni información personal.
Formato
Cada error trae type (la URL de su explicación en esta página), title, status, code, detail y request_id. Decide con code, no con title ni detail: el texto puede cambiar.
Errores por campo
Un INVALID_REQUEST puede incluir errors: una lista con pointer (JSON Pointer al campo), code y detail. Hoy contiene la primera infracción encontrada. El puntero es relativo al cuerpo enviado, a los parámetros de consulta o, al publicar, al producto tal como lo devuelve GET.
Códigos de campo: required, type, range, length, format, enum, unknown_field, duplicate, relation y media.
Publicar un borrador sin categoría
Solicitud · ejemplo ilustrativo
cURL
: "${MOKU_PAT:?}" &&
test "${MOKU_ALLOW_WRITES:-}" = "1" &&
curl --silent --show-error --fail-with-body \
--request POST \
'https://moku.cl/api/v1/vendors/vendor_demo_ceramica/products/product_demo_borrador/publish' \
--header "Authorization: Bearer ${MOKU_PAT}" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data-raw '{
"expected_revision": 1
}'Node.js
Módulo ES para Node.js 18 o posterior (guárdalo, por ejemplo, como ejemplo.mjs). Usa el fetch incluido, sin dependencias. No debe ejecutarse en el navegador.
const token = process.env.MOKU_PAT;
if (!token) throw new Error('MOKU_PAT');
if (process.env.MOKU_ALLOW_WRITES !== '1') throw new Error('MOKU_ALLOW_WRITES=1');
const url = new URL('https://moku.cl/api/v1/vendors/vendor_demo_ceramica/products/product_demo_borrador/publish');
const body = {
"expected_revision": 1
};
const response = await fetch(url, {
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
signal: AbortSignal.timeout(30_000),
});
const result = await response.json();
if (!response.ok) console.error(`HTTP ${response.status}`);
(response.ok ? console.log : console.error)(JSON.stringify(result, null, 2));
process.exitCode = response.ok ? 0 : 1;PHP
Ejemplo para PHP CLI con la extensión cURL. No es un plugin de WordPress ni debe ejecutarse en el navegador.
<?php
$token = getenv('MOKU_PAT');
if ($token === false || $token === '') {
throw new RuntimeException('MOKU_PAT');
}
if (getenv('MOKU_ALLOW_WRITES') !== '1') {
throw new RuntimeException('MOKU_ALLOW_WRITES=1');
}
$url = 'https://moku.cl/api/v1/vendors/vendor_demo_ceramica/products/product_demo_borrador/publish';
$body = <<<'MOKU_REQUEST_JSON'
{
"expected_revision": 1
}
MOKU_REQUEST_JSON;
$curl = curl_init($url);
if ($curl === false) {
throw new RuntimeException('curl_init');
}
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Accept: application/json',
'Authorization: Bearer ' . $token,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => $body,
]);
$response = curl_exec($curl);
if ($response === false) {
$message = curl_error($curl);
curl_close($curl);
throw new RuntimeException($message);
}
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
$result = json_decode($response, false, 512, JSON_THROW_ON_ERROR);
$failed = $status < 200 || $status >= 300;
if ($failed) {
fwrite(STDERR, "HTTP {$status}\n");
}
fwrite(
$failed ? STDERR : STDOUT,
json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR) . PHP_EOL
);
exit($failed ? 1 : 0);Respuesta 400 application/problem+json
{
"type": "https://developers.moku.cl/reference/errors/#invalid-request",
"title": "Invalid request",
"status": 400,
"code": "INVALID_REQUEST",
"detail": "The product is not ready to publish.",
"request_id": "req_00000000000000000000000000000003",
"errors": [
{
"pointer": "/category",
"code": "required",
"detail": "Choose a category before publishing."
}
]
}
Qué reintentar
| Respuesta | Acción |
|---|---|
400 | Corrige la solicitud; no reintentes igual. |
401/403 | Corrige token o scopes. |
409 | Lee el estado actual y reconcilia. |
429 | Espera Retry-After con jitter. |
500/503 | Verifica el estado y reintenta con backoff; conserva la misma clave para una escritura idéntica. |
400 · Solicitud inválida
INVALID_CURSOR · 400- Usa sin modificar el next_cursor de la página anterior y con el mismo recurso y filtros.
INVALID_MEDIA · 400- Verifica el SHA-256 y envía una imagen JPEG, PNG o WebP válida, de un solo cuadro y hasta 16 megapíxeles.
INVALID_REQUEST · 400- Corrige el cuerpo, los parámetros o las cabeceras según el esquema OpenAPI; no repitas la misma solicitud. Cuando Moku puede ubicar el problema, errors[].pointer indica el campo: una ruta dentro del cuerpo (/variations/0/price), dentro de los parámetros de consulta (/limit) o, al publicar, dentro del producto (/image_urls).
401 · Token no válido
UNAUTHENTICATED · 401- Envía un PAT válido, no vencido ni revocado en Authorization: Bearer.
403 · Permiso insuficiente
INSUFFICIENT_SCOPE · 403- Crea o usa un PAT con el bundle requerido para el endpoint.
404 · Recurso no encontrado
RESOURCE_NOT_FOUND · 404- Verifica el ID y el vendor concedido al PAT; Moku no revela recursos de otro vendedor.
409 · Conflicto de estado, versión o autoridad
Efectos de stock entre canales
STOCK_CLAIM_EXPIRED · 409- La concesión venció o cambió. Vuelve a consultar la operación y conserva cualquier comando incierto.
STOCK_EFFECT_BUSY · 409- La operación tiene una concesión vigente. Respeta Retry-After y vuelve a consultar su estado.
STOCK_EFFECT_CONFLICT · 409- Consulta la operación y verifica cuenta, autoridad, revisión y mapeo antes de continuar.
STOCK_EFFECT_VERSION_CONFLICT · 409- Vuelve a leer la versión de la operación antes de solicitar una nueva concesión.
STOCK_RECONCILIATION_REQUIRED · 409- Consulta el recibo del comando original. Un recibo ausente nunca autoriza a repetir el débito.
STOCK_SOURCE_BUSY · 409- Otra operación ocupa el mismo artículo fuente. Respeta Retry-After sin cambiar la identidad del pedido.
Inventario y reservas
INVENTORY_VERSION_CONFLICT · 409- Vuelve a leer el item, recalcula target_on_hand y reintenta con una clave nueva.
ON_HAND_BELOW_RESERVED · 409- No bajes on_hand por debajo de reserved; libera compromisos o usa una cantidad mayor.
RESERVATION_CONFLICT · 409- Vuelve a leer la reserva y no mezcles comandos de pedido externo con comandos públicos.
RESERVATION_EXPIRED · 409- Crea una reserva nueva después de refrescar disponibilidad.
RESERVATION_MANAGED_BY_EXTERNAL_ORDER · 409- Cambia el estado mediante external-orders; no renueves, consumas ni liberes la reserva directamente.
Productos e imágenes
MARKETPLACE_NOT_ACTIVE · 409- La tienda no está activa en Moku Marketplace, por lo que este producto no puede publicarse. Puedes seguir preparándolo como borrador privado.
MEDIA_QUOTA_EXCEEDED · 409- La tienda alcanzó su presupuesto de 256 MiB o 1000 imágenes, incluidas cargas pendientes. Contacta a Moku antes de agregar más; reintentar el mismo contenido no consume otra admisión.
PRODUCT_REVISION_CONFLICT · 409- Vuelve a leer el producto, fusiona cambios y reintenta con expected_revision actualizado.
PRODUCT_SLUG_CONFLICT · 409- Moku asigna las URL de los productos. Reintenta la misma solicitud; si el conflicto persiste, contacta a soporte.
PRODUCT_STATE_CONFLICT · 409- Vuelve a leer el producto y usa una transición válida para su estado actual.
SOURCE_MEDIA_NOT_READY · 409- Carga primero los bytes de la imagen privada y confirma su admisión antes de vincular su digest al producto.
SOURCE_MEDIA_SNAPSHOT_CHANGED · 409- Consulta otra vez las imágenes pendientes y recalcula los hashes de los archivos actuales. Conserva la identidad de cualquier intento incierto hasta reconciliar su recibo.
Pedidos y fulfillment
EXTERNAL_ORDER_LINES_LOCKED · 409- Conserva las líneas comerciales originales; corrige el pedido en el sistema fuente mediante una operación compatible.
EXTERNAL_ORDER_SOURCE_CONFLICT · 409- No reutilices una versión fuente para contenido diferente; envía una nueva versión y timestamp.
EXTERNAL_ORDER_STALE · 409- Descarta la observación antigua y continúa desde el último source_updated_at aceptado.
EXTERNAL_ORDER_TERMINAL · 409- No intentes reabrir un pedido terminal; consulta su estado y crea un pedido distinto si corresponde.
EXTERNAL_ORDER_TERMINAL_REVIEW_REQUIRED · 409- Resuelve primero terminal-resolution con la versión actual del pedido externo.
FULFILLMENT_REVIEW_REQUIRED · 409- Detén fulfillment y completa la revisión terminal antes de avanzar.
FULFILLMENT_STATE_CONFLICT · 409- Vuelve a leer el pedido y aplica solo la siguiente transición monotónica permitida.
FULFILLMENT_VERSION_CONFLICT · 409- Vuelve a leer fulfillment y reintenta con expected_version actualizado.
Conexiones, autoridad y listings
AUTHORITY_CONFLICT · 409- Detén escrituras, liquida reservas y pedidos pendientes, vuelve a leer la autoridad y reintenta el reemplazo de roles.
CONNECTION_STATE_CONFLICT · 409- Vuelve a leer la conexión o conflicto y reintenta con su versión actual.
LISTING_CONFLICT · 409- Vuelve a leer el listing y corrige identidad, estado o versión fuente antes de reintentar.
OBSERVATION_STALE · 409- Descarta la inspección antigua y envía una captura nueva con otra Idempotency-Key. La clave rechazada repite el mismo rechazo.
Claves de idempotencia
IDEMPOTENCY_KEY_REUSED · 409- Usa una clave nueva para trabajo distinto; conserva la clave original solo para un replay idéntico.
413 · Archivo demasiado grande
MEDIA_TOO_LARGE · 413- Reduce la imagen: tanto el archivo original como la salida normalizada deben medir hasta 2 MiB.
429 · Límite de solicitudes
Cada credencial dispone de 60 lecturas y 12 escrituras por minuto. Las respuestas incluyen RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset; un 429 agrega Retry-After.
RATE_LIMITED · 429- Espera Retry-After, agrega jitter y reduce concurrencia por PAT.
500 · Error interno
INTERNAL_ERROR · 500- Registra request_id y contacta soporte; verifica el estado antes de repetir una escritura.