Para Developers

Una API que ya conoce la ley

Integra facturación compliant con Verifactu en tu producto con una sola llamada REST.Nosotros calculamos los impuestos, numeramos por serie y registramos cada factura con su huella encadenada; con VERI*FACTU activado la enviamos a la AEAT y el PDF lleva el QR de verificación.

  • REST API con autenticación por API Key
  • Webhooks para estado de facturas en tiempo real
  • SDKs para Node.js, Python y PHP (próximamente)
  • Entorno sandbox para pruebas sin coste
  • Rate limit: 300 lecturas cada 5 min y 20 escrituras por minuto
crear-factura.http
1// POST https://www.chiklin.com/api/v1/invoices
2// Authorization: Bearer chk_test_xxxxxxxxxxxxxxxxxxxx
3// Idempotency-Key: f2e86a1c-0b3d-4a5e-9f7c-1d2e3f4a5b6c
4
5{
6 "series_id": "b3f1a2e0-4c1a-4e7a-9c1a-3f6a8e2d9c11",
7 "invoice_type": "STANDARD",
8 "contact_id": "9d2f1a3b-5c6d-4e7f-8a9b-0c1d2e3f4a5b",
9 "payment_method": "TRANSFER",
10 "payment_term_days": 30,
11 "items": [
12 {
13 "description": "Desarrollo web - Sprint 3",
14 "quantity": 1,
15 "unit_price": 1500.00,
16 "tax_rate": 21,
17 "irpf_rate": 15
18 }
19 ]
20}
21
22// Respuesta 201 (el número sigue la plantilla de la serie):
23{
24 "invoice_id": "3a1b2c3d-4e5f-6789-abcd-ef0123456789",
25 "invoice_number": "A-2026-0042"
26}
Recursos

Referencia de la API

Todo lo que necesitas para integrar Chiklin desde tu propio backend: autenticación por API Key, entornos de Pruebas/Real aislados, idempotencia en operaciones fiscales irreversibles y un endpoint por cada recurso de negocio (facturas, clientes, proveedores, series, recurrentes, gastos y productos).

Base URL
https://www.chiklin.com/api/v1
Autenticación
Authorization: Bearer <api_key>
Rate limits
300 lecturas / 5 min · 20 escrituras / min
Idempotencia
Cabecera Idempotency-Key en POST de facturas
Paginación
?limit=1…100 (50 por defecto) &offset=0
Errores
{ "error": "...", "details"?: {...} }

Ejemplos de uso

GET/api/v1/series

Autenticación

Toda petición (salvo /healthz) lleva la clave en la cabecera Authorization como Bearer token; la API requiere el plan Developer. Una clave está permanentemente ligada a un entorno (chk_test_… para Pruebas, chk_live_… para Real) y a los datos de ese entorno únicamente. Para comprobar que tu clave funciona, pide cualquier recurso, por ejemplo tus series: 200 si es válida, 401 si no (/healthz no mira la clave). Usa siempre https://www.chiklin.com: el dominio sin www redirige y la mayoría de clientes HTTP descartan la cabecera Authorization al seguir la redirección.

python — /api/v1/series
import requests

API_KEY = "chk_test_xxxxxxxxxxxxxxxxxxxx"
BASE_URL = "https://www.chiklin.com/api/v1"

response = requests.get(
    f"{BASE_URL}/series",
    headers={"Authorization": f"Bearer {API_KEY}"},
)
print(response.status_code, response.json())
POST/api/v1/invoices

Crear una factura

Emite una factura Ordinaria o Simplificada: calcula IVA/IRPF, numera correlativamente por serie y la registra en VeriFactu. Añade una cabecera Idempotency-Key (un UUID por intento lógico) para que un reintento de red no emita una segunda factura. issue_date es opcional (por defecto, hoy en hora de Madrid); con una clave chk_live_ solo se admite la fecha de hoy. Si la operación se hizo otro día, indícalo en operation_date, que no puede ser posterior a issue_date. El cliente va como contact_id (uno existente) o como contact (objeto con los mismos campos que POST /clients, que lo da de alta); una Simplificada puede ir sin cliente; una Ordinaria (invoice_type por defecto) sin cliente responde 400. Opcionales: payment_method (TRANSFER, CASH, CARD, CHECK, DIRECT_DEBIT o NONE), payment_term_days (calcula el vencimiento) y, por línea, irpf_rate y surcharge_rate (recargo de equivalencia). Responde 201 con invoice_id e invoice_number. Por ahora, con una clave chk_live_ se responde 400 a una factura con alguna línea al 0 % de IVA o a un cliente con identificador extranjero (NIF-IVA, pasaporte…): el registro de VeriFactu todavía no sabe describir esas operaciones.

