---
title: "Build your first integration"
description: "Set up a sandbox API key, make your first request, and follow the REST and MCP workflows."
language: en
canonical_url: "https://exac.mx/docs/en/quickstart"
md_url: "https://exac.mx/docs/en/quickstart.md"
---

# Build your first integration

Set up a sandbox API key, make your first request, and follow the REST and MCP workflows.

## Production and sandbox

Organization API keys are bound to one environment. Sandbox keys use the operations marked “Production and sandbox” in the API reference against isolated test data. Production-only operations and MCP remain unavailable in sandbox. Credentials are rejected outside their assigned environment.

## Make your first authenticated request

Start with an isolated sandbox organization and a sandbox API key.

### 1. Open the developer console

Open /consola from Exac, select Test, and open API keys for your current workspace.

### 2. Create a sandbox API key

Create a key for Test and copy it once. Exac prepares the isolated environment automatically.

### 3. Verify the sandbox organization

Call GET /v1/organization with the sandbox key against the sandbox server shown in OpenAPI.

### 4. Run a Test workflow

Create a contact and CFDI draft, then create, retrieve, and cancel a test stamp. Sandbox artifacts are not submitted to SAT and have no fiscal validity.

```bash
curl "https://grateful-squid-667.convex.site/v1/organization" \
  --header "Authorization: Bearer <EXAC_API_KEY>"
```

## Request, response, and retry conventions

### Authentication and JSON

Send Authorization: Bearer <credential> on every API request and Content-Type: application/json when sending a JSON body. JSON successes use { data }; paginated responses also include pagination. Failures use { error: { code, message, status, details? } }. Branch on error.code, not the human message, and retain the Request-Id response header for diagnostics. File downloads return bytes instead of a JSON envelope.

### Safe retries

Every write requires Idempotency-Key, including the first attempt. Generate a unique key per intended operation and preserve it with the request.

After a timeout, retry with the same credential, key, path, and payload. Changing the operation or payload under a retained key returns idempotency_conflict.

Keys are scoped to the organization and calling identity, across REST and MCP; switching credentials can change that scope. Successful operations replay their original result, which can differ from the current resource state.

### Retry limits and recovery

Idempotency records are retained for 7 days; API-key creation secrets can be replayed for 15 minutes. Do not rely on deduplication after the window: reconcile the resource before submitting another write.

Wait for Retry-After when present. Never automatically retry recovery_required or details.retryable = false, and never change keys to bypass an uncertain outcome.

Use details.document.documentRef to inspect an affected document when supplied.

### Pagination and identifiers

Start without cursor, then pass pagination.nextCursor unchanged with the same filters until pagination.hasMore is false. A short or empty page is not the end when hasMore is true.

IDs and documentRef values are opaque and organization-scoped: store the complete returned value, including a documentRef prefix, and URL-encode it as a path segment. Do not substitute a SAT UUID for documentRef.

### Dates, amounts, and missing fields

Instants use RFC 3339 with an offset, for example 2026-07-15T18:00:00.000Z.

Calendar dates use YYYY-MM-DD; calendar months use YYYY-MM.

CFDI fields ending in LocalDateTime are civil time without an offset: do not append Z or assume UTC.

Standard { amount, currency } money objects use numeric major units (116 means 116 pesos for MXN); fields ending in Minor use minor units, such as centavos.

Some fiscal amounts, tax bases, and rateOrFee fields use exact decimal strings: preserve their schema-declared type and precision instead of converting to floating point or cents.

Numeric tax rates are fractions, such as 0.16 for 16%.

Optional fields may be omitted; send null only when the schema explicitly allows it.

## Canonical workflows

Use the same domain intent through REST or MCP. These examples are validated against the runtime contracts; replace example identifiers and credentials with values from your organization.

### Test a CFDI lifecycle in sandbox

Create, stamp, download, and cancel a non-fiscal test CFDI using only sandbox REST operations.

#### Verify the organization

Confirm that the sandbox key resolves to the expected isolated organization.

