Certifick API v1

Integra NOM-151 y firma electrónica a tus sistemas

API REST sobre HTTPS para ERP, CRM, CLM y automatizaciones. Cada organización genera sus llaves desde Integraciones y API en el backoffice. Todas las respuestas son JSON en UTF-8 y las fechas están en UTC (ISO 8601).

Elige tu escenario de integración

Hay dos formas de usar Certifick. Identifica la tuya antes de crear la llave: define los alcances que marcas, los endpoints que llamas y el consumo de certificados.

escenario a

Firma electrónica completa

Certifick gestiona el flujo: envía el documento a los firmantes, valida con OTP, recibe la firma autógrafa o la e.firma (FIEL) del SAT, sella el PDF y al cerrarse el sobre emite la constancia NOM-151 y ancla la huella en blockchain.

  • Alcances: envelopes:write, envelopes:read, webhooks:read (opcional nom151:read).
  • Endpoints: POST /envelopes, POST /envelopes/{id}/send, GET /envelopes/{id}, GET /envelopes/{id}/documents/{docId}.
  • Consumo: 1 certificado por documento firmado; la constancia NOM-151 está incluida.
  • Úsalo si: necesitas que tus clientes o empleados firmen y quieres la evidencia legal de punta a punta.
escenario b

Solo NOM-151 (conservación)

Tu plataforma ya produce el archivo final y solo necesitas la constancia de conservación de mensajes de datos con sello de tiempo del PSC acreditado. Certifick no ve el flujo de firma; basta la huella del archivo.

  • Alcances: nom151:write y nom151:read.
  • Endpoints: POST /nom151/constancias, GET /nom151/constancias/{folio}, POST /nom151/validate.
  • Entrada: sha256 del archivo, o contentBase64 (máx. 20 MB) si prefieres que Certifick calcule la huella.
  • Guarda: folio y constanciaBase64 como archivo .asn1 junto al documento.
NecesidadEscenarioAlcances a marcar
Recabar firmas de terceros por correoAenvelopes:write, envelopes:read
Firmar con e.firma (FIEL) del SATAenvelopes:write, envelopes:read
Conservar un PDF ya firmado o un expedienteBnom151:write, nom151:read
Verificar integridad o validar una constanciaA o Bnom151:read
Recibir notificaciones automáticasA o Bwebhooks:read

En ambos escenarios empieza con una llave de pruebas (sandbox): las constancias se emiten simuladas con folio sbx-, sin consumir certificados ni contactar al proveedor, y se pueden validar igual. Al terminar, crea la llave de producción con los mismos alcances y cambia solo el secreto. Nuestros certificados no tienen vigencia.

Inicio rápido en 5 minutos

  1. 1. En el backoffice, entra a Integraciones y API y crea una llave con los alcances nom151:write y nom151:read. El secreto se muestra una sola vez.
  2. 2. Comprueba la conexión con GET /health.
  3. 3. Calcula el SHA-256 del archivo y emite la constancia con POST /nom151/constancias.
  4. 4. Guarda folio y constanciaBase64 (archivo .asn1) junto al documento en tu sistema.
  5. 5. Verifica cuando quieras con GET /verify/{sha256} o POST /nom151/validate.
curl -X POST https://certifick.com/api/public/v1/nom151/constancias \
  -H "Authorization: Bearer $CERTIFICK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sha256": "3f786850e387550fdab836ed7e6dc881de23001b3f0cbc4b0d1a4f4a1d9ca1a5",
    "fileName": "contrato-4471.pdf",
    "externalId": "ERP-4471"
  }'

Autenticación

Envía tu llave en el encabezado Authorization. Guárdala en el gestor de secretos de tu sistema y nunca en el navegador.

Authorization: Bearer cfk_1a2b3c4d_<secreto>
Content-Type: application/json

Alcances: nom151:write, nom151:read, envelopes:read, envelopes:write, webhooks:read. Límite por defecto: 120 peticiones por minuto y por llave (respuesta 429 al excederlo).

Base URL

https://certifick.com/api/public/v1

Cómo calcular el SHA-256 correctamente

