Skip to content

Integration Guide — Partner API

This guide covers the full lifecycle of a purchase_code: issuing it, redeeming it (validating the holder’s identity), and retrieving the already-issued certificate. There are two separate APIs, on two different servers:

  • Purchase Code API (partner-pcode, Cloudflare Worker, /api/partner/v1) — generates and lists purchase_codes.
  • Partner API (/api/partners/v1) — redeems identity and delivers certificates.

1. Your configuration decides the flow, not the endpoint

Section titled “1. Your configuration decides the flow, not the endpoint”

Unlike previous versions of this API, there is a single redeem endpoint (certificate_request). Its behavior adapts automatically based on your partner configuration:

Your configuration What happens in certificate_request
require_cedula_serie = 0 (full flow, default) You must send names/fLastname/phone. Validated against Clave Única in addition to the civil registry.
require_cedula_serie = 1 (reduced flow) Don’t send names/fLastname/phone — they come from the civil registry. You must send serialNumber (ID card serial). No Clave Única.
mode = 1 (B2C, default) The certificate is only delivered once you call certificate_claim.
mode = 2 (B2B) The certificate is generated and delivered automatically (webhook/email) in the same certificate_request call — don’t call certificate_claim, it will always say “already issued”.

These two settings are independent — you can have reduced flow + B2B, full flow + B2C, or any other combination. Contact support to configure them.

  1. Issue a purchase_codePOST /pcode on the Purchase Code API.

    Ventana de terminal
    curl -X POST https://partner-pcode.tsp.workers.dev/api/partner/v1/pcode \
    -H "x-gw: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"productCode": "FV01", "external_reference_id": "order-12345"}'

    This call can fail with 400 if your partner doesn’t have that productCode enabled — each partner can be restricted to a subset of products (FV00-FV03). If you’re not sure which products you have access to, contact support.

  2. Redeem the purchase_codePOST /certificate_request. Which fields you send depends on your flow (see table above). Example with the reduced flow:

    Ventana de terminal
    curl -X POST https://api.firma.digital/api/partners/v1/certificate_request \
    -H "x-gw: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
    "pCode": "MYPARTNER-26-FV01-A1B2C3D4",
    "referenceId": "order-12345",
    "dni": "18925910-7",
    "serialNumber": "536463312",
    "email": "user@example.com",
    "pin": "1234"
    }'

    The response comes back with status: "VALIDATED" — the certificate doesn’t exist yet, only identity was verified.

  3. Retrieve the certificatePOST /certificate_claim, with the same pin used in the previous step (it doubles as the PFX’s password).

    Ventana de terminal
    curl -X POST https://api.firma.digital/api/partners/v1/certificate_claim \
    -H "x-gw: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"p_code": "MYPARTNER-26-FV01-A1B2C3D4", "dni": "18925910-7", "pin": "1234"}'

    This call is one-time only: calling it again responds 201 with ALREADY_ISSUED instead of regenerating the certificate. If you need to recover it after it was already claimed, contact support.

Same as steps 1 and 2 above, except step 2 is already the last one: if your configuration has mode = 2, the certificate_request response comes back with status: "EMITTED" and the certificate is delivered automatically through your configured webhook and/or email — both can fire at once, it’s not either/or. There is no step 3.

GET /status?p_code=... — most useful if you integrated via the widget (the user completes the flow in their own browser, not in a single call you make) and you need to know how far along they are without listening to widget events in real time.

Ventana de terminal
curl "https://api.firma.digital/api/partners/v1/status?p_code=MYPARTNER-26-FV01-A1B2C3D4" \
-H "x-gw: $API_KEY"

Possible states, in precedence order (the first one that applies wins):

State Meaning
CANCELLED Voided (order cancelled) — wins even over an already-issued certificate.
EXPIRED The certificate was issued but has since expired.
EMITTED Certificate generated and delivered.
LOCKED Blocked before it got issued — if it was already issued, this doesn’t show: it still reports EMITTED.
IN_ONBOARDING The user is midway through the widget flow.
VALIDATED Identity verified (B2C only), certificate_claim still pending.
ACTIVE Exists, nobody has redeemed it yet.
NOT_FOUND The purchase code doesn’t exist.
Code Cause
401 Invalid or missing API Key.
404 The purchase_code doesn’t exist (or, in certificate_claim, exists but never went through certificate_request).
406 Business rejection — the message field says which: serial required, RUT mismatch, duplicate email, ID card doesn’t match the civil registry, expiration date mismatch, etc.
423 The purchase_code is permanently blocked (voided).
429 Rate limit — 10 emissions per minute per partner, or ID validation attempts exhausted (temporary security lock).

See the Partner API Reference and the Purchase Code API Reference for full details on each endpoint.