Retry guidance: This read is safe to repeat.

#### Create a test customer

Create the customer with its fiscal identity. Use the returned contactId as customerId in the next request.

Retry guidance: Reuse the same key only for an identical request.

#### Create a CFDI draft

Create a draft that can be reviewed before the explicit test stamp.

Retry guidance: Reuse the same key only for the identical draft payload.

#### Create a test stamp

Sandbox creates a test artifact. It is not submitted to SAT and has no fiscal validity.

Retry guidance: Retry only with the same key and documentRef.

#### Download the test PDF

Download the generated test document from the sandbox receiver.

Retry guidance: This file read is safe to repeat.

#### Cancel the test CFDI

Exercise the cancellation transition against isolated test data.

Retry guidance: Reuse the same key only for the same cancellation request.

```json
{
  "steps": [
    {
      "id": "verify-sandbox-organization",
      "rest": {
        "operationId": "getOrganization",
        "method": "GET",
        "path": "/v1/organization",
        "environments": [
          "production",
          "sandbox"
        ]
      }
    },
    {
      "id": "create-sandbox-contact",
      "rest": {
        "operationId": "createContact",
        "method": "POST",
        "path": "/v1/contacts",
        "environments": [
          "production",
          "sandbox"
        ],
        "headers": {
          "Idempotency-Key": "sandbox-create-contact"
        },
        "body": {
          "kind": "customer",
          "legalName": "Estudio Jacaranda",
          "email": "administracion@jacaranda.example",
          "rfc": "AAA010101AAA",
          "taxSystem": "601",
          "cfdiUse": "G03",
          "address": {
            "postalCode": "82110",
            "country": "MEX"
          }
        }
      }
    },
    {
      "id": "create-sandbox-cfdi",
      "rest": {
        "operationId": "createInvoiceDraft",
        "method": "POST",
        "path": "/v1/invoices",
        "environments": [
          "production",
          "sandbox"
        ],
        "headers": {
          "Idempotency-Key": "sandbox-create-cfdi"
        },
        "body": {
          "customerId": "customer-example",
          "items": [
            {
              "kind": "custom",
              "description": "Consultoría administrativa · julio 2026",
              "quantity": 1,
              "unitPrice": 10000,
              "satProductCode": "84111506",
              "satUnitCode": "E48",
              "taxRate": 0.16,
              "taxability": "standard"
            }
          ],
          "kind": "income",
          "cfdiUse": "G03",
          "payment": {
            "timing": "deferred_or_installments",
            "formCode": "99",
            "conditions": "Crédito a 30 días"
          }
        }
      }
    },
    {
      "id": "stamp-sandbox-cfdi",
      "rest": {
        "operationId": "stampInvoice",
        "method": "POST",
        "path": "/v1/invoices/invoice:invoice-example/stamp",
        "environments": [
          "production",
          "sandbox"
        ],
        "headers": {
          "Idempotency-Key": "sandbox-stamp-cfdi"
        },
        "body": {}
      }
    },
    {
      "id": "download-sandbox-pdf",
      "rest": {
        "operationId": "downloadDocumentFile",
        "method": "GET",
        "path": "/v1/documents/invoice:invoice-example/files/pdf",
        "environments": [
          "production",
          "sandbox"
        ]
      }
    },
    {
      "id": "cancel-sandbox-cfdi",
      "rest": {
        "operationId": "cancelInvoice",
        "method": "POST",
        "path": "/v1/invoices/invoice:invoice-example/cancel",
        "environments": [
          "production",
          "sandbox"
        ],
        "headers": {
          "Idempotency-Key": "sandbox-cancel-cfdi"
        },
        "body": {
          "reason": "02"
        }
      }
    }
  ]
}
```

### Configure fiscal access

Set the organization fiscal identity, upload its CSD, and verify readiness before creating CFDIs.

#### Set the fiscal identity

Use the issuer identity from your tax records, with the RFC matching the CSD you will upload. Update one organization settings section at a time.