Es el error más común de integración. La huella debe calcularse sobre los bytes exactos del archivo que vas a conservar, en hexadecimal minúsculas de 64 caracteres. Si el archivo cambia aunque sea un byte (por ejemplo, al re-guardarlo o al agregar metadatos), la huella cambia y la constancia deja de corresponder.

# macOS / Linux
shasum -a 256 contrato-4471.pdf

# Windows (PowerShell)
Get-FileHash contrato-4471.pdf -Algorithm SHA256

Si prefieres que Certifick la calcule, envía contentBase64 con el archivo completo (máximo 20 MB) en lugar de sha256.

Ambiente de pruebas (sandbox)

Al crear la llave, marca Llave de pruebas (sandbox). Esa llave usa los mismos endpoints y devuelve la misma estructura de respuesta, pero emite constancias simuladas: no consume certificados ni contacta al PSC. El folio inicia con sbx-, environment es sandbox y status es simulado; POST /nom151/validate también valida esas constancias simuladas. Cuando tu integración esté lista, genera una llave de producción con los mismos alcances y cambia sólo el valor del secreto.

Prueba paso a paso en Postman

La colección descargable ya trae la base URL de producción, la autorización Bearer heredada y scripts que guardan solos folio, sha256 y constanciaBase64 tras emitir la constancia.

  1. 1. Descarga la colección. Desde /api/public/v1/postman.json o con el botón “Colección de Postman” al inicio de esta página.
  2. 2. Crea tu llave sandbox. Backoffice → Integraciones y API → Crear llave → marca Llave de pruebas (sandbox) con alcances nom151:write y nom151:read. Copia el secreto cfk_…: sólo se muestra una vez.
  3. 3. Importa en Postman. Import → arrastra el archivo. Aparece la colección “Certifick API v1 — NOM-151”.
  4. 4. Configura las variables. Haz clic en el nombre de la colección (no en una petición) → pestaña Variables → pega tu llave en CERTIFICK_API_KEY y deja baseUrl como viene → Save. Ojo: Params no es lo mismo que Variables; Params sólo agrega query string a una petición.
  5. 5. Health. Ejecuta la petición 1: responde 200 con modo, organización, alcances y saldo. Un 401 significa llave mal pegada o revocada. Agrega ?deep=1 para comprobar también al PSC.
  6. 6. Emite la constancia. Petición 2: envía sha256 (64 hex en minúsculas) o contentBase64 + fileName (≤ 20 MB). Devuelve folio (con prefijo sbx- en sandbox), hashProcessed, issuedAt y constanciaBase64.
  7. 7. Guarda folio y huella. El script de la petición 2 los escribe automáticamente en las variables de la colección. Si prefieres hacerlo a mano, copia los valores en las variables folio, sha256 y constanciaBase64. El script es:
    const r = pm.response.json();
    if (r.folio) pm.collectionVariables.set("folio", r.folio);
    if (r.hashProcessed || r.sha256)
      pm.collectionVariables.set("sha256", r.hashProcessed || r.sha256);
    if (r.constanciaBase64)
      pm.collectionVariables.set("constanciaBase64", r.constanciaBase64);
  8. 8. Recupera y lista. Peticiones 3 y 4: GET /nom151/constancias/{{folio}} y el listado paginado de tu organización.
  9. 9. Valida la constancia. Petición 5: el body ya usa {{sha256}}, {{folio}} y {{constanciaBase64}}. Envía y debes recibir valid: true. Si responde falso, revisa que los tres valores sean de la misma emisión y que el base64 esté completo (sin saltos de línea ni recortes).
  10. 10. Verificación pública. Petición 6: GET /verify/{{sha256}}, sin llave; muestra integridad, NOM-151 y blockchain.
  11. 11. Pasa a producción. Repite el flujo con una llave sin sandbox: se contacta al PSC real y se consume un certificado por constancia (idempotente por huella, no cobra dos veces la misma).

Errores frecuentes en la prueba: invalid_hash (huella mal formada), insufficient_credits (sin saldo, sólo en producción) y psc_unavailable (reintenta).

Endpoints NOM-151

GET/health

Cualquier llave válida sirve, sin alcance específico. Devuelve la organización, sus alcances, el modo (pruebas o produccion), el saldo de certificados por país y la hora del servidor. Con ?deep=1 además comprueba en vivo la disponibilidad del proveedor de certificación, sin consumir certificados.
curl "https://certifick.com/api/public/v1/health?deep=1" -H "Authorization: Bearer $CERTIFICK_API_KEY"

