Skip to Content
Guía del vendedorIntegración de API

18. Integración de API

◀ Índice

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

  1. Crea un token de API en el panel de Inkica (se hace una sola vez).
  2. Consulta el catálogo para obtener el variant_id del producto que quieres vender (modelo de camiseta, color, talla).
  3. 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.
  4. Envía a producción — Inkica descuenta el dinero de la billetera y pasa el pedido al taller.
  5. 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

  1. Abre el menú de la cuenta (esquina inferior de la barra lateral) → API.
  2. Pulsa Crear token y ponle un nombre fácil de recordar (p. ej. “Website sync”).
  3. 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 URLhttps://api.inkica.com/api/v1
AutenticaciónHeader Authorization: Bearer ink_pat_...
FormatoJSON (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.

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=20

Tambié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_price al 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" } } ] }
CampoObligatorioNotas
external_idNo (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_methodNostandard (predeterminado), priority o express — consulta Envío rápido.
shipping_modeNoinkica (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_urlCon selfEnlace público al archivo de la etiqueta (PDF) — el taller lo descarga, lo imprime y lo pega en el paquete.
shipping_label.tracking_numberCon selfCódigo de seguimiento de esa etiqueta, máximo 128 caracteres.
shipping_label.carrierNoTransportista de la etiqueta, p. ej. USPS.
address_to.first_nameSí
address_to.countrySíCódigo de país de 2 letras, p. ej. US.
address_to.regionSíCódigo de estado/provincia, p. ej. CA. Para EE. UU. también sirve el nombre completo del estado (California).
address_to.address1SíMáximo 50 caracteres — si es más largo, pasa el resto a address2.
address_to.city, zipSí
address_to.email, phoneNo
line_itemsSíMáximo 50 líneas por pedido.
line_items[].variant_idSíSe obtiene en el paso 3.
line_items[].quantitySíDe 1 a 999.
line_items[].print_areasSí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[].mockupsNoImagen de mockup de cada posición. Si se omite, se usa el propio archivo de impresión.
line_items[].personalizationNoTexto 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" y shipping_label van juntos — enviar solo uno de los dos devuelve 400.
  • La etiqueta debe ir a la misma dirección address_to del 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_url debe 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/express devuelve 400 (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 con dry_run. En ese caso divídelo en varios pedidos, o quita shipping_mode/shipping_label para que Inkica compre la etiqueta.
  • Si cambias de idea mientras el pedido sigue en borrador: vuelve a enviar el mismo external_id sin shipping_label → el pedido vuelve a que Inkica compre la etiqueta y la etiqueta anterior se descarta.
  • La respuesta incluye "shipping_mode": "self", y shipment muestra tu etiqueta + seguimiento de inmediato. Si usas webhooks, el evento order:shipment:created de 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_production

Inkica 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 }
  • total es 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 400 que 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 id nuevo. El borrador se sustituye por el pedido definitivo, de modo que el id anterior (4821) ya no sirve. Guarda el orders[].id del 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-10023

El 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=50
statusSignificado
draftBorrador — no se ha enviado a producción, no se ha descontado dinero.
pendingEnviado; Inkica está eligiendo el taller.
in_productionEl taller lo está produciendo.
on_holdEn pausa — Inkica necesita comprobar algo más (p. ej. un problema con la dirección). Contacta con soporte si se prolonga.
shippedEntregado a la empresa de transporte — tiene código de seguimiento.
deliveredEntregado al destinatario.
cancelledCancelado.
rejectedRechazado (p. ej. el archivo de impresión no es válido) — revisa el pedido en el panel o contacta con soporte.
splitEl 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_production aproximadamente una vez por hora.

8. Cancelar el pedido

POST /v1/orders/4822/cancel

Solo 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"] }
EventoCuándo
order:updatedCambia el estado del pedido (p. ej. in_production → shipped). Incluye previous_status.
order:shipment:createdEl 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).

  • url debe ser una https:// 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 evento ping y 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:

HeaderContenido
X-Inkica-EventNombre del evento
X-Inkica-DeliveryCódigo del envío (coincide con el id del contenido)
X-Inkica-TimestampMomento del envío (Unix, en segundos)
X-Inkica-Signaturesha256= + 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 id para descartar duplicados y confía siempre en el data.order.status más reciente (o llama a GET /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 a POST /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 a GET /v1/orders para 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_id si 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ódigoSignificadoCómo resolverlo
400Los 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.
401Falta el token, es incorrecto o ha sido revocadoComprueba el header Authorization y crea un token nuevo si hace falta.
404No 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.
409El external_id ya se usó en un pedido enviado a producciónEse 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.
429Demasiadas llamadas muy seguidasEspera 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_run para comprobar un pedido sin gastar dinero.

◀ Notificaciones · Índice · Siguiente: Programa de referidos ▶

Last updated on