Retry guidance: Reuse the same Idempotency-Key only for the exact same section payload.

#### Upload the CSD pair

Upload the certificate and private key as base64; secret material is never returned.

Retry guidance: Retry with the same key and unchanged certificate payload.

#### Verify readiness

Read the organization projection and confirm fiscal readiness before issuing.

Retry guidance: Reads are safe to repeat; do not add an idempotency key.

```json
{
  "steps": [
    {
      "id": "update-fiscal-settings",
      "rest": {
        "operationId": "updateOrganization",
        "method": "PATCH",
        "path": "/v1/organization",
        "environments": [
          "production"
        ],
        "headers": {
          "Idempotency-Key": "workflow-fiscal-settings"
        },
        "body": {
          "section": "fiscal",
          "legalName": "Consultoría Bruma SA de CV",
          "rfc": "EKU9003173C9",
          "taxSystem": "601",
          "address": {
            "postalCode": "82110"
          }
        }
      },
      "mcp": {
        "tool": "update_organization",
        "arguments": {
          "idempotencyKey": "workflow-fiscal-settings",
          "input": {
            "section": "fiscal",
            "legalName": "Consultoría Bruma SA de CV",
            "rfc": "EKU9003173C9",
            "taxSystem": "601",
            "address": {
              "postalCode": "82110"
            }
          }
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "upload-csd",
      "rest": {
        "operationId": "uploadCertificate",
        "method": "PUT",
        "path": "/v1/organization/certificates/csd",
        "environments": [
          "production"
        ],
        "headers": {
          "Idempotency-Key": "workflow-upload-csd"
        },
        "body": {
          "certificateBase64": "BASE64_CER",
          "privateKeyBase64": "BASE64_KEY",
          "password": "certificate-password",
          "certificateFileName": "certificate.cer",
          "privateKeyFileName": "private.key"
        }
      }
    },
    {
      "id": "verify-organization",
      "rest": {
        "operationId": "getOrganization",
        "method": "GET",
        "path": "/v1/organization",
        "environments": [
          "production",
          "sandbox"
        ]
      },
      "mcp": {
        "tool": "get_organization",
        "arguments": {},
        "environments": [
          "production"
        ]
      }
    }
  ]
}
```

### Issue and send a production CFDI

Production workflow: configure the organization fiscal identity and CSD, fund the API/MCP wallet, and create a customer with RFC, legal name, tax system, and postal address. Use that contactId as customerId. Then create a draft, inspect it, explicitly stamp it with SAT, and send the resulting document.

#### Create the draft

Creation is draft-only. It does not stamp or send the CFDI; inspect the returned draft before either explicit transition.

Retry guidance: Use the same key for an exact retry; a changed payload is a new request.

#### Inspect the draft

Use the returned documentRef to review the canonical document projection.

Retry guidance: This read is safe to repeat and has no idempotency key.

#### Preview the draft PDF (optional)

Use preview_pdf to inspect the rendered document before stamping. The preview has no fiscal validity.

Retry guidance: This file read is safe to repeat and has no idempotency key.

#### Stamp with SAT

Stamping is a separate irreversible transition. Review the draft first.

Retry guidance: Retry only with the same key and documentRef; provider failures may require recovery.

#### Send the CFDI

Email the stamped CFDI and its fiscal files to an explicit recipient.

Retry guidance: Reuse the key for the same recipient and document; sending remains an external side effect.