python — /api/v1/invoices
import requests, uuid

API_KEY = "chk_test_xxxxxxxxxxxxxxxxxxxx"
BASE_URL = "https://www.chiklin.com/api/v1"

payload = {
    "series_id": "b3f1a2e0-4c1a-4e7a-9c1a-3f6a8e2d9c11",
    "invoice_type": "STANDARD",
    "contact_id": "9d2f1a3b-5c6d-4e7f-8a9b-0c1d2e3f4a5b",
    "items": [
        {"description": "Desarrollo web - Sprint 3", "quantity": 1, "unit_price": 1500.00, "tax_rate": 21, "irpf_rate": 15}
    ],
}

response = requests.post(
    f"{BASE_URL}/invoices",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json=payload,
)
response.raise_for_status()
print(response.json())  # { "invoice_id": "...", "invoice_number": "..." } (formato según la plantilla de la serie)
POST/api/v1/invoices/{id}/void

Anular una factura

No borra ni marca un flag: emite una factura rectificativa (R4/R5 según AEAT) que invierte el signo de cada línea y la registra en VeriFactu. La rectificativa se numera en la serie de rectificativas del entorno (se crea si no existe), nunca en la de la factura original. Solo si esa rectificativa queda correctamente registrada, la original pasa a voided. rectification_reason (obligatorio, hasta 150 caracteres) se imprime en el PDF de la rectificativa.

python — /api/v1/invoices/{id}/void
import requests, uuid

API_KEY = "chk_test_xxxxxxxxxxxxxxxxxxxx"
BASE_URL = "https://www.chiklin.com/api/v1"
invoice_id = "3a1b2c3d-4e5f-6789-abcd-ef0123456789"

response = requests.post(
    f"{BASE_URL}/invoices/{invoice_id}/void",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={"rectification_reason": "Error en el importe de la línea 2"},
)
response.raise_for_status()
print(response.json())  # { "original_invoice_id", "corrective_invoice_id", "corrective_invoice_number" }
POST/api/v1/clients

Crear un cliente

Da de alta un contacto como cliente (is_customer=true). Valida el NIF/CIF según el país antes de guardarlo. Un NIF/CIF solo puede estar en un contacto por entorno: si ya existe (como cliente, proveedor o ambos) responde 409 con contact_id, el del contacto que ya lo tiene.

python — /api/v1/clients
import requests

API_KEY = "chk_test_xxxxxxxxxxxxxxxxxxxx"
BASE_URL = "https://www.chiklin.com/api/v1"

payload = {
    "person_type_code": "J",
    "tax_identification_number": "B12345674",
    "corporate_name": "Acme Soluciones SL",
    "address": "Calle Mayor 1",
    "post_code": "28001",
    "town": "Madrid",
    "province": "Madrid",
    "email": "facturacion@acme.es",
}

response = requests.post(f"{BASE_URL}/clients", headers={"Authorization": f"Bearer {API_KEY}"}, json=payload)
response.raise_for_status()
print(response.json())
POST/api/v1/suppliers

Crear un proveedor

Igual que /clients pero marca is_provider=true (is_customer queda a false). Un NIF/CIF solo puede estar en un contacto por entorno: si ya existe, aunque sea como cliente, responde 409 con contact_id. Un mismo contacto puede ser cliente y proveedor a la vez, pero ese segundo papel se le añade desde la app (Clientes o Proveedores).

python — /api/v1/suppliers
import requests

API_KEY = "chk_test_xxxxxxxxxxxxxxxxxxxx"
BASE_URL = "https://www.chiklin.com/api/v1"

payload = {
    "person_type_code": "F",
    "tax_identification_number": "12345678Z",
    "first_name": "Laura",
    "first_surname": "Gomez",
    "address": "Av. Diagonal 200",
    "post_code": "08018",
    "town": "Barcelona",
    "province": "Barcelona",
}

response = requests.post(f"{BASE_URL}/suppliers", headers={"Authorization": f"Bearer {API_KEY}"}, json=payload)
response.raise_for_status()
print(response.json())
POST/api/v1/series

Crear una serie de facturación

El prefijo debe ser único dentro del entorno de la clave. Con "is_rectificativa": true crea una serie solo para rectificativas: la ley obliga a numerarlas en su propia serie, y en ella no se puede emitir ninguna otra factura. Sujeto al límite de series de tu plan, que cuenta aparte las de rectificativas.

python — /api/v1/series
import requests

API_KEY = "chk_test_xxxxxxxxxxxxxxxxxxxx"
BASE_URL = "https://www.chiklin.com/api/v1"