POST/nom151/constanciasnom151:write

Emite la constancia de conservación NOM-151 de una huella, con un PSC acreditado. Consume 1 certificado. La operación es idempotente por organización y huella: repetirla devuelve 200 con la constancia existente y no consume otro certificado. Si el proveedor falla, el certificado se reversa automáticamente. Campo opcional psc para elegir un PSC habilitado (ver GET /psc).
# 201 Created
{
  "sha256": "3f786850e387550fdab836ed7e6dc881de23001b3f0cbc4b0d1a4f4a1d9ca1a5",
  "folio": "b9d4f1e0-1c2a-4f7d-9a44-6f0f1f2c3d4e",
  "provider": "codex",
  "hashProcessed": "3f786850…",
  "issuedAt": "2026-08-31T05:12:44.000Z",
  "environment": "produccion",
  "fileName": "contrato-4471.pdf",
  "externalId": "ERP-4471",
  "constanciaBase64": "MIIF…",
  "status": "certificado"
}

GET/pscnom151:read

Lista los PSC habilitados para NOM-151 en el país de tu organización. Envía su key en el campo opcional psc al emitir una constancia o crear un sobre.
{ "country": "MX", "providers": [{ "key": "cincel", "name": "Cincel" }, { "key": "codex", "name": "PSC CODEX" }] }

GET/nom151/constancias/{folio}nom151:read

Recupera una constancia ya emitida. Acepta el folio del PSC o la huella SHA-256, por lo que puedes reconstruir el archivo .asn1 en cualquier momento sin guardarlo tú.

GET/nom151/constancias?page=&pageSize=nom151:read

Listado paginado de las constancias de la organización (sin el archivo, para respuestas ligeras).

POST/nom151/validatenom151:read

Valida ante el PSC una constancia que ya tengas: envía sha256, folio y constanciaBase64.
{ "valid": true, "provider": "codex", "message": "Constancia válida" }

GET/verify/{sha256}

Verificación pública, sin llave: integridad en Certifick, constancia NOM-151, anclaje en blockchain y sello institucional de una huella. Ideal para portales de consulta de tus clientes.

Endpoints de firma electrónica

POST/envelopesenvelopes:write

Crea un sobre con uno o más PDF en base64 y, por defecto, lo envía a firma de inmediato (send: false lo deja en borrador). Cada archivo se certifica con NOM-151 al cerrarse el sobre. psc es opcional: elige un PSC habilitado en tu país (consulta GET /psc); si lo omites se usa el PSC asignado a tu organización.
curl -X POST https://certifick.com/api/public/v1/envelopes \
  -H "Authorization: Bearer $CERTIFICK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Contrato de arrendamiento 4471",
    "message": "Favor de firmar antes del viernes.",
    "signingOrder": "paralelo",
    "expiresInDays": 15,
    "send": true,
    "externalId": "ERP-4471",
    "psc": "cincel",
    "documents": [{ "name": "contrato.pdf", "contentBase64": "JVBERi0xLjQK..." }],
    "signers": [
      { "fullName": "Ana Ruiz", "email": "ana@cliente.com", "role": "Firmante" },
      { "fullName": "Auditoría", "email": "audit@cliente.com", "role": "Observador" }
    ]
  }'

# 201 Created
{ "id": "8f0e...", "folio": "MX-8F0E4C21", "status": "en_proceso" }

GET/envelopes?status=&page=&pageSize=envelopes:read

Lista paginada de los sobres de la organización, con folio, estatus y conteos.

GET/envelopes/{id}envelopes:read

Estatus completo: participantes con su estado y fecha de firma, archivos con su huella SHA-256 y su constancia NOM-151, y la bitácora de eventos.

POST/envelopes/{id}/sendenvelopes:write

Envía a firma un sobre que quedó en borrador.

GET/envelopes/{id}/documents/{documentId}envelopes:read

Devuelve un enlace firmado (15 minutos) al PDF certificado con las firmas estampadas y la constancia NOM-151 en base64.

Coordenadas, tipo de firma y PSC (v1.4)