```json
{
  "steps": [
    {
      "id": "create-cfdi-draft",
      "rest": {
        "operationId": "createInvoiceDraft",
        "method": "POST",
        "path": "/v1/invoices",
        "environments": [
          "production",
          "sandbox"
        ],
        "headers": {
          "Idempotency-Key": "workflow-create-cfdi"
        },
        "body": {
          "customerId": "customer-example",
          "items": [
            {
              "kind": "custom",
              "description": "Consultoría administrativa · julio 2026",
              "quantity": 1,
              "unitPrice": 10000,
              "satProductCode": "84111506",
              "satUnitCode": "E48",
              "taxRate": 0.16,
              "taxability": "standard"
            }
          ],
          "kind": "income",
          "cfdiUse": "G03",
          "payment": {
            "timing": "deferred_or_installments",
            "formCode": "99",
            "conditions": "Crédito a 30 días"
          }
        }
      },
      "mcp": {
        "tool": "create_invoice_draft",
        "arguments": {
          "idempotencyKey": "workflow-create-cfdi",
          "input": {
            "customerId": "customer-example",
            "items": [
              {
                "kind": "custom",
                "description": "Consultoría administrativa · julio 2026",
                "quantity": 1,
                "unitPrice": 10000,
                "satProductCode": "84111506",
                "satUnitCode": "E48",
                "taxRate": 0.16,
                "taxability": "standard"
              }
            ],
            "kind": "income",
            "cfdiUse": "G03",
            "payment": {
              "timing": "deferred_or_installments",
              "formCode": "99",
              "conditions": "Crédito a 30 días"
            }
          }
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "inspect-cfdi-draft",
      "rest": {
        "operationId": "getInvoice",
        "method": "GET",
        "path": "/v1/invoices/invoice:invoice-example",
        "environments": [
          "production",
          "sandbox"
        ]
      },
      "mcp": {
        "tool": "get_document",
        "arguments": {
          "documentRef": "invoice:invoice-example"
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "preview-cfdi-draft-pdf",
      "rest": {
        "operationId": "downloadDocumentFile",
        "method": "GET",
        "path": "/v1/documents/invoice:invoice-example/files/preview_pdf",
        "environments": [
          "production",
          "sandbox"
        ]
      },
      "mcp": {
        "tool": "get_document_file",
        "arguments": {
          "documentRef": "invoice:invoice-example",
          "file": "preview_pdf"
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "stamp-cfdi",
      "rest": {
        "operationId": "stampInvoice",
        "method": "POST",
        "path": "/v1/invoices/invoice:invoice-example/stamp",
        "environments": [
          "production",
          "sandbox"
        ],
        "headers": {
          "Idempotency-Key": "workflow-stamp-cfdi"
        },
        "body": {}
      },
      "mcp": {
        "tool": "stamp_invoice",
        "arguments": {
          "documentRef": "invoice:invoice-example",
          "idempotencyKey": "workflow-stamp-cfdi"
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "send-cfdi",
      "rest": {
        "operationId": "sendDocument",
        "method": "POST",
        "path": "/v1/documents/invoice:invoice-example/send",
        "environments": [
          "production"
        ],
        "headers": {
          "Idempotency-Key": "workflow-send-cfdi"
        },
        "body": {
          "recipient": "administracion@jacaranda.example"
        }
      },
      "mcp": {
        "tool": "send_document",
        "arguments": {
          "idempotencyKey": "workflow-send-cfdi",
          "input": {
            "documentRef": "invoice:invoice-example",
            "recipient": "administracion@jacaranda.example"
          }
        },
        "environments": [
          "production"
        ]
      }
    }
  ]
}
```

### Create a payment complement

Record one or more payments against a PPD invoice. Exac distributes the known invoice taxes across each partial payment.

#### Inspect the related CFDI

Use taxes: "auto" when Exac has the stamped invoice. For an unknown external invoice, send its SAT taxObject and payment-level tax rows; no XML import is required.

Retry guidance: This read is safe to repeat.

#### Create the payment-complement draft

For the first payment use installment 1 and the invoice total as previousBalance. For later payments, increment installment and use the preceding remaining balance. Exac resolves automatic taxes before creating the draft.

Retry guidance: Reuse the same key only for the identical payment.

#### Inspect before stamping

Confirm balances, installment, and payment taxes in the canonical draft projection.

Retry guidance: This read is safe to repeat.

#### Stamp the payment complement

Stamp only after the related UUID, installment, previous, paid, remaining balances, and proportional taxes are correct.

Retry guidance: Reuse the same key only for the same reviewed draft and emission date.

