https://api.newinvoice.dev. Do it all in test mode (an sk_test_... key) — test-mode stamps
hit the PAC’s test environment, so nothing here touches SAT production and no real CFDI is issued.
When you’re ready for real invoices, swap the test key for a live one (see
Going live).
0. Get your API key
Sign up athttps://api.newinvoice.dev/signup and open the
dashboard. Each organization gets a test key (sk_test_...) and a live key
(sk_live_...); copy the test key — it’s shown once.
/v1 call needs Authorization: Bearer $API_KEY. The key’s mode scopes all data: a test key
never sees live resources and vice-versa, and livemode appears on every resource.
1. Register a fiscal profile (emitter + CSD)
An invoice is issued by a fiscal profile: an RFC plus its CSD (Certificado de Sello Digital). Upload the.cer and .key files directly (multipart) with the private-key password; the RFC,
serial and validity window are read from the certificate. The key material is AES-256-GCM encrypted
at rest and never returned.
csd_cer, csd_key, csd_password for the CSD, and fiel_cer,
fiel_key, fiel_password if you also attach a FIEL. Prefer JSON? Send the same data as
application/json with csd: { cer_base64, key_base64, password } — both content types are accepted.
Testing without a production CSD? Test mode tolerates expired and SAT test certificates, so
you can onboard with a free SAT test CSD. Live mode rejects expired CSDs (422
fiscal_profile.csd_expired) — use a current CSD to go live.
The profile comes back on hold. A brand-new profile has not yet been authorized to stamp, so
its response carries status: "requires_action" and a single next_actions entry telling you
exactly what to do next:
pending_actions. When the profile is
authorized both arrays are [] and status is "active".
2. Sign the carta manifiesto
The PAC requires a signed carta manifiesto per RFC to authorize timbrado (invoice stamping) for that taxpayer — this is the SAT/PAC authorization, not the CSD. This API signs it for you; there is no browser portal to visit. The gate applies in test mode too, so you sign it once here before stamping. The manifiesto is signed with the taxpayer’s FIEL (e.firma):-F cer= -F key= -F password= (or fiel: { cer_base64, key_base64, password \} in JSON), or reuses a FIEL already stored on the profile. On success the
manifiesto is signed once and for all: the profile flips to status: "active" (manifest_status: "signed"), next_actions/pending_actions empty out, and a fiscal_profile.manifest_signed
webhook fires. Signing is idempotent — an “already signed” result is treated as success.
Skip this step and the very next stamp attempt returns 409 fiscal_profile.manifest_required
(in both test and live), with remediation pointing back to this endpoint. Every stamp call checks
the manifiesto, so you only ever sign it once per profile.
3. Create + stamp an invoice
Send friendly JSON. You do not send the issuer — it comes from the profile. Omit taxes and each item defaults to 16% IVA traslado;subtotal/total are computed and rounded to the
currency’s decimals.
status: "stamped", a real uuid (folio fiscal), total: "116.00", serie: "A",
folio: "1", the sello_cfd/sello_sat, and xml_url/pdf_url.
Required fields, briefly
Common coherence rules the API enforces (returned as 422
cfdi.invalid_input with a path):
payment_method: "PPD"forcespayment_form: "99"(Por definir).- Type
Pmust not carry items orpayment_method; it needspayments. - Type
Eshould carryrelation(type01nota de crédito or03devolución) + original UUID. - Receptor
XAXX010101000(público en general) requiresglobal_information. - Non-MXN
currencyrequiresexchange_rate.
4. Draft, then stamp later (optional)
Pass"draft": true to build and sign without stamping; the invoice returns status: "draft".
Stamp it when ready:
5. Fetch the artifacts
Idempotency
SendIdempotency-Key: <unique> on POSTs. A retry with the same key + identical body replays the
stored response (idempotent-replayed: true) instead of stamping twice; a different body under
the same key → 409 idempotency.key_reuse. The PAC’s own duplicate code 307 is also resolved as
a success-replay of the prior stamp, so double submits never mint two CFDIs.
Next
- Cancellation · Webhooks · Going live
- Full field reference:
/openapi.json· error codes:../errors.md