Todo es opcional y compatible con integraciones actuales. Cada firmante acepta fields[] con document (1 = primer archivo, o su nombre), page, x, y, width y height en porcentaje de la página (0–100, desde la esquina superior izquierda) y kind: firma, iniciales, fecha, nombre o texto. signatureType puede ser dibujada, tipografiada, efirma (solo México) o libre. Además: externalId por firmante, requireLiveness, role: "observador", messageTemplate, reminderEveryDays y documents[].psc para elegir el PSC de un archivo concreto.

"documents": [{ "name": "contrato.pdf", "contentBase64": "JVBERi0...", "psc": "cincel" }],
"signers": [{
  "fullName": "Ana Ruiz", "email": "ana@cliente.com", "externalId": "EMP-77",
  "signatureType": "dibujada", "requireLiveness": false,
  "fields": [
    { "document": 1, "page": 3, "x": 10, "y": 80, "width": 30, "height": 8, "kind": "firma" },
    { "document": 1, "page": 1, "x": 88, "y": 92, "width": 8, "height": 4, "kind": "iniciales" }
  ]
}]

Prueba de vida y e.firma (v1.5)

requireLiveness: true pide la prueba de vida al firmante y revisa el saldo de la bolsa antes de enviar el sobre (402 si no alcanza). Cada firmante devuelve liveness con status (pendiente, en_proceso, aprobada, rechazada, expirada), provider, startedAt, updatedAt y finishOn: con e.firma la firma siempre concluye en la computadora donde se abrió el enlace, aunque la prueba se haga en el celular; con firma dibujada o tipografiada se termina en el equipo donde se hizo la prueba. Los avisos envelope.signer_liveness_approved y envelope.signer_liveness_rejected se activan por organización en su configuración de avisos.

"liveness": {
  "status": "aprobada",
  "provider": "didit",
  "startedAt": "2026-10-14T18:11:04Z",
  "updatedAt": "2026-10-14T18:12:37Z",
  "finishOn": "computadora"
}

POST/envelopes/{id}/remindenvelopes:write

Recordatorio inmediato a todos los firmantes pendientes.

POST/envelopes/{id}/cancelenvelopes:write

Cancela el sobre ({ reason } opcional) y revoca los enlaces vigentes.

POST/envelopes/{id}/documents/{documentId}/replaceenvelopes:write

Sube la versión corregida de un documento rechazado ({ name, contentBase64, psc? }); todos los firmantes vuelven a firmarlo. Consume 1 certificado.

POST/envelopes/{id}/documents/{documentId}/withdrawenvelopes:write

Retira un documento en firma o rechazado y devuelve su certificado; el sobre puede cerrarse con los demás.

Gestión de firmantes

Estatus: pendiente (en espera de turno), enviado, visto, firmado, rechazado, reemplazado, expirado. Un firmante que ya firmó algún documento o que rechazó no puede editarse ni reemplazarse (409). Tras cambiar el correo o reemplazar, el enlace anterior deja de funcionar. Envía el encabezado Idempotency-Key en PATCH, replace y remind para reintentar sin duplicar acciones.

GET/envelopes/{id}/signersenvelopes:read

Firmantes con externalId, fechas de envío, vista, firma y rechazo, y última notificación.

GET/signers/pending-documents?email=&page=&pageSize=envelopes:read

Consulta los documentos pendientes de firma de un usuario por su correo, aunque no tenga cuenta registrada. Solo devuelve archivos de la organización de tu llave API, uno por asignación pendiente; no incluye observadores, firmas realizadas, rechazadas ni archivos retirados o sobres vencidos. Incluye pendientes en espera de turno (waitingForTurn). Paginación de 15 por defecto, máximo 100. No genera enlaces ni elimina la prueba de vida u OTP.
curl --get https://certifick.com/api/public/v1/signers/pending-documents \
  -H "Authorization: Bearer $CERTIFICK_API_KEY" \
  --data-urlencode "email=ana@cliente.com" \
  --data-urlencode "page=1" \
  --data-urlencode "pageSize=15"