```json
{
  "steps": [
    {
      "id": "inspect-related-cfdi",
      "rest": {
        "operationId": "getInvoice",
        "method": "GET",
        "path": "/v1/invoices/invoice:invoice-example",
        "environments": [
          "production",
          "sandbox"
        ]
      },
      "mcp": {
        "tool": "get_document",
        "arguments": {
          "documentRef": "invoice:invoice-example"
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "create-payment-complement-draft",
      "rest": {
        "operationId": "createInvoiceDraft",
        "method": "POST",
        "path": "/v1/invoices",
        "environments": [
          "production",
          "sandbox"
        ],
        "headers": {
          "Idempotency-Key": "workflow-create-payment-complement"
        },
        "body": {
          "kind": "payment_complement",
          "customerId": "customer-example",
          "payments": [
            {
              "formCode": "03",
              "paidLocalDateTime": "2026-07-15T12:00:00",
              "documents": [
                {
                  "uuid": "00000000-0000-4000-8000-000000000001",
                  "amount": 11600,
                  "installment": 1,
                  "previousBalance": 11600,
                  "taxes": "auto"
                }
              ]
            }
          ]
        }
      },
      "mcp": {
        "tool": "create_invoice_draft",
        "arguments": {
          "idempotencyKey": "workflow-create-payment-complement",
          "input": {
            "kind": "payment_complement",
            "customerId": "customer-example",
            "payments": [
              {
                "formCode": "03",
                "paidLocalDateTime": "2026-07-15T12:00:00",
                "documents": [
                  {
                    "uuid": "00000000-0000-4000-8000-000000000001",
                    "amount": 11600,
                    "installment": 1,
                    "previousBalance": 11600,
                    "taxes": "auto"
                  }
                ]
              }
            ]
          }
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "inspect-payment-complement-draft",
      "rest": {
        "operationId": "getInvoice",
        "method": "GET",
        "path": "/v1/invoices/invoice:payment-example",
        "environments": [
          "production",
          "sandbox"
        ]
      },
      "mcp": {
        "tool": "get_document",
        "arguments": {
          "documentRef": "invoice:payment-example"
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "stamp-payment-complement",
      "rest": {
        "operationId": "stampInvoice",
        "method": "POST",
        "path": "/v1/invoices/invoice:payment-example/stamp",
        "environments": [
          "production",
          "sandbox"
        ],
        "headers": {
          "Idempotency-Key": "workflow-stamp-payment-complement"
        },
        "body": {}
      },
      "mcp": {
        "tool": "stamp_invoice",
        "arguments": {
          "documentRef": "invoice:payment-example",
          "idempotencyKey": "workflow-stamp-payment-complement"
        },
        "environments": [
          "production"
        ]
      }
    }
  ]
}
```

### Convert receipts into a CFDI

Create one CFDI draft from selected receipt sales. Stamping remains a separate explicit operation.

#### Create the receipt

Use a catalog product with its fiscal identity configured. Without productId, supply satProductCode and satUnitCode when creating this paid receipt. Exac preserves the fiscal data as charged for later invoicing.

Retry guidance: Reuse the same key only for the identical sale.

#### Convert the receipts

The operation validates receipt ownership and reconciliation, then returns a CFDI draft. It does not stamp or send the CFDI.

Retry guidance: Retry the exact receipt set with the same key; never change the set under an existing key.

#### Read the resulting CFDI

Use the CFDI documentRef returned by the conversion to retrieve the canonical detail.

Retry guidance: Reads are safe to repeat and do not need an idempotency key.