payload = {"name": "Serie B", "prefix": "B-2026"}

response = requests.post(f"{BASE_URL}/series", headers={"Authorization": f"Bearer {API_KEY}"}, json=payload)
response.raise_for_status()
print(response.json())
POST/api/v1/recurring-invoices

Crear una plantilla recurrente

La plantilla queda congelada al entorno de la clave y necesita una serie normal (no de rectificativas). frequency: weekly, monthly, quarterly o yearly. Si no envías next_run_date se calcula a partir de la frecuencia. Opcionales: end_date, max_occurrences, payment_method y payment_term_days.

python — /api/v1/recurring-invoices
import requests

API_KEY = "chk_test_xxxxxxxxxxxxxxxxxxxx"
BASE_URL = "https://www.chiklin.com/api/v1"

payload = {
    "series_id": "b3f1a2e0-4c1a-4e7a-9c1a-3f6a8e2d9c11",
    "contact_id": "9d2f1a3b-5c6d-4e7f-8a9b-0c1d2e3f4a5b",
    "frequency": "monthly",
    "items": [
        {"description": "Mantenimiento mensual", "quantity": 1, "unit_price": 250.00, "tax_rate": 21, "irpf_rate": 15}
    ],
}

response = requests.post(f"{BASE_URL}/recurring-invoices", headers={"Authorization": f"Bearer {API_KEY}"}, json=payload)
response.raise_for_status()
print(response.json())
POST/api/v1/expenses

Registrar un gasto

total_gross_amount es la base imponible (sin IVA); el IVA, la retención y el total se calculan con tax_rate e irpf_rate. provider_id es opcional (un proveedor del mismo entorno). Otros campos opcionales: description, invoice_number (el número de la factura del proveedor), category e is_iva_deductible (por defecto true). Un ticket (document_type: RECEIPT) nunca es deducible de IVA aunque envíes is_iva_deductible: true — el servidor lo fuerza a false.

python — /api/v1/expenses
import requests

API_KEY = "chk_test_xxxxxxxxxxxxxxxxxxxx"
BASE_URL = "https://www.chiklin.com/api/v1"

payload = {
    "provider_id": "6a7b8c9d-0e1f-2a3b-4c5d-6e7f8a9b0c1d",
    "expense_date": "2026-07-20",
    "document_type": "INVOICE",
    "total_gross_amount": 500.00,
    "tax_rate": 21,
    "irpf_rate": 15,
    "category": "Suministros",
}

response = requests.post(f"{BASE_URL}/expenses", headers={"Authorization": f"Bearer {API_KEY}"}, json=payload)
response.raise_for_status()
print(response.json())
POST/api/v1/products

Crear un producto/servicio

Alta simple en el catálogo. El producto nace activo y en el entorno de la clave usada.

python — /api/v1/products
import requests

API_KEY = "chk_test_xxxxxxxxxxxxxxxxxxxx"
BASE_URL = "https://www.chiklin.com/api/v1"

payload = {"name": "Hora de consultoria", "unit_price": 60.00, "tax_rate": 21}

response = requests.post(f"{BASE_URL}/products", headers={"Authorization": f"Bearer {API_KEY}"}, json=payload)
response.raise_for_status()
print(response.json())

Todos los endpoints

Sistema

GET/healthzComprobación de estado (sin autenticación)curl https://www.chiklin.com/api/v1/healthz

Facturas

GET/invoicesListar facturas (limit, offset)curl "https://www.chiklin.com/api/v1/invoices?limit=50" -H "Authorization: Bearer $API_KEY"
POST/invoicesCrear factura Ordinaria o Simplificadacurl -X POST https://www.chiklin.com/api/v1/invoices -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "series_id": "...", "contact_id": "...", "items": [...] }'
GET/invoices/{id}Obtener una factura y sus líneascurl https://www.chiklin.com/api/v1/invoices/{id} -H "Authorization: Bearer $API_KEY"
POST/invoices/{id}/voidAnular vía rectificativa (R4/R5)curl -X POST https://www.chiklin.com/api/v1/invoices/{id}/void -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "rectification_reason": "..." }'

Clientes

GET/clientsListar clientes (limit, offset)curl "https://www.chiklin.com/api/v1/clients?limit=50" -H "Authorization: Bearer $API_KEY"
POST/clientsCrear clientecurl -X POST https://www.chiklin.com/api/v1/clients -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "person_type_code": "J", "tax_identification_number": "...", ... }'
GET/clients/{id}Obtener un clientecurl https://www.chiklin.com/api/v1/clients/{id} -H "Authorization: Bearer $API_KEY"
PATCH/clients/{id}Actualizar un clientecurl -X PATCH https://www.chiklin.com/api/v1/clients/{id} -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "email": "nuevo@correo.es" }'