{ "data": [{
  "id": "archivo-en-sobre", "documentId": "documento", "name": "contrato.pdf",
  "status": "en_firma", "signatureStatus": "enviado", "signerId": "firmante",
  "requiredSignatureType": "efirma", "requireLiveness": true, "waitingForTurn": false,
  "envelope": { "id": "sobre", "title": "Contrato", "externalId": "CRM-1029",
    "status": "en_proceso", "signingOrder": "paralelo", "expiresAt": null,
    "sentAt": "2026-10-28T23:00:00Z" }
}], "total": 1, "page": 1, "pageSize": 15 }

GET/envelopes/{id}/signers/{signerId}envelopes:read

Detalle de un firmante.

PATCH/envelopes/{id}/signers/{signerId}envelopes:write

Corrige fullName, email o externalId de la misma persona. Si cambia el correo se envía una invitación nueva.

POST/envelopes/{id}/signers/{signerId}/replaceenvelopes:write

Sustituye al firmante por otra persona ({ fullName, email, externalId, reason }). El nuevo hereda su lugar, sus firmas pendientes y sus campos.

POST/envelopes/{id}/signers/{signerId}/remindenvelopes:write

Reenvía la invitación; máximo una vez cada 10 minutos por firmante (429).

Webhooks firmados

Registra una URL HTTPS y suscríbete a los eventos que necesites. Cada entrega incluye X-Zign-Event, X-Zign-Timestamp y X-Zign-Signature. Valida la firma recalculando el HMAC-SHA256 de `${timestamp}.${cuerpo}` con tu secreto antes de procesar el evento.

const esperado = "sha256=" + crypto
  .createHmac("sha256", process.env.CERTIFICK_WEBHOOK_SECRET)
  .update(timestamp + "." + rawBody)
  .digest("hex");

Eventos: nom151.constancia.emitida, nom151.constancia.fallida, envelope.created, envelope.sent, envelope.signer_signed, envelope.completed, envelope.declined, envelope.document.declined, envelope.expired, document.certified, envelope.document.completed, envelope.document.replaced, envelope.document.withdrawn, envelope.partially_completed, envelope.cancelled, envelope.signer_viewed, envelope.signer_updated, envelope.signer_replaced, envelope.signer_declined, envelope.signer_liveness_approved y envelope.signer_liveness_rejected (con el firmante completo y los externalId). Cada firmante trae liveness con status (pendiente, en_proceso, aprobada, rechazada, expirada), fechas y finishOn (computadora con e.firma, o el dispositivo de la prueba). Estados del sobre: borrador, en_proceso, completado, completado_parcial (algunos archivos rechazados o retirados), rechazado, expirado, cancelado. Cada archivo en documents[] trae status (en_firma, completado, rechazado, retirado) y declinedReason.

Anclaje blockchain

Cada huella certificada se agrega como hoja de un árbol Merkle diario cuya raíz se ancla en Bitcoin a través de OpenTimestamps. Cualquiera puede comprobar que un documento formó parte de ese conjunto sin revelar su contenido.

# Consultar el anclaje de una fecha (público)
GET https://certifick.com/api/public/v1/blockchain/anchors/2026-08-31

# Verificar un archivo desde el navegador (el archivo nunca se sube)
https://certifick.com/verificar-blockchain

Errores

{ "error": true, "code": "insufficient_credits", "message": "Sin certificados disponibles." }
HTTPcodeQué hacer
400invalid_hash / invalid_json / missing_inputCorrige la petición
401unauthorizedRevisa la llave
403forbidden_scopeAgrega el alcance a la llave
402insufficient_creditsCompra certificados en el backoffice
404not_foundFolio o huella inexistente
422psc_rejectedDatos rechazados por el PSC; no reintentes igual
429rate_limitedEspera y reintenta con retroceso exponencial
404envelope_not_found / signer_not_found / document_not_foundRevisa los identificadores
409signer_already_signed / signer_not_editableEl firmante ya no puede modificarse
409envelope_closedEl sobre está completado, expirado o cancelado
422field_out_of_bounds / field_page_not_foundCorrige las coordenadas o la página
422invalid_signature_type / psc_not_availableUsa un tipo de firma o PSC disponible
429remind_rate_limitedEspera 10 minutos antes de reenviar
503psc_unavailableReintenta en unos minutos; el cobro se reversa

Checklist de integración

Nuestros certificados no tienen vigencia: se consumen al usarse y no caducan.

Volver al inicio