```json
{
  "steps": [
    {
      "id": "create-invoiceable-receipt",
      "rest": {
        "operationId": "createSalesReceipt",
        "method": "POST",
        "path": "/v1/sales-receipts",
        "environments": [
          "production",
          "sandbox"
        ],
        "headers": {
          "Idempotency-Key": "workflow-create-invoiceable-receipt"
        },
        "body": {
          "saleType": "paid",
          "customer": {
            "kind": "stored",
            "customerId": "customer-example"
          },
          "items": [
            {
              "productId": "product-example",
              "description": "Servicio",
              "quantity": 1,
              "unitPrice": 1250
            }
          ],
          "paymentForm": "03"
        }
      },
      "mcp": {
        "tool": "create_sales_receipt",
        "arguments": {
          "idempotencyKey": "workflow-create-invoiceable-receipt",
          "input": {
            "saleType": "paid",
            "customer": {
              "kind": "stored",
              "customerId": "customer-example"
            },
            "items": [
              {
                "productId": "product-example",
                "description": "Servicio",
                "quantity": 1,
                "unitPrice": 1250
              }
            ],
            "paymentForm": "03"
          }
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "create-cfdi-from-receipts",
      "rest": {
        "operationId": "createInvoiceDraftFromSalesReceipts",
        "method": "POST",
        "path": "/v1/invoices/from-sales-receipts",
        "environments": [
          "production",
          "sandbox"
        ],
        "headers": {
          "Idempotency-Key": "workflow-receipts-to-cfdi"
        },
        "body": {
          "salesReceiptRefs": [
            "sales_receipt:receipt-example"
          ],
          "customer": {
            "kind": "existing",
            "customerId": "customer-example"
          },
          "cfdiUse": "S01"
        }
      },
      "mcp": {
        "tool": "create_invoice_draft_from_sales_receipts",
        "arguments": {
          "idempotencyKey": "workflow-receipts-to-cfdi",
          "input": {
            "salesReceiptRefs": [
              "sales_receipt:receipt-example"
            ],
            "customer": {
              "kind": "existing",
              "customerId": "customer-example"
            },
            "cfdiUse": "S01"
          }
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "read-converted-cfdi",
      "rest": {
        "operationId": "getInvoice",
        "method": "GET",
        "path": "/v1/invoices/invoice:invoice-example",
        "environments": [
          "production",
          "sandbox"
        ]
      },
      "mcp": {
        "tool": "get_document",
        "arguments": {
          "documentRef": "invoice:invoice-example"
        },
        "environments": [
          "production"
        ]
      }
    }
  ]
}
```

### Find and download a CFDI

Search the CFDI collection with fiscal filters, retrieve a document, and download its PDF or XML.

#### Search CFDIs

Use kind and paymentTiming instead of a generic document type filter.

Retry guidance: This read is safe to repeat and uses cursor pagination for later pages.

#### Retrieve the CFDI

Use the opaque CFDI reference returned by the collection response.

Retry guidance: Reads are safe to repeat and do not need an idempotency key.

#### Download the PDF

The REST route returns an attachment; the MCP tool returns a binary resource.

Retry guidance: File reads are safe to repeat and do not need an idempotency key.

#### Download the XML

Use the same documentRef to retrieve the fiscal XML when it is available.

Retry guidance: File reads are safe to repeat and do not need an idempotency key.

```json
{
  "steps": [
    {
      "id": "search-cfdis",
      "rest": {
        "operationId": "listInvoices",
        "method": "GET",
        "path": "/v1/invoices",
        "environments": [
          "production",
          "sandbox"
        ],
        "query": {
          "kind": "income",
          "status": "valid",
          "dateFrom": "2026-01-01",
          "dateTo": "2026-01-31",
          "limit": 20
        }
      },
      "mcp": {
        "tool": "search_documents",
        "arguments": {
          "input": {
            "category": "invoice",
            "kind": "income",
            "status": "valid",
            "dateFrom": "2026-01-01",
            "dateTo": "2026-01-31",
            "limit": 20
          }
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "get-cfdi",
      "rest": {
        "operationId": "getInvoice",
        "method": "GET",
        "path": "/v1/invoices/invoice:invoice-example",
        "environments": [
          "production",
          "sandbox"
        ]
      },
      "mcp": {
        "tool": "get_document",
        "arguments": {
          "documentRef": "invoice:invoice-example"
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "download-pdf",
      "rest": {
        "operationId": "downloadDocumentFile",
        "method": "GET",
        "path": "/v1/documents/invoice:invoice-example/files/pdf",
        "environments": [
          "production",
          "sandbox"
        ]
      },
      "mcp": {
        "tool": "get_document_file",
        "arguments": {
          "documentRef": "invoice:invoice-example",
          "file": "pdf"
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "download-xml",
      "rest": {
        "operationId": "downloadDocumentFile",
        "method": "GET",
        "path": "/v1/documents/invoice:invoice-example/files/xml",
        "environments": [
          "production",
          "sandbox"
        ]
      },
      "mcp": {
        "tool": "get_document_file",
        "arguments": {
          "documentRef": "invoice:invoice-example",
          "file": "xml"
        },
        "environments": [
          "production"
        ]
      }
    }
  ]
}
```

