/v1/invoices. An invoice is a
CFDI you stamped through this API. A sat_document is any CFDI the SAT has on file for that
RFC — including a supplier’s invoice to the taxpayer, and everything they issued long before
they ever integrated with you.
It is also different from massive download: that is an on-demand pull for
one date range, hemmed in by hard SAT limits. This is a standing sync you turn on once.
1. Attach a FIEL
Sync authorizes with the taxpayer’s FIEL (e.firma) — not the CSD. Attach it to the fiscal profile (fiel_cer, fiel_key, fiel_password); without one you get
422 sync.fiel_required.
2. Turn sync on
Enabling is idempotent — re-enabling an already-registered RFC is a no-op, not an error.
The backfill runs in the background, chunk by chunk. Six years of history is many small jobs, not
one enormous request, so it makes steady progress rather than timing out.
3. Read the documents
fiscal_profile_id, side (issued / received), and status
(vigente / cancelado); cursor-paginate with starting_after. Each row carries the folio
fiscal (uuid), both parties, total, subtotal, type, serie/folio, and the SAT status.
Cancellations flow through: if a CFDI you already mirrored is cancelled later, the next sync flips
its status to cancelado and fills cancelled_at on the same row.
Freshness: expect 1–3 days, and we tell you exactly
synced_through is the honest watermark — we have your CFDIs up to and including this date.
lag_days is how far that trails today.
A healthy sync sits 1–3 days behind, and that floor cannot be beaten. It is not our latency:
the SAT itself does not publish a CFDI to its bulk-download service until roughly 24–72 hours
after it is issued. Any vendor claiming real-time SAT data for received invoices is describing
something the SAT does not offer.
So: use /v1/invoices for the CFDIs you stamp (those are immediate). Use SAT sync for the
complete fiscal picture, and read synced_through before you reconcile a period.
Health: enabled is not the same as working
The upstream sync can stop silently. When the SAT rejects one of its requests, it stops
fetching for that RFC and does not recover on its own — while still reporting itself as enabled.
Left alone, a taxpayer’s data simply stops updating and nothing says so.
We watch the watermark instead of the flag. If it stops advancing, we mark the profile
stalled, attempt an automatic repair, and fire a webhook:
fiscal_profile.sync_stalled. It is the only warning that a taxpayer’s fiscal
data has quietly gone stale.
When the automatic repair is not enough: an expired FIEL
The most common cause of a permanent stall is an expired or revoked e.firma. This one is nasty, and worth understanding:- A FIEL is not validated when you register it. Registration succeeds with a dead certificate.
- The failure only appears later, when the SAT rejects the data requests.
- The result looks identical to a transient stall — except no repair fixes it.
.cer/.key
to the fiscal profile, and then call POST /v1/fiscal_profiles/:id/sync again. Re-enabling
pushes the renewed certificate to the sync service (it does not just re-toggle), so the nightly job
recovers on its next run. No amount of retrying the old certificate will substitute. If a profile
stays stalled after a repair attempt, check the certificate’s validity before anything else.
Status reference
Turning it off
Next
- Massive download — one-off pull for a specific range
- Webhooks — subscribe to
fiscal_profile.sync_stalled - Error codes:
../errors.md(thesync.*family)