18. Integración de API
La API de Inkica permite que tu propio sistema envíe pedidos a Inkica automáticamente — sin entrar en el panel para crear cada pedido a mano. Es adecuada si:
- Vendes en tu propio sitio web o en un canal que Inkica aún no tiene conectado de serie.
- Tienes una herramienta o software propio que gestiona los pedidos y quieres enviarlos directamente al taller.
- Quieres automatizarlo todo: llega el pedido → se crea el pedido en Inkica → se sigue el tracking.
Si vendes en eBay, Etsy, TikTok Shop, Shopify o Amazon, lo más sencillo es conectar tu tienda: los pedidos llegan solos y no hace falta programar. La API es para los demás casos.
Esta página está escrita tanto para ti como para el desarrollador que se encargará de la integración — puedes enviarle directamente el enlace de esta página.
Cómo funciona, en resumen
- Crea un token de API en el panel de Inkica (se hace una sola vez).
- Consulta el catálogo para obtener el
variant_iddel producto que quieres vender (modelo de camiseta, color, talla). - Crea el pedido — envía la dirección del destinatario + los archivos de impresión. El pedido se crea en estado borrador, sin descontar dinero.
- Envía a producción — Inkica descuenta el dinero de la billetera y pasa el pedido al taller.
- Sigue el pedido — lee el estado y el código de seguimiento cuando el pedido se entrega a la empresa de transporte, o registra un webhook para que Inkica te avise automáticamente.
1. Crear un token de API
- Abre el menú de la cuenta (esquina inferior de la barra lateral) → API.
- Pulsa Crear token y ponle un nombre fácil de recordar (p. ej. “Website sync”).
- Copia el token de inmediato — tiene el formato
ink_pat_...y solo se muestra una vez. Al cerrar el cuadro de diálogo ya no se puede volver a ver; lo único que puedes hacer es crear un token nuevo.
🔒 Guarda el token como si fuera una contraseña. Quien tenga el token puede crear pedidos y gastar el dinero de tu billetera. No pegues el token en código que se ejecute en el navegador, no lo envíes por chat, no lo subas a GitHub. Si sospechas que se ha filtrado, entra en Configuración → API y pulsa Revocar para revocarlo de inmediato; ese token deja de ser válido al instante.
Cada cuenta puede tener como máximo 10 tokens a la vez. Conviene crear un token distinto para cada sistema o herramienta, de modo que, si tienes que revocar uno, los demás sigan funcionando.
2. Llamar a la API
| Base URL | https://api.inkica.com/api/v1 |
| Autenticación | Header Authorization: Bearer ink_pat_... |
| Formato | JSON (Content-Type: application/json), moneda USD |
| Documentación de referencia completa (prueba la API en directo) | api.inkica.com/api/v1/docs |
Prueba rápidamente el token pidiendo la lista de productos:
curl https://api.inkica.com/api/v1/catalog/blueprints?limit=5 \
-H "Authorization: Bearer ink_pat_xxxxxxxxxxxx"Si recibes la lista de productos, el token ya funciona.
3. Elegir el producto (catálogo)
El catálogo tiene 2 niveles:
- Blueprint — el modelo de producto base, p. ej. “US Unisex Heavy Cotton Tee”.
- Variant — una combinación concreta de color × talla de ese blueprint, p. ej. Black / L. Al crear un pedido, eliges por
variant_id.
Lista de blueprints
GET /v1/catalog/blueprints?q=tee&page=1&limit=20También puedes filtrar por category (p. ej. clothing). Cada blueprint tiene id, name, product_type, imagen y print_areas — las posiciones donde se puede imprimir.
Detalle de un blueprint
GET /v1/catalog/blueprints/1{
"id": 1,
"name": "US Unisex Heavy Cotton Tee 2D",
"colors": [{ "name": "Black", "hex": "#000000" }],
"sizes": ["S", "M", "L", "XL", "2XL"],
"included_print_area": "front",
"print_areas": [
{ "position": "front", "fee": 4.2, "width": 38, "height": 58, "unit": "cm" },
{ "position": "back", "fee": 4.2, "width": 38, "height": 58, "unit": "cm" },
{ "position": "sleeve_left", "fee": 3.35, "width": 4, "height": 3.5, "unit": "inch" }
]
}print_areas[].width/height/unit— tamaño del área de impresión; úsalo para preparar el archivo de impresión con la proporción correcta.fee— cargo de impresión de esa posición.
Lista de variants (con precio)
GET /v1/catalog/blueprints/1/variants?page=1&limit=100{
"data": [
{ "id": 20139, "sku": "IUSG5000-S-ASH", "color": "ASH", "size": "S", "is_available": true, "price": 7.58 }
],
"page": 1, "limit": 100, "total": 821
}Cómo se calcula el precio: el price del variant ya incluye la impresión en 1 posición (la posición included_print_area, normalmente el frente). Si imprimes en otra posición más, se suma el cargo de impresión de esa posición. En el ejemplo anterior: imprimir el frente = $7.58; imprimir delante + detrás = $7.58 + $4.20 = $11.78.
El precio exacto de cada línea siempre aparece en
unit_priceal crear el pedido — toma ese valor como referencia.
Usa solo variants con is_available: true. Los blueprints grandes tienen cientos de variants — aumenta limit (máximo 1000) o cambia de page para obtenerlos todos.
4. Estimar el coste de envío (opcional)
Si quieres informar al cliente del coste de envío antes de hacer el pedido:
POST /v1/orders/shipping{
"line_items": [{ "variant_id": 20139, "quantity": 2 }],
"address_to": { "country": "US", "region": "CA", "zip": "90001" },
"shipping_method": "standard"
}Devuelve { "shipping": 7.39, "currency": "USD", "is_estimate": true }. Los pedidos enviados a EE. UU. requieren obligatoriamente zip.
Si envías tu propia etiqueta, añade "shipping_mode": "self" — el shipping devuelto es entonces la tarifa fija de gestión (en lugar del coste de envío), con is_estimate: false.
5. Crear el pedido
POST /v1/orders{
"external_id": "WEB-10023",
"shipping_method": "standard",
"address_to": {
"first_name": "John",
"last_name": "Smith",
"email": "john@example.com",
"phone": "+1 555 123 4567",
"country": "US",
"region": "CA",
"address1": "123 Main St",
"address2": "Apt 4",
"city": "Los Angeles",
"zip": "90001"
},
"line_items": [
{
"variant_id": 20139,
"quantity": 2,
"print_areas": {
"front": "https://your-cdn.com/designs/front.png",
"back": "https://your-cdn.com/designs/back.png"
},
"mockups": {
"front": "https://your-cdn.com/mockups/front.jpg"
}
}
]
}| Campo | Obligatorio | Notas |
|---|---|---|
external_id | No (recomendado) | Código del pedido en tu sistema, máximo 100 caracteres. Debe ser único entre tus pedidos. Si vuelves a enviar el mismo external_id de un pedido que sigue en borrador, ese borrador se actualiza en lugar de crear un pedido nuevo — es seguro si tu sistema reintenta por un fallo de red. Si el pedido ya se ha enviado a producción, ese external_id queda bloqueado (error 409), incluso si el pedido se ha dividido en -F1, -F2 — para que nunca se cree y se pague 2 veces el mismo pedido. |
shipping_method | No | standard (predeterminado), priority o express — consulta Envío rápido. |
shipping_mode | No | inkica (predeterminado — Inkica compra la etiqueta y cobra el envío) o self (tú aportas la etiqueta, solo se cobra una tarifa fija de gestión) — consulta Usar tu propia etiqueta de envío. |
shipping_label.label_url | Con self | Enlace público al archivo de la etiqueta (PDF) — el taller lo descarga, lo imprime y lo pega en el paquete. |
shipping_label.tracking_number | Con self | Código de seguimiento de esa etiqueta, máximo 128 caracteres. |
shipping_label.carrier | No | Transportista de la etiqueta, p. ej. USPS. |
address_to.first_name | Sí | |
address_to.country | Sí | Código de país de 2 letras, p. ej. US. |
address_to.region | Sí | Código de estado/provincia, p. ej. CA. Para EE. UU. también sirve el nombre completo del estado (California). |
address_to.address1 | Sí | Máximo 50 caracteres — si es más largo, pasa el resto a address2. |
address_to.city, zip | Sí | |
address_to.email, phone | No | |
line_items | Sí | Máximo 50 líneas por pedido. |
line_items[].variant_id | Sí | Se obtiene en el paso 3. |
line_items[].quantity | Sí | De 1 a 999. |
line_items[].print_areas | Sí | Archivo de impresión de cada posición: { "posición": "URL" }. La posición debe estar en los print_areas del blueprint (paso 3). Los productos con frente/espalda (camisetas, sudaderas…) necesitan al menos una de esas dos caras. La URL debe descargarse directamente como archivo de imagen original (no una página web ni una imagen de vista previa) — Inkica la descarga como prueba al crear el pedido y devuelve un error 400 si el enlace está roto o si la imagen mide menos de 600px en su lado más largo. |
line_items[].mockups | No | Imagen de mockup de cada posición. Si se omite, se usa el propio archivo de impresión. |
line_items[].personalization | No | Texto personalizado (p. ej. el nombre grabado en una joya), máximo 255 caracteres. |
Requisitos de los archivos de impresión: la URL debe ser un enlace público (https://...), descargable directamente sin iniciar sesión, y debes mantener ese mismo enlace hasta que el pedido se entregue — el taller descarga el archivo desde este enlace en el momento de producir. Archivo PNG con fondo transparente y con resolución suficiente para el tamaño del área de impresión del paso 3.
El resultado es el pedido en estado draft:
{
"id": "4821",
"external_id": "WEB-10023",
"status": "draft",
"line_items": [
{ "id": "9150", "variant_id": 20139, "sku": "IUSG5000-S-ASH", "quantity": 2, "unit_price": 11.78, "print_areas": { "front": "...", "back": "..." } }
],
"subtotal": 23.56,
"shipping": 0,
"total": 23.56,
"currency": "USD",
"shipment": null
}El borrador aún no descuenta dinero ni entra en producción. El coste de envío en este momento es siempre
0— se calcula al enviar a producción. Los pedidos creados mediante la API también aparecen en la sección Pedidos del panel, junto con el resto de pedidos.
Usar tu propia etiqueta de envío (self-ship)
¿Ya tienes una etiqueta (comprada por ti o proporcionada por el marketplace)? Envíala con el pedido — el taller imprime tu etiqueta y la pega en el paquete, e Inkica no compra etiqueta ni cobra envío; solo pagas una pequeña tarifa fija de gestión (consulta el importe exacto con POST /v1/orders/shipping o dry_run).
{
"external_id": "WEB-10024",
"shipping_mode": "self",
"shipping_label": {
"label_url": "https://your-cdn.com/labels/WEB-10024.pdf",
"tracking_number": "9400111899223197428490",
"carrier": "USPS"
},
"address_to": { "...": "..." },
"line_items": [ { "...": "..." } ]
}shipping_mode: "self"yshipping_labelvan juntos — enviar solo uno de los dos devuelve400.- La etiqueta debe ir a la misma dirección
address_todel pedido. Inkica no lee la etiqueta: una etiqueta con la dirección equivocada, caducada o ya usada envía el paquete mal, y la responsabilidad es tuya. label_urldebe poder descargarse directamente (sin iniciar sesión) y mantenerse igual hasta que se entregue el pedido, igual que los archivos de impresión.- Solo con envío estándar — combinarlo con
priority/expressdevuelve400(la velocidad la decide tu etiqueta). - Una etiqueta solo sirve para un paquete, así que todos los productos del pedido deben fabricarse en el mismo taller, y no todos los talleres aceptan etiquetas externas. Si el pedido no lo cumple, enviar a producción devuelve
400— compruébalo antes condry_run. En ese caso divídelo en varios pedidos, o quitashipping_mode/shipping_labelpara que Inkica compre la etiqueta. - Si cambias de idea mientras el pedido sigue en borrador: vuelve a enviar el mismo
external_idsinshipping_label→ el pedido vuelve a que Inkica compre la etiqueta y la etiqueta anterior se descarta. - La respuesta incluye
"shipping_mode": "self", yshipmentmuestra tu etiqueta + seguimiento de inmediato. Si usas webhooks, el eventoorder:shipment:createdde este pedido llega en cuanto se crea/envía el pedido, sin esperar a que el taller lo despache.
6. Enviar a producción
POST /v1/orders/4821/send_to_productionInkica calcula el coste de envío, descuenta el total de la billetera y pasa el pedido al taller. Si la billetera no tiene saldo suficiente, la API devuelve un error y el pedido sigue en borrador; recarga más saldo y vuelve a enviarlo.
Probar antes de enviar de verdad (dry_run)
¿Estás desarrollando la integración y no quieres gastar dinero real? Envía además "dry_run": true:
POST /v1/orders/4821/send_to_production{ "dry_run": true }Inkica ejecuta todas las comprobaciones como en un envío real — dirección, archivos de impresión, disponibilidad de stock, si hay algún taller que pueda imprimir esa posición, coste de envío — y devuelve el importe que se descontaría, pero no descuenta dinero, no produce nada y el pedido sigue siendo borrador:
{
"dry_run": true,
"orders": [
{ "external_id": "WEB-10023", "subtotal": 23.56, "shipping": 7.39, "total": 30.95 }
],
"total": 30.95,
"currency": "USD",
"wallet_balance": 26.66,
"sufficient_balance": false
}totales exactamente el importe que se descontaría si lo enviaras de verdad en ese momento.sufficient_balance: false→ la billetera no tiene saldo suficiente y el envío real se rechazaría — recarga antes.- Si el pedido tiene algún problema (sin stock, posición de impresión que no se puede producir…) → recibes exactamente el error
400que obtendrías en el envío real.
Puedes ejecutar la prueba todas las veces que quieras. Cuando todo esté bien, vuelve a enviar sin dry_run (o con "dry_run": false) para enviar a producción de verdad.
La prueba no pasa por las fases posteriores al envío (el pedido pasa a
in_production→shipped, con tracking). Para comprobar la lectura del estado/tracking, usa un pedido real pequeño — cancélalo enseguida si hace falta; el dinero se reembolsa a la billetera.
⚠️ Después de este paso el pedido tiene un
idnuevo. El borrador se sustituye por el pedido definitivo, de modo que elidanterior (4821) ya no sirve. Guarda elorders[].iddel resultado para hacer el seguimiento después:
{
"orders": [
{ "id": "4822", "external_id": "WEB-10023", "status": "in_production", "shipping": 7.39, "total": 30.95 }
]
}Normalmente orders contiene un solo pedido. Si los productos del pedido deben fabricarse en varios talleres distintos, el pedido se dividirá en varios pedidos — el external_id llevará entonces el sufijo -F1, -F2…
¿Has perdido el resultado (p. ej. se cortó la conexión a mitad)? No lo envíes otra vez — busca el pedido por external_id:
GET /v1/orders?external_id=WEB-10023El resultado incluye también las partes -F1, -F2 si el pedido se ha dividido.
7. Seguir el pedido
GET /v1/orders/4822
GET /v1/orders?status=shipped&page=1&limit=50status | Significado |
|---|---|
draft | Borrador — no se ha enviado a producción, no se ha descontado dinero. |
pending | Enviado; Inkica está eligiendo el taller. |
in_production | El taller lo está produciendo. |
on_hold | En pausa — Inkica necesita comprobar algo más (p. ej. un problema con la dirección). Contacta con soporte si se prolonga. |
shipped | Entregado a la empresa de transporte — tiene código de seguimiento. |
delivered | Entregado al destinatario. |
cancelled | Cancelado. |
rejected | Rechazado (p. ej. el archivo de impresión no es válido) — revisa el pedido en el panel o contacta con soporte. |
split | El pedido se ha dividido por taller — consulta los pedidos hijos en split_orders. |
Cuando el pedido se entrega a la empresa de transporte, el campo shipment contiene la información de seguimiento para que se la envíes al cliente:
"shipment": {
"carrier": "usps",
"tracking_number": "9400111899223456789012",
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223456789012",
"label_url": "https://cdn.inkica.com/labels/4822.pdf",
"status": "in_transit",
"delivered_at": null
}label_url es el archivo de la etiqueta (PDF) que se pega en el paquete — es null cuando el taller compra la etiqueta por su cuenta y solo devuelve el código de seguimiento. tracking_url también puede ser null; en ese caso, busca por tracking_number en la página del carrier.
En los pedidos con tu propia etiqueta, shipment es la etiqueta y el código de seguimiento que enviaste, disponibles desde que se crea el pedido.
¿Quieres que Inkica te avise automáticamente cada vez que un pedido cambie de estado o tenga tracking, en lugar de que tu sistema tenga que consultarlo continuamente? Usa un webhook. Si no usas webhooks, te sugerimos revisar los pedidos en
pending/in_productionaproximadamente una vez por hora.
8. Cancelar el pedido
POST /v1/orders/4822/cancelSolo se puede cancelar mientras el taller aún no haya empezado a producir. Los pedidos ya pagados se reembolsan a la billetera. Cancelar un borrador no tiene nada que reembolsar porque no se ha descontado dinero. Pasado el momento en que se puede cancelar, la API devuelve un error — contacta con soporte si aun así necesitas gestionarlo.
9. Webhook — recibir notificaciones automáticas
Registra una dirección (URL) en tu servidor — Inkica enviará automáticamente (POST) a esa dirección cada vez que haya un cambio, sin necesidad de consultar continuamente.
Registro
La forma más rápida: abre el menú de la cuenta → API → sección Webhooks → Añadir webhook, escribe la URL y elige los eventos. Aquí también ves el estado de cada webhook (activo / desactivado y el motivo), si el último envío fue correcto o falló, el botón Enviar prueba y el botón para eliminar.
O regístralo mediante la API:
POST /v1/webhooks{
"url": "https://your-server.com/inkica/webhooks",
"events": ["order:updated", "order:shipment:created"]
}| Evento | Cuándo |
|---|---|
order:updated | Cambia el estado del pedido (p. ej. in_production → shipped). Incluye previous_status. |
order:shipment:created | El pedido tiene código de seguimiento — ya puedes enviárselo al cliente. |
Si dejas events vacío, recibes todos. El resultado incluye un secret con el formato whsec_... — solo se muestra una vez; guárdalo para verificar la firma (más abajo).
urldebe ser unahttps://pública — no se aceptan direcciones internas (localhost, IP de red local…).- Máximo 5 webhooks por cuenta, y cada URL solo se puede registrar una vez. Ver la lista:
GET /v1/webhooks· Eliminar:DELETE /v1/webhooks/{id}. - Enviar una prueba al instante:
POST /v1/webhooks/{id}/test— Inkica envía un eventopingy devuelve el resultado (delivered,status_code,error).
Contenido que envía Inkica
{
"id": "dlv_1042",
"event": "order:updated",
"created_at": "2026-10-17T08:06:10.000Z",
"data": {
"previous_status": "in_production",
"order": { "id": "4822", "external_id": "WEB-10023", "status": "shipped", "shipment": { "tracking_number": "9400111899223456789012", "...": "..." }, "...": "..." }
}
}data.order tiene exactamente la misma estructura que GET /v1/orders/{id} — puedes reutilizar el código que ya tienes para procesar pedidos.
Tu servidor debe responder con un código 2xx en un máximo de 10 segundos. Conviene guardar el evento y responder 200 de inmediato, y procesarlo después.
Verificar la firma (muy recomendable)
Para asegurarte de que la solicitud viene de Inkica (y no de alguien que la suplanta), cada solicitud incluye estos headers:
| Header | Contenido |
|---|---|
X-Inkica-Event | Nombre del evento |
X-Inkica-Delivery | Código del envío (coincide con el id del contenido) |
X-Inkica-Timestamp | Momento del envío (Unix, en segundos) |
X-Inkica-Signature | sha256= + HMAC-SHA256 de la cadena {timestamp}.{contenido original} con el secret como clave |
Recalcula la firma sobre el contenido original (sin parsear el JSON) y compárala:
// Node.js (Express) — usa express.raw() para conservar el contenido original
const crypto = require('crypto');
app.post('/inkica/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
const ts = req.get('X-Inkica-Timestamp');
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.INKICA_WEBHOOK_SECRET)
.update(`${ts}.${req.body}`).digest('hex');
const got = req.get('X-Inkica-Signature') || '';
const valid = got.length === expected.length && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
if (!valid || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);
const event = JSON.parse(req.body);
// ... guarda el evento y procésalo después
res.sendStatus(200);
});# Python (Flask)
import hmac, hashlib, time
from flask import request, abort
@app.post("/inkica/webhooks")
def inkica_webhook():
ts = request.headers.get("X-Inkica-Timestamp", "")
body = request.get_data() # contenido original (bytes)
expected = "sha256=" + hmac.new(SECRET.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, request.headers.get("X-Inkica-Signature", "")) or abs(time.time() - int(ts or 0)) > 300:
abort(401)
event = request.get_json()
return "", 200// PHP
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_INKICA_TIMESTAMP'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $body, $secret);
if (!hash_equals($expected, $_SERVER['HTTP_X_INKICA_SIGNATURE'] ?? '') || abs(time() - (int)$ts) > 300) {
http_response_code(401); exit;
}
$event = json_decode($body, true);
http_response_code(200);Comprueba además que X-Inkica-Timestamp no tenga más de 5 minutos, para impedir que alguien reenvíe solicitudes antiguas.
Reintentos cuando hay errores
- Si tu servidor no devuelve 2xx (error, más de 10 segundos, inaccesible) → Inkica reintenta automáticamente a los 1, 5, 15 y 60 minutos, y luego a las 3, 6 y 12 horas — 8 envíos en total en aproximadamente 1 día.
- Un mismo evento puede llegar más de una vez, y los eventos pueden llegar en desorden — usa el
idpara descartar duplicados y confía siempre en eldata.order.statusmás reciente (o llama aGET /v1/orders/{id}) en lugar de suponer un orden. - Si falla de forma continua durante demasiado tiempo (20 envíos consecutivos fallidos del todo) → el webhook se desactiva solo (
active: false). Cuando arregles el servidor, pulsa Enviar prueba en la página API (menú de la cuenta) (o llama aPOST /v1/webhooks/{id}/test) — un ping correcto lo reactiva. Los cambios que ocurran mientras el webhook esté desactivado no se reenvían después — tras reactivarlo, llama aGET /v1/orderspara actualizar el estado de los pedidos que estás siguiendo. - También se notifican los pedidos que creas desde el panel o los pedidos de los marketplaces (eBay, Etsy…) — filtra por
external_idsi solo te interesan los pedidos creados mediante la API.
Errores frecuentes
Cuando hay un error, la API devuelve un código HTTP con la explicación en message:
{ "statusCode": 400, "error": "Bad Request", "message": "line_items[0].print_areas: this blueprint has no \"hood\" print position" }| Código | Significado | Cómo resolverlo |
|---|---|---|
400 | Los datos enviados son incorrectos o incompletos, o no se puede realizar la operación (saldo insuficiente, el pedido ya no se puede cancelar…) | Lee message — en los errores de validación de datos, message puede ser una lista con varios errores. Corrige y vuelve a enviar. |
401 | Falta el token, es incorrecto o ha sido revocado | Comprueba el header Authorization y crea un token nuevo si hace falta. |
404 | No se encuentra (id incorrecto, pedido de otra cuenta, o el id del borrador que se sustituyó tras enviar a producción) | Revisa el id, o busca por external_id. |
409 | El external_id ya se usó en un pedido enviado a producción | Ese pedido ya existe — búscalo con GET /v1/orders?external_id=... en lugar de crear uno nuevo. Si realmente es otro pedido, usa otro external_id. |
429 | Demasiadas llamadas muy seguidas | Espera 1 minuto y vuelve a llamar. |
Límites
- 600 llamadas / minuto.
- Máximo 50 líneas de producto por pedido, 10 tokens por cuenta.
- Solo se pueden crear pedidos a partir del catálogo de Inkica (por
variant_id); los productos que ya has creado en la sección Productos todavía no se pueden usar directamente mediante la API. - Máximo 5 webhooks por cuenta.
- Todavía no hay un entorno de pruebas independiente — usa
dry_runpara comprobar un pedido sin gastar dinero.
◀ Notificaciones · Índice · Siguiente: Programa de referidos ▶