### Reconcile CFDI status with SAT

Ask SAT for the current status of a stamped production CFDI after an asynchronous response or uncertain outcome. This workflow does not support withholdings. Test and simulated documents are not queried at SAT; read their stored state instead.

#### Refresh SAT status

Refresh requires verification data captured from the fiscal XML and reconciles local state.

Retry guidance: Reuse the same key for the same document observation; this is a state-changing external read.

#### Read the reconciled document

Fetch the document again to consume the canonical local status and cancellation projection.

Retry guidance: Reads are safe to repeat and do not need an idempotency key.

```json
{
  "steps": [
    {
      "id": "refresh-cfdi-status",
      "rest": {
        "operationId": "refreshInvoiceStatus",
        "method": "POST",
        "path": "/v1/invoices/invoice:invoice-example/status/refresh",
        "environments": [
          "production"
        ],
        "headers": {
          "Idempotency-Key": "workflow-refresh-cfdi-status"
        },
        "body": {}
      },
      "mcp": {
        "tool": "refresh_invoice_status",
        "arguments": {
          "documentRef": "invoice:invoice-example",
          "idempotencyKey": "workflow-refresh-cfdi-status"
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "read-reconciled-cfdi",
      "rest": {
        "operationId": "getInvoice",
        "method": "GET",
        "path": "/v1/invoices/invoice:invoice-example",
        "environments": [
          "production",
          "sandbox"
        ]
      },
      "mcp": {
        "tool": "get_document",
        "arguments": {
          "documentRef": "invoice:invoice-example"
        },
        "environments": [
          "production"
        ]
      }
    }
  ]
}
```

### Read fiscal reports

Read already synchronized CFDI aggregates and authoritative declaration totals separately.

#### Read CFDI aggregates

CFDI totals exclude receipt/POS sales and are distinct from declaration tax totals.

Retry guidance: This report is read-only and safe to repeat.

#### Read declared tax totals

Tax totals come only from parsed declarations; unavailable totals remain null rather than being estimated.

Retry guidance: This report is read-only and safe to repeat.

```json
{
  "steps": [
    {
      "id": "read-cfdi-summary",
      "rest": {
        "operationId": "getIncomeExpensesReport",
        "method": "GET",
        "path": "/v1/reports/income-expenses",
        "environments": [
          "production",
          "sandbox"
        ],
        "query": {
          "fiscalYear": 2026,
          "period": 1
        }
      },
      "mcp": {
        "tool": "get_income_expenses_summary",
        "arguments": {
          "fiscalYear": 2026,
          "period": 1
        },
        "environments": [
          "production"
        ]
      }
    },
    {
      "id": "read-tax-summary",
      "rest": {
        "operationId": "getTaxReport",
        "method": "GET",
        "path": "/v1/reports/taxes",
        "environments": [
          "production"
        ],
        "query": {
          "fiscalYear": 2026
        }
      },
      "mcp": {
        "tool": "get_tax_summary",
        "arguments": {
          "fiscalYear": 2026
        },
        "environments": [
          "production"
        ]
      }
    }
  ]
}
```

Complete documentation: https://exac.mx/docs/en.md
Agent documentation index: https://exac.mx/docs/en/llms.txt