Proveedores

GET/suppliersListar proveedores (limit, offset)curl "https://www.chiklin.com/api/v1/suppliers?limit=50" -H "Authorization: Bearer $API_KEY"
POST/suppliersCrear proveedorcurl -X POST https://www.chiklin.com/api/v1/suppliers -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "person_type_code": "F", "tax_identification_number": "...", ... }'
GET/suppliers/{id}Obtener un proveedorcurl https://www.chiklin.com/api/v1/suppliers/{id} -H "Authorization: Bearer $API_KEY"
PATCH/suppliers/{id}Actualizar un proveedorcurl -X PATCH https://www.chiklin.com/api/v1/suppliers/{id} -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "phone": "600000000" }'

Series

GET/seriesListar series de facturacióncurl https://www.chiklin.com/api/v1/series -H "Authorization: Bearer $API_KEY"
POST/seriesCrear serie (prefijo único por entorno; is_rectificativa para la de rectificativas)curl -X POST https://www.chiklin.com/api/v1/series -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "name": "Serie B", "prefix": "B-2026" }'
GET/series/{id}Obtener una seriecurl https://www.chiklin.com/api/v1/series/{id} -H "Authorization: Bearer $API_KEY"

Facturas recurrentes

GET/recurring-invoicesListar plantillascurl https://www.chiklin.com/api/v1/recurring-invoices -H "Authorization: Bearer $API_KEY"
POST/recurring-invoicesCrear plantilla recurrentecurl -X POST https://www.chiklin.com/api/v1/recurring-invoices -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "series_id": "...", "contact_id": "...", "frequency": "monthly", "items": [...] }'
GET/recurring-invoices/{id}Obtener una plantillacurl https://www.chiklin.com/api/v1/recurring-invoices/{id} -H "Authorization: Bearer $API_KEY"
PATCH/recurring-invoices/{id}Activar / desactivarcurl -X PATCH https://www.chiklin.com/api/v1/recurring-invoices/{id} -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "active": false }'
DELETE/recurring-invoices/{id}Eliminar una plantillacurl -X DELETE https://www.chiklin.com/api/v1/recurring-invoices/{id} -H "Authorization: Bearer $API_KEY"

Gastos

GET/expensesListar gastos (limit, offset)curl "https://www.chiklin.com/api/v1/expenses?limit=50" -H "Authorization: Bearer $API_KEY"
POST/expensesRegistrar un gastocurl -X POST https://www.chiklin.com/api/v1/expenses -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "expense_date": "2026-07-20", "document_type": "INVOICE", "total_gross_amount": 500, "tax_rate": 21 }'
GET/expenses/{id}Obtener un gastocurl https://www.chiklin.com/api/v1/expenses/{id} -H "Authorization: Bearer $API_KEY"
PATCH/expenses/{id}Editar un gasto (solo los campos que envíes; los totales se recalculan). En Real, si es de un trimestre anterior, se guarda y la respuesta trae warningcurl -X PATCH https://www.chiklin.com/api/v1/expenses/{id} -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "total_gross_amount": 450 }'
DELETE/expenses/{id}Eliminar un gasto (en Real, con warning si es de un trimestre anterior)curl -X DELETE https://www.chiklin.com/api/v1/expenses/{id} -H "Authorization: Bearer $API_KEY"

Productos

GET/productsListar productos/servicios (limit, offset)curl "https://www.chiklin.com/api/v1/products?limit=50" -H "Authorization: Bearer $API_KEY"
POST/productsCrear producto/serviciocurl -X POST https://www.chiklin.com/api/v1/products -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "name": "Hora de consultoria", "unit_price": 60, "tax_rate": 21 }'
GET/products/{id}Obtener un productocurl https://www.chiklin.com/api/v1/products/{id} -H "Authorization: Bearer $API_KEY"
PATCH/products/{id}Actualizar nombre, descripción, precio, IVA o activocurl -X PATCH https://www.chiklin.com/api/v1/products/{id} -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" -d '{ "active": false }'

Códigos de respuesta

200 / 201Correcto / recurso creado
400Cuerpo inválido (details indica qué campo) o regla fiscal incumplida
401Falta la clave, o es inválida o está revocada
403Tu plan no lo permite o la empresa no puede emitir (pago pendiente, archivada…)
404No existe en el entorno de la clave
409Conflicto: duplicado, factura ya anulada o petición idempotente aún en curso
422La serie no corresponde al tipo de factura
429Límite de peticiones superado; espera lo que indica Retry-After