Extractions

An extraction downloads CFDI from the SAT for a date range, parses the XML, links related documents, and updates invoice aggregates.

Lifecycle

stateDiagram-v2
    [*] --> pending: POST /v1/extractions
    pending --> running: Worker picks up job
    running --> finished: All months processed
    running --> failed: Unrecoverable error
    failed --> running: Automatic retry
    finished --> [*]

Request and processing

sequenceDiagram
    autonumber
    participant App as Your app
    participant API as Meefi API
    participant Worker as Processing
    participant SAT as SAT portal

    App->>+API: POST /v1/extractions
{ entity_id, options.period } API-->>-App: 201 { id, status: pending } API->>Worker: Dispatch job Worker->>Worker: status → running API->>App: webhook extraction.update (running) loop Each month in period Worker->>+SAT: List CFDI metadata SAT-->>-Worker: UUID list + status fields Worker->>Worker: Upsert invoice metadata Worker->>SAT: Download XML / PDF Worker->>Worker: Parse & store fields end Worker->>Worker: Resolve payment → invoice links Worker->>Worker: Recompute PPD aggregates Worker->>Worker: status → finished API->>App: webhook extraction.update (finished) App->>+API: GET /v1/extractions/{id} API-->>-App: 200 { status: finished }

Extraction object

Field Type Description
id UUID Extraction ID
status string pending, running, finished, failed
tries integer Number of processing attempts
entity object Nested entity summary (id, tax_id, name)
options object Request options (period, download type)
started_at datetime When processing started
finished_at datetime When processing completed or failed
created_at datetime When the extraction was created

Start an extraction

POST /v1/extractions

{
  "entity_id": "9e08bb63-f6c1-44cf-a5b5-a92967cb172d",
  "options": {
    "period": {
      "from": "2026-01-01",
      "to": "2026-06-03"
    },
    "download_type": "issued"
  }
}

Options

Field Type Description
options.period.from date Start of date range (inclusive)
options.period.to date End of date range (inclusive)
options.download_type string issued (default) or received

Long date ranges are processed month by month against the SAT.

Returns 201 Created. Processing is asynchronous — poll or use webhooks.

Monitor progress

GET /v1/extractions/{id}

Poll until status is finished or failed. Alternatively, subscribe to extraction.update webhooks.

List extractions for an entity

GET /v1/entities/{entity_id}/extractions?per_page=50

Returns paginated extractions ordered by newest first.

What happens during an extraction

  1. Authenticate to the SAT with the entity CIEC
  2. List CFDI metadata for each month in the period
  3. Download and parse XML and PDF files
  4. Link payment complements to their target invoices
  5. Link credit notes to related invoices
  6. Refresh paid_amount, due_amount, and credited_amount on affected invoices

Re-running an extraction for the same period is safe and produces consistent results.

Historical coverage

Payment complements (type P) reference UUIDs of original invoices (type I). If you only extract recent months:

  • Complements download successfully
  • Payment data is stored against the target UUID
  • Aggregates on the target invoice update once that invoice is included in a later extraction with an earlier date range
flowchart TD
    A["Day 1: Extract last 30 days"] --> B["Type P complements arrive"]
    B --> C["Payments stored · UUID link pending"]
    C --> D["Day 7: Backfill 12 months"]
    D --> E["Type I originals downloaded"]
    E --> F["Aggregates refreshed on invoice"]

Recommendation: run a wide initial backfill (12+ months), then incremental syncs.

Retries and failures

Failed extractions are retried automatically. Common causes:

  • Invalid or expired CIEC (credential_status: invalid)
  • SAT connectivity or availability issues

When status is failed, check failed_reason on the extraction resource.

Webhook events

Status transitions emit extraction.update with the latest extraction object in the payload.