Alegra – Configuration Guide

Service ID: alegra

Cloud-based invoicing, accounting and POS software popular across Latin America (Mexico, Colombia, Peru, Spain, Dominican Republic, Argentina, Chile and others) for SMBs and entrepreneurs.

Using the Alegra connector

Alegra is a cloud invoicing + accounting platform used across Latin America (Mexico, Colombia, Peru, Spain, Dominican Republic, Argentina, Chile, …). It is electronic-invoicing (CFDI/e-invoice) native, which shapes a lot of how invoicing works here.

Authentication

Alegra uses HTTP Basic auth with an email + API token (the consumer generates the token in Alegra under Settings → Manual integration (API)). Setup is covered in the connection guide. Once connected, all calls use the standard Apideck headers:

Authorization: Bearer {APIDECK_API_KEY}
x-apideck-app-id: {APP_ID}
x-apideck-consumer-id: {CONSUMER_ID}
x-apideck-service-id: alegra

What you can do

Full CRUD unless noted; R = read-only.

ResourceOperations
company-infoR
customers, suppliersCRUD
tax-ratesCRUD
ledger-accountsCreate · Read · Update (no delete — Alegra has no delete-account endpoint)
departmentsCRUD
bank-accountsCRUD
invoice-itemsCRUD
invoices, credit-notesCRUD
bills, purchase-ordersCRUD
payments, bill-paymentsCRUD
journal-entriesCRUD
quotesCRUD

1. CFDI stamping (timbrado) — the most important topic

Stamping certifies a document with the Mexican tax authority (SAT), issuing a folio fiscal (UUID) and consuming a real fiscal folio. It applies to the sales documents you issue — invoices and credit notes. Bills and purchase orders are not stamped: they record a document the supplier issues, and stay editable while open.

Creating an invoice produces a draft

A create returns an unstamped draft — no fiscal folio is consumed:

curl -X POST 'https://unify.apideck.com/accounting/invoices' -H '…headers…' -d '{
  "customer":     { "id": "7" },
  "invoice_date": "2026-05-31",
  "due_date":     "2026-06-30",
  "line_items": [{ "item": { "id": "11" }, "unit_price": 0.01, "quantity": 1 }]
}'
# → 201, and a GET shows: { "id": "6", "status": "draft", "total": 0.01, "currency": "MXN" }

Each line item's Alegra product must have a SAT product key (productKey) configured, or the create is rejected:

{ "status_code": 400, "error": { "message": "La clave del producto es requerida.", "code": 1035 } }

