Emita y verifique desde sus propios sistemas
Una API REST con JSON y claves API con permisos limitados, además de webhooks firmados que informan a sus sistemas lo que ocurre con cada certificado. El acceso a la API está incluido en todos los planes, incluido el plan gratuito Starter.
Autenticación
Cree una clave API en la aplicación, en Configuración y luego Claves API. Elija los permisos que necesita y, si lo desea, una caducidad en días. La clave completa (empieza con crtfd_live_) se muestra una sola vez, así que guárdela en un lugar seguro. Envíela como token bearer:
Authorization: Bearer crtfd_live_your_key_here
Todos los endpoints están bajo https://certifyd.cloud/api/v1 y usan JSON. Las respuestas correctas envuelven el contenido como { "data": ... }. Los errores llegan como { "error": { "code", "message" } }. Los códigos comunes son INVALID_API_KEY, INSUFFICIENT_SCOPE (la respuesta indica el permiso que falta) y CREDIT_LIMIT (HTTP 402, ya usó sus créditos mensuales). Las solicitudes tienen límite de frecuencia. Espere antes de reintentar si recibe HTTP 429.
Permisos
| Permiso | Permite |
|---|---|
| events:read, events:write | Leer, o crear / actualizar / eliminar, eventos y su configuración de registro |
| attendees:read, attendees:write | Leer, o crear / actualizar / eliminar / importar, asistentes |
| templates:read, templates:write | Leer, o administrar, plantillas de certificados |
| certificates:generate | Emitir, regenerar y generar certificados de forma masiva |
| certificates:read, certificates:write | Leer y descargar certificados, o revocarlos, eliminarlos y enviarlos |
| badges:read, badges:write | Leer, o crear / actualizar / eliminar / emitir, insignias |
| analytics:read | Analítica del panel y por evento |
| webhooks:manage | Administrar suscripciones de webhooks y consultar sus entregas |
Ejemplo: emitir un certificado y verificarlo
La clave necesita los permisos templates:read, events:write, attendees:write y certificates:generate. Cada certificado emitido usa un crédito. Los ejemplos usan jq para extraer valores del JSON.
# 0. Your key and the API address
export CERTIFYD_KEY="crtfd_live_your_key_here"
export API="https://certifyd.cloud/api/v1"
# 1. Pick one of your templates (take the "id" of any entry in data)
curl -s "$API/templates?active=true" \
-H "Authorization: Bearer $CERTIFYD_KEY" | jq '.data[] | {id, name}'
export TEMPLATE_ID="paste-a-template-id-here"
# 2. Create an event
export EVENT_ID=$(curl -s -X POST "$API/events" \
-H "Authorization: Bearer $CERTIFYD_KEY" \
-H "Content-Type: application/json" \
-d "{\"name\":\"Safety Training\",\"eventDate\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"templateId\":\"$TEMPLATE_ID\"}" \
| jq -r '.data.id')
# 3. Add an attendee
export ATTENDEE_ID=$(curl -s -X POST "$API/attendees" \
-H "Authorization: Bearer $CERTIFYD_KEY" \
-H "Content-Type: application/json" \
-d "{\"eventId\":\"$EVENT_ID\",\"firstName\":\"Ana\",\"lastName\":\"Rivera\",\"email\":\"ana@example.com\"}" \
| jq -r '.data.id')
# 4. Issue the certificate ("sendEmail": false holds back the delivery email).
# The Idempotency-Key makes a retry of this exact request safe (see below).
export CODE=$(curl -s -X POST "$API/certificates/generate" \
-H "Authorization: Bearer $CERTIFYD_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d "{\"templateId\":\"$TEMPLATE_ID\",\"eventId\":\"$EVENT_ID\",\"attendeeId\":\"$ATTENDEE_ID\",\"sendEmail\":false}" \
| jq -r '.data.verificationCode')
echo "Verification code: $CODE"
# 5. Verify it. This endpoint is public: no API key needed.
curl -s "$API/verify/$CODE"
La respuesta de verificación incluye status (valid, expired o revoked), el destinatario, la credencial, el emisor y las fechas. El mismo código abre la página legible en https://certifyd.cloud/verify/<code>. Consulte cómo verificar una credencial.
Los reintentos nunca emiten dos veces
Un asistente tiene como máximo un certificado válido por evento y plantilla. Si POST /certificates/generate indica un asistente que ya tiene uno, la API responde HTTP 409 con el código ALREADY_ISSUED y un encabezado Location que apunta al certificado existente; el miembro existing del cuerpo del error incluye su id, certificateNumber y verificationCode. No se emite, envía ni cobra nada. Un certificado revocado o vencido no cuenta, por lo que puede emitir uno nuevo después.
POST /badges/{id}/issue funciona igual para cada asistente. Un asistente que ya tiene la insignia aparece en la respuesta con "alreadyIssued": true, y solo las insignias nuevas usan créditos.
Ambos endpoints aceptan además un encabezado opcional Idempotency-Key: de 1 a 255 caracteres imprimibles, idealmente un UUID que usted genera para cada solicitud. Si la misma clave llega de nuevo con el mismo cuerpo dentro de 24 horas, la API responde HTTP 200 con la respuesta original y el encabezado Idempotent-Replayed: true. La misma clave con un cuerpo distinto se rechaza con HTTP 422 IDEMPOTENCY_KEY_REUSED. Una repetición que llega mientras la primera solicitud aún se procesa recibe HTTP 409 IDEMPOTENCY_IN_PROGRESS; reinténtela un momento después. Una solicitud que falló no se recuerda, por lo que puede reintentarla con la misma clave.
Eliminar una credencial emitida
DELETE /certificates/{id} sobre un certificado ya emitido lo revoca con el motivo "Deleted by issuer" (la respuesta pública de verificación incluye además revocationReasonCode: "deleted_by_issuer") en lugar de borrarlo, de modo que quien escanee su código QR vea "revocado" y nunca "no encontrado". Solo se elimina un borrador que nunca se emitió. DELETE /badges/{id} sobre una insignia ya emitida la retira: deja de aparecer en su lista y las insignias ya emitidas a partir de ella quedan revocadas. Un asistente que aún tiene certificados no se puede eliminar (HTTP 409 ATTENDEE_HAS_CERTIFICATES), ni tampoco uno al que se le han emitido insignias (HTTP 409 ATTENDEE_HAS_BADGES).
Endpoints
Todas las rutas siguientes son relativas a /api/v1.
| Área | Endpoints |
|---|---|
| Eventos | GET/POST /events GET/PUT/DELETE /events/{id} GET /events/{id}/attendees GET /events/{id}/certificates GET/PUT /events/{id}/registration |
| Emisión masiva | POST /events/{id}/certificates/generate POST /events/{id}/certificates/generate/jobs GET /events/{id}/certificates/generate/jobs/{jobId} |
| Asistentes | GET/POST /attendees GET/PUT/DELETE /attendees/{id} GET /attendees/count POST /attendees/import GET /events/{id}/attendees/export |
| Plantillas | GET/POST /templates GET/PUT/DELETE /templates/{id} POST /templates/{id}/duplicate POST /templates/{id}/preview GET /system-templates |
| Certificados | POST /certificates/generate GET/DELETE /certificates/{id} GET /certificates/{id}/download POST /certificates/{id}/regenerate POST /certificates/{id}/revoke POST /certificates/{id}/send |
| Insignias | GET/POST /badges GET/PUT/DELETE /badges/{id} POST /badges/{id}/issue GET /badges/{id}/assertions |
| Correo | POST /email/send-bulk GET /email/deliveries |
| Analítica | GET /analytics/dashboard GET /analytics/events/{id} |
| Créditos | GET /credits (créditos usados, límite y restantes este mes) |
| Webhooks | GET/POST /webhooks PUT/DELETE /webhooks/{id} GET /webhooks/{id}/deliveries POST /webhooks/{id}/test |
| Verificación (pública) | GET /verify/{code} GET /verify/{code}/qr GET /verify/{code}/preview.png GET /verify/{code}/badge.png GET /verify/{code}/badge.svg GET /verify/{code}/certificate.pdf |
Webhooks
Suscriba un endpoint HTTPS con POST /webhooks (o en la aplicación, en Configuración y luego Webhooks) y elija los eventos que recibirá. Los endpoints deben usar HTTPS y resolver a una dirección pública. El secreto de firma se devuelve una sola vez, al crear la suscripción.
| Evento | Se envía cuando |
|---|---|
| certificate.issued | Se genera un certificado, individualmente o de forma masiva |
| certificate.sent | Se envía un certificado por correo a su destinatario |
| certificate.viewed | El destinatario abre su enlace del portal por primera vez |
| certificate.downloaded | El destinatario descarga el PDF del certificado desde el portal |
| certificate.revoked | Usted revoca un certificado |
También puede enviarse una muestra con POST /webhooks/{id}/test, que entrega un evento webhook.test.
Qué recibe
POST https://your-server.example/certifyd-hook
Content-Type: application/json
X-Certifyd-Event: certificate.issued
X-Certifyd-Delivery: 7c0e5b0e-0000-0000-0000-000000000000
X-Certifyd-Timestamp: 1790000000
X-Certifyd-Signature: sha256=3f1c...e9
{ "eventType": "certificate.issued", "timestamp": "...", "data": { "certificateId": "...", "certificateNumber": "...", "eventId": "...", "attendeeId": "...", "status": "...", "verificationCode": "CFD-7X4K-92QM" } }
La firma es un HMAC-SHA256 en hexadecimal de "{timestamp}.{cuerpo sin modificar}" con el secreto de su suscripción como clave. Verifíquela, rechace marcas de tiempo con más de unos minutos de antigüedad y use X-Certifyd-Delivery para ignorar duplicados. No cambia entre reintentos.
# Recompute the signature on your side (bash + openssl) printf '%s.%s' "$TIMESTAMP" "$RAW_BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET"
Cada entrega tiene un tiempo límite de 10 segundos. Una entrega fallida se intenta hasta 5 veces en total, tras 1 minuto, 5 minutos, 30 minutos y 2 horas. Una suscripción que sigue fallando se desactiva tras 10 intentos fallidos seguidos.
Lo que no está disponible
Todavía no hay bibliotecas cliente oficiales ni un documento OpenAPI publicado. Tampoco hay un conector nativo de Zapier o Make: cualquier herramienta que pueda enviar solicitudes HTTPS y recibir webhooks puede integrarse con los endpoints anteriores.