Developers
Zertidox API reference
Order Spanish certificates, valuations and legal documents and follow their status.
Overview
- Base URL
https://zertidox.com/api/v1- Authentication
Authorization: Bearer cd_…- Format
- JSON over HTTPS
- OpenAPI 3.1
- /api/v1/openapi.json
- Version
- 1.0.0
API keys belong to a Zertidox Business account. Create them in your dashboard. Keep them secret: a key acts as your account. REST API of Zertidox Business. JSON over HTTPS; field names are in Spanish. Rate limit per account: between 30 and 600 requests per minute depending on the account plan (30 per minute for webhook management). A 429 response says which limit applies.
Errors return a JSON body with error (a message in Spanish) and, when there is one, a stable code. Field names are in Spanish (solicitud = request, estado = status, datos = form data).
Get the authenticated account
GET/api/v1/me
Returns the account that owns the API key. Use it to test a key: Zapier calls it when a user connects their account and labels the connection with the email.
Authentication
API key: Authorization: Bearer cd_…
Example request
curl -X GET "https://zertidox.com/api/v1/me" \
-H "Authorization: Bearer cd_your_api_key"Errors
| Status | Meaning |
|---|---|
| 401 | The API key is missing, invalid or revoked, or the account has no active Business plan. |
| 429 | Rate limit exceeded. Wait one minute before retrying. More than 30 failed authentications per minute from the same IP also return 429. |
List request types
GET/api/v1/catalogo
Public catalog of the request types (certificates, valuations, legal documents) and the fields each one accepts inside `datos`. No authentication. Cached for one hour. Prices can change: the one that applies is shown on each product page.
Authentication
None (public endpoint).
Example request
curl -X GET "https://zertidox.com/api/v1/catalogo"Response 200
Request types and their fields.
{
"certificados": [
{
"tipo": "NACIMIENTO",
"label": "Certificado de Nacimiento",
"campos": [
{
"nombre": "nombre",
"label": "Nombre",
"tipo": "text",
"requerido": true
},
{
"nombre": "apellido1",
"label": "Primer apellido",
"tipo": "text",
"requerido": true
},
{
"nombre": "fechaNacimiento",
"label": "Fecha de nacimiento",
"tipo": "date",
"requerido": true
}
]
}
]
}Errors
| Status | Meaning |
|---|
List requests
GET/api/v1/solicitudes
Lists the requests of the account, newest first.
Authentication
API key: Authorization: Bearer cd_…
Parameters
| Name | In | Required | Description |
|---|---|---|---|
estado | query | No | Filter by status. Values: PENDIENTE_PAGO, PAGADA, ENVIADA_AL_MJ, ESPERANDO_CERTIFICADO, ENTREGADA, REEMBOLSADA, REQUIERE_REVISION, RECHAZADA, REQUIERE_FIRMA, FIRMADA, REVISION_ABOGADO, REVISADA, EN_PROCESO, CADUCADA. |
limit | query | No | Page size, 1–100. |
offset | query | No | Items to skip. |
Example request
curl -X GET "https://zertidox.com/api/v1/solicitudes" \
-H "Authorization: Bearer cd_your_api_key"Response 200
A page of requests.
{
"data": [
{
"id": "clx0example",
"referencia": "CD-1792078788561-8ACCA12F",
"tipo": "NACIMIENTO",
"estado": "ENVIADA_AL_MJ",
"precio": "0",
"pagado": true,
"clienteNombre": "Client 0042",
"createdAt": "2026-10-15T09:00:00.000Z"
}
],
"limit": 20,
"offset": 0
}Errors
| Status | Meaning |
|---|---|
| 400 | Unknown `estado` value. |
| 401 | The API key is missing, invalid or revoked, or the account has no active Business plan. |
| 429 | Rate limit exceeded. Wait one minute before retrying. More than 30 failed authentications per minute from the same IP also return 429. |
Create a request
POST/api/v1/solicitudes
Creates a request. With `pago: "plan"` it is paid at once from the monthly Zertidox Business balance and processing starts; the Zapier integration always sends it. Without `pago` it is created unpaid (`PENDIENTE_PAGO`). Each call creates (and charges) a new request unless you send the same `Idempotency-Key`. The `estado` in the response is the one at creation time; read the request again for its current status.
Authentication
API key: Authorization: Bearer cd_…
Parameters
| Name | In | Required | Description |
|---|---|---|---|
Idempotency-Key | header | No | Optional, 1–255 visible ASCII characters. Repeating a key returns the original request (200, `Idempotent-Replayed: true`) instead of creating another one. |
Body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
tipo | string | Yes | A `tipo` from `GET /catalogo`. |
datos | object | Yes | Field values keyed by the `nombre` of each catalog field. |
clienteNombre | string | No | Your internal reference. |
pago | string | No | Pay from the Zertidox Business balance. |
Example request
curl -X POST "https://zertidox.com/api/v1/solicitudes" \
-H "Authorization: Bearer cd_your_api_key" \
-H "Content-Type: application/json" \
-d '{"tipo":"CONSULTORIA_FIANZA","datos":{"importeFianza":"1200","nombreArrendador":"Inmuebles Ejemplo S.L.","direccionVivienda":"Calle Mayor 1, 2.º B, 28013 Madrid","fechaEntregaLlaves":"2026-09-30","descripcionHechos":"Entregué las llaves en buen estado y la fianza no se ha devuelto."},"clienteNombre":"Client 0042","pago":"plan"}'Response 201
Request created.
{
"id": "clx0example",
"referencia": "CD-1792078788561-8ACCA12F",
"tipo": "CONSULTORIA_FIANZA",
"estado": "PENDIENTE_PAGO",
"precio": 0,
"pagado": true,
"clienteNombre": "Client 0042",
"createdAt": "2026-10-15T09:00:00.000Z",
"cubiertoPorPlan": true
}Response 200
Replay of an earlier call with the same `Idempotency-Key`.
{
"id": "clx0example",
"referencia": "CD-1792078788561-8ACCA12F",
"tipo": "NACIMIENTO",
"estado": "ENVIADA_AL_MJ",
"precio": "0",
"pagado": true,
"clienteNombre": "Client 0042",
"createdAt": "2026-10-15T09:00:00.000Z"
}Errors
| Status | Meaning |
|---|---|
| 400 | Invalid body (`Body inválido`) or data rejected by the request type. Codes include `CAMPOS_REQUERIDOS` (missing fields, listed in `campos`), `TIPO_NO_DISPONIBLE`, `AUTORIZACION_REQUERIDA` (civil-registry certificates need a signed authorization first, so they cannot be paid with `pago: "plan"` through the API), `IDEMPOTENCY_KEY_INVALIDA`. |
| 401 | The API key is missing, invalid or revoked, or the account has no active Business plan. |
| 402 | Not covered by the Business plan. Codes: `SALDO_INSUFICIENTE` (balance too low this month), `PRODUCTO_NO_ELEGIBLE`. The body includes `saldoRestanteEur` and `precioEur`. Nothing is created or charged. |
| 409 | Codes: `IDEMPOTENCY_EN_CURSO` (the first call with that key is still running; retry in a minute), `PEDIDO_YA_EN_PROCESO`. |
| 429 | Rate limit exceeded. Wait one minute before retrying. More than 30 failed authentications per minute from the same IP also return 429. |
| 500 | `COBERTURA_NO_SELLADA`: the payment could not be recorded and the balance is returned. The request stays created and unpaid; retry with an `Idempotency-Key` to avoid a second one. |
Retrieve a request
GET/api/v1/solicitudes/{id}
Returns one request of the account, with its status history and delivered documents.
Authentication
API key: Authorization: Bearer cd_…
Parameters
| Name | In | Required | Description |
|---|---|---|---|
id | path | Yes | Request ID or public reference (CD-…). |
Example request
curl -X GET "https://zertidox.com/api/v1/solicitudes/CD-1792078788561-8ACCA12F" \
-H "Authorization: Bearer cd_your_api_key"Response 200
The request.
{
"id": "clx0example",
"referencia": "CD-1792078788561-8ACCA12F",
"tipo": "NACIMIENTO",
"estado": "ENTREGADA",
"precio": "0",
"pagado": true,
"clienteNombre": "Client 0042",
"createdAt": "2026-10-15T09:00:00.000Z",
"updatedAt": "2026-10-15T10:00:00.000Z",
"historial": [
{
"estado": "ENTREGADA",
"nota": null,
"createdAt": "2026-10-15T10:00:00.000Z"
},
{
"estado": "ENVIADA_AL_MJ",
"nota": null,
"createdAt": "2026-10-15T09:05:00.000Z"
}
],
"documentos": [
{
"nombre": "certificado-nacimiento.pdf",
"url": "https://…/certificado-nacimiento.pdf",
"tipo": "application/pdf",
"createdAt": "2026-10-15T10:00:00.000Z"
}
]
}Errors
| Status | Meaning |
|---|---|
| 401 | The API key is missing, invalid or revoked, or the account has no active Business plan. |
| 404 | No request with that ID or reference in this account. |
| 429 | Rate limit exceeded. Wait one minute before retrying. More than 30 failed authentications per minute from the same IP also return 429. |
Subscribe a webhook
POST/api/v1/webhooks
Registers a URL that receives the status events below (see Webhooks). Zapier calls it when a Zap with the "Request Status Changed" trigger is turned on. Up to 20 webhooks per account.
Authentication
API key: Authorization: Bearer cd_…
Body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Public HTTPS URL. Private and internal addresses are rejected. |
eventos | array | No | Events to receive. Empty or omitted: all of them. |
Example request
curl -X POST "https://zertidox.com/api/v1/webhooks" \
-H "Authorization: Bearer cd_your_api_key" \
-H "Content-Type: application/json" \
-d '{"url":"https://hooks.zapier.com/hooks/standard/123/abc/","eventos":["solicitud.completada"]}'Response 201
Webhook created. Store `secret`: it is not shown again.
{
"id": "clxwebhook0",
"url": "https://hooks.zapier.com/hooks/standard/123/abc/",
"activo": true,
"eventos": [
"solicitud.completada"
],
"createdAt": "2026-10-15T09:00:00.000Z",
"secret": "whsec_…"
}Errors
| Status | Meaning |
|---|---|
| 400 | Missing or invalid `url`, or unknown events (listed in `validos`). |
| 401 | Missing or invalid API key. |
| 409 | `LIMITE_WEBHOOKS`: the account already has 20 webhooks. |
| 429 | More than 30 webhook calls per minute. |
Unsubscribe a webhook
DELETE/api/v1/webhooks/{id}
Deletes a webhook of the account. Zapier calls it when the Zap is turned off.
Authentication
API key: Authorization: Bearer cd_…
Parameters
| Name | In | Required | Description |
|---|---|---|---|
id | path | Yes | Webhook ID. |
Example request
curl -X DELETE "https://zertidox.com/api/v1/webhooks/clxwebhook0" \
-H "Authorization: Bearer cd_your_api_key"Response 200
Deleted.
{
"ok": true
}Errors
| Status | Meaning |
|---|---|
| 401 | Missing or invalid API key. |
| 404 | No webhook with that ID in this account. |
| 429 | More than 30 webhook calls per minute. |
Webhook events
Sent to each active webhook of the account when a request changes status. Headers: `X-Zertidox-Event` (event name) and `X-Zertidox-Signature: t=<unix seconds>,v1=<hex>`, where `v1` is HMAC-SHA256 of `<t>.<raw body>` with the webhook `secret`. Reply with any 2xx within 10 seconds; redirects (3xx) count as failures. Failed deliveries are retried twice (after 30 seconds and 2 minutes) with the same `t`. A 410 response disables the webhook. Test-mode accounts get simulated events, sent once without retries and with `modoPrueba: true`.
Events
Each status change sends one event. Subscribe with an empty eventos list to receive all of them.
| Event | Sent when the request moves to |
|---|---|
solicitud.estado_cambiado | Any other status |
solicitud.completada | ENTREGADA |
solicitud.rechazada | RECHAZADA |
solicitud.tramitada | ENVIADA_AL_MJ |
solicitud.listo_para_descarga | ESPERANDO_CERTIFICADO |
Example payload
{
"evento": "solicitud.completada",
"solicitudId": "clx0example",
"referencia": "CD-1792078788561-8ACCA12F",
"tipo": "NACIMIENTO",
"estado": "ENTREGADA",
"nota": null,
"updatedAt": "2026-10-15T10:00:00.000Z"
}Verifying the signature (Node.js)
import { createHmac, timingSafeEqual } from 'node:crypto'
// header: value of X-Zertidox-Signature, rawBody: the request body as received
function isValid(secret, header, rawBody) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
if (!parts.t || !parts.v1) return false
const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex')
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300
return fresh && expected.length === parts.v1.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
}Questions or a custom integration? Write to us from contact.