productKey is a Mexico-specific SAT code with no unified field (the unified code maps to Alegra's reference/SKU, a different thing). Set it when creating the item through Unify via pass_through — it must be a valid SAT clave de producto/servicio string:

{
  "name": "Servicio de consultoría",
  "type": "service",
  "pass_through": [{ "service_id": "alegra", "extend_object": { "productKey": "80141600" } }]
}

To read productKey back, fetch the item through the Proxy (GET /items/{id}). Native mapping is tracked in #11099. (Unset payment_method/paymentType on an invoice default to cash/PUE.)

Issuing (stamping) an invoice

To stamp, send a pass_through that turns on stamping and supplies the required SAT fields:

{
  "customer": { "id": "7" },
  "invoice_date": "2026-05-31", "due_date": "2026-06-30",
  "payment_method": "cash",
  "line_items": [{ "item": { "id": "11" }, "unit_price": 100, "quantity": 1 }],
  "pass_through": [{ "service_id": "alegra", "extend_object": {
    "stamp":        { "generateStamp": true, "version": "4.0" },
    "paymentType":  "PUE",
    "cfdiUse":      "G03",
    "regimeClient": "SIMPLIFIED_REGIME"
  }}]
}
FieldMeaningNotes
stamp.generateStampstamp now vs. leave as drafttrue to issue
payment_methodforma de pagoAlegra string (cash/transfer/deposit/check/credit-card/debit-card/…) — a numeric SAT code is rejected
paymentTypemétodo de pagoPUE (single payment) or PPD (installments/deferred). PPD requires payment_method: "other"
cfdiUseuso del CFDISAT catalog (G01, G03, D01, S01, …)
regimeClientclient's fiscal regimerequired for CFDI 4.0
  • ⚠️ Stamping consumes a real CFDI folio — there is no test/dry-run stamp. The client must have a valid RFC (XAXX010101000 works for unstamped/draft testing).
  • If stamping fails, Alegra still saves the invoice as a draft and returns HTTP 400 with the error (e.g. code 3051) plus the created invoice — fix the data and re-stamp; nothing is lost.

Reading the CFDI back (folio fiscal, seals)

A stamped invoice read through Unify returns the commercial data (status, totals, lines) but not the CFDI fields. To get them, add ?raw=true to the normal GET — the full downstream record, including stamp, comes back under data._raw:

curl 'https://unify.apideck.com/accounting/invoices/5?raw=true' -H '…headers…'
"stamp": {
  "uuid":          "2B95841F-9AAA-5AFB-980F-F266F8D23D67",   // folio fiscal — the field most often needed
  "emissionStatus":"STAMPED_AND_ACCEPTED",
  "version":       "4.0",
  "satSeal":       "pOl8yNEC3Q2Nm/2rjpAgOQP7…",              // sello del SAT
  "cfdSeal":       "QpyNuG04R7cProDVN5VbM8Sv…",              // sello del CFD
  "satCertificateNumber": "00001000000707310321",
  "stampDate":     "2026-05-30 13:02:18",
  "barCodeContent":"https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?id=2B95…",
  "originalString":"||1.1|2B95841F-…||CVD110412TF6|…"        // cadena original
}

For the CFDI PDF or XML, call the Proxy with Alegra's ?fields=pdf,xml (base /proxy, target in the x-apideck-downstream-url header).

Stamping an existing draft, and cancelling

A stamped invoice is immutable — update and delete only work while it is a draft. Using the Proxy against Alegra's own endpoints you can:

  • stamp drafts in bulk: POST /invoices/stamp with { "ids": [6] }
  • stamp one draft: POST /invoices/{id}/open with { "stamp": { "generateStamp": true } }
  • cancel a stamped invoice at the SAT: POST /invoices/{id}/void with a reason cause (0104; 01 also needs relatedFolio)

The invoice id does not change when a draft becomes stamped, so it is safe to round-trip.


2. Document status is derived from the balance

Alegra's underlying states are draft / open / closed / void. The unified status is computed using the balance, so an Alegra open invoice can surface as:

SituationUnified status
draftdraft
voidvoided
nothing paidauthorised
partly paidpartially_paid
fully paid / closedpaid

This applies to invoices, bills and credit notes. Note that partially_paid cannot be used as a filter (Alegra has no equivalent state) — for status filtering, paid and authorised/unpaid and voided work.


3. Payments and bank accounts

  • payments are customer receipts; bill-payments are supplier payments. Both support full CRUD.
  • A payment must be applied to at least one invoice/bill — Alegra rejects an unapplied payment. The documents it was applied to come back in allocations (with the applied amount).
  • payment_method is one of cash/transfer/check/deposit/credit-card/debit-card.
  • bank-accounts represent the money accounts that receive/issue payments (types cash/checking/credit_card). Alegra exposes no IBAN, BIC, routing number, or balance, so those fields come back empty; bank-type accounts do carry an account number.

4. Bill & purchase-order line items: catalog item or ledger account

A bill or purchase-order line can be costed against a catalog item or directly against an expense ledger account, and one document can mix both. line_items[].type tells you which:

  • expense_item → the line carries line_items[].item (a reference to invoice-items)
  • expense_account → the line carries line_items[].ledger_account (a reference to ledger-accounts)

(Sales documents — invoices, credit notes, quotes — always bill against catalog items.)


5. Ledger accounts (chart of accounts)

  • The chart is hierarchical (up to 5 levels; a Mexican SAT chart is ~466 accounts). Each account exposes its parent_account and sub_accounts.
  • Only postable (leaf) accounts can be used on transactions. Accounts with header: true are grouping/summary nodes; posting against them is rejected.
  • Two codes are exposed: code (the company's own account code, e.g. 101-01-001) and nominal_code (the SAT código agrupador, e.g. 101.01). The SAT code is shared across related accounts — it is not unique per account.
  • Creating an account requires a parent (parent_account.id); Alegra rejects a create without one (there is no API-created root account). Accounts can be created and updated but not deleted — Alegra has no delete-account endpoint; block/deactivate the account in Alegra instead.
curl -X POST 'https://unify.apideck.com/accounting/ledger-accounts' -H '…headers…' -d '{
  "name": "Comisiones bancarias",
  "parent_account": { "id": "5315" },   # required — the account this hangs under
  "code": "604-02-001",                 # your own account code (optional)
  "nominal_code": "604.02"              # SAT código agrupador (optional)
}'
# → 200 { "data": { "id": "5486" } }

The account's classification/type and nature (debit/credit) are inherited from the parent — you do not send them. An update (PATCH) changes only the fields you send (name, code, description, …).


6. Tax rates

Full CRUD. Two things to know:

  • Creating a tax requires a type (IVA, IEPS, EXENTO, …) — Alegra rejects a tax without one. total_tax_rate (or effective_tax_rate) carries the percentage.
  • An update preserves the tax's ledger accounts automatically, so you can PATCH just the name or rate; you do not need to re-send tax_payable_account_id/tax_remitted_account_id (Alegra would otherwise reject the update for a missing purchase account).
curl -X POST 'https://unify.apideck.com/accounting/tax-rates' -H '…headers…' -d '{
  "name": "IVA 16",
  "type": "IVA",                 # required
  "total_tax_rate": 16,
  "tax_payable_account_id":  "5166",   # optional — IVA trasladado ledger account
  "tax_remitted_account_id": "5063"    # optional — IVA a favor ledger account
}'
# → 201 { "data": { "id": "21" } }

7. Journal entries

  • Total debits must equal total credits, or Alegra rejects the entry. Each unified line_items[] entry is one debit or one credit (type + total_amount) posting to a ledger_account.
  • number is always empty (Alegra assigns none) and journal entries have no created/updated timestamps.

8. A contact can be both a customer and a supplier

In Alegra one contact can be a customer and a supplier at the same time. The consequence: the same record (same id) can appear in both the customers and suppliers lists, and updating it through either resource changes the same underlying contact.


9. Filtering, sorting, pagination

  • Pagination is offset-based and capped at 30 per page; walk meta.cursors.next until null. ledger-accounts is unpaginated (the whole tree returns at once).
  • Sorting by created_at/updated_at works on most list resources. ledger-accounts, journal-entries and departments cannot be sorted (no timestamps).
  • Filtering is uneven: status and customer_id/supplier_id work on payments, bill-payments and journal-entries; invoices, credit-notes and quotes expose no unified-compatible filters; invoice-items filters only by name. Filter client-side when a filter isn't available.

10. Mexican fiscal (CFDI/SAT) fields

Beyond stamping, Alegra carries many Mexico-specific fields that have no place in the unified accounting schema: cfdiUse, paymentType, fiscal regime, line productKey/unit, taxCondition, the full CFDI stamp, the IVA ledger accounts, and more. Send them on write with pass_through; read them with ?raw=true (or the Proxy). Native support for these is tracked in #11099; the single most-requested field is the CFDI uuid (folio fiscal).


11. Webhooks

Alegra delivers native webhooks for four resources — invoices, bills, invoice-items, and contacts — on create, update and delete. A contact change is delivered for both customers and suppliers (since one contact can be both). Other resources (payments, credit-notes, journal-entries, …) do not emit webhooks.