Mexico's 2026 Marketplace Tax Withholding: An Engineer's Guide to Retenciones (ISR + IVA) and the Retención CFDI — Cesar Ayala
← All posts

Mexico's 2026 Marketplace Tax Withholding: An Engineer's Guide to Retenciones (ISR + IVA) and the Retención CFDI

From January 1, 2026 (LIF 2026, DOF Nov 7, 2025), Mexican platforms that intermediate sales — now including personas morales — must withhold ISR (2.5% of gross) and IVA (8%, half of 16%) per sale on goods/services, net it before your marketplace fee, remit to SAT, and issue a retención CFDI. No valid RFC raises it to 20%/16%. I'm an engineer, not a contador — confirm rates and deadlines.

What changed on January 1, 2026 (and who it now hits)

Starting January 1, 2026 (Ley de Ingresos de la Federación 2026, published in the DOF on November 7, 2025), Mexico’s régimen de plataformas digitales now also covers personas morales (companies), and the ISR withholding on goods/services sales rose from 1% to 2.5% (IVA stays at 8%). If you run a Mexican marketplace, you may now be the retenedor — an engineering problem, not just an accounting one.

Two changes matter most for builders:

  1. Until 2025, the régimen de plataformas digitales (the digital-platform tax regime) mainly hit personas físicas — individual sellers. From 2026 it also applies to personas morales — companies selling through platforms. So a chunk of sellers you used to ignore are now in scope. (IDC has a good breakdown of the personas-morales expansion.)
  2. The ISR retención (income-tax withholding) for enajenación de bienes y prestación de servicios (sale of goods and provision of services) rose from 1% to 2.5%.

Here’s the part the accountant blogs gloss over. A retenedor (withholding agent) is the digital platform or marketplace that intermediates the sale of goods or services in Mexico. As the retenedor, you must withhold ISR + IVA (income tax + value-added tax) from each seller’s sales and remit it to the SAT (Mexico’s tax authority) on the seller’s behalf. If you operate a Mexican marketplace — Stripe Connect, Mercado Pago split payments, or a custom payout pipeline — you may now be the retenedor. That makes this an engineering problem, not just an accounting one. (Mercado Pago has published its own note on the 2026 retenciones.)

One disclaimer up front, and I’ll repeat it: I’m an engineer, not a contador (accountant). I’ll show you how to build the pipeline. Confirm scope, exact rates, and deadlines against the SAT and your own contador — and treat every figure here as time-sensitive (“as of 2026, confirm current”).

EffectiveJan 1, 2026 (LIF 2026, DOF Nov 7, 2025)
Now also coverspersonas morales (not just personas físicas)
ISR retenciónrose from 1% to 2.5% of gross
IVA retención8% (50% of the 16% IVA)
Scopegoods & services — other activities differ
No valid RFC penaltyISR 20% / IVA 16%

What are the rates? ISR 2.5%, IVA 8% — and the no-RFC penalty

For enajenación de bienes y prestación de servicios — the e-commerce / marketplace case this post covers — the rates as of 2026 are:

  • ISR retención = 2.5% of GROSS income per sale. Gross means before deductions, regardless of whether the seller made a profit on that sale.
  • IVA retención = 8%, which is 50% of the 16% IVA.

Combined, that’s roughly 10.5% withheld from gross on the valid-RFC path.

A warning so you don’t over-generalize: other activities have their own ISR rates. Transporte de pasajeros / entrega de bienes (passenger transport / delivery) is around 2.1%, and hospedaje (lodging) is around 4%. This post covers goods and services — tell your finance team to confirm the rate for your activity.

Now the part that will bite marketplaces that cut corners on onboarding. If the seller does not provide a valid RFC (Registro Federal de Contribuyentes — Mexico’s taxpayer ID), the withholding jumps to ISR 20% and IVA 16% (100% of the IVA). The up-to-100% IVA also applies for operations with foreign residents or deposits in foreign accounts.

Opinion (labeled): RFC validation is the single step where marketplaces will get burned. If you let a seller transact without a validated RFC, you’re on the hook to withhold 20%/16% — and if your code silently applied 2.5%/8%, you just under-withheld and that’s your problem to reconcile. Make RFC validation a hard gate at onboarding, not an afterthought.

Is the seller losing money? No — it’s creditable, not an extra tax

This is the conversation you’ll have with every seller who watches ~10.5% vanish from their first payout. Get ahead of it.

The withheld amounts are not a new tax — they’re a prepayment the seller recovers:

  • The ISR withheld is a pago provisional (a provisional payment) the seller credits in their monthly and annual return.
  • The IVA withheld is creditable in the seller’s monthly IVA return.

The platform just anticipates the payment to the SAT. The seller doesn’t lose the ~10.5% — they recover it as a credit. You are not “stealing” 10.5% of every sale; you’re prepaying the seller’s taxes to the SAT for them.

Practical builder note: this is exactly why your retención CFDI + constancia matter. They’re the seller’s proof to claim the credit. If your timbrado pipeline is flaky, you’re not just out of compliance — you’re blocking your sellers from recovering their own money. Same plumbing as your sale CFDIs, which I cover in auto-invoicing CFDI from Stripe/Mercado Pago.

Are you the retenedor or not? What your code must branch on

The decision logic has two layers. First: are you the retenedor for this seller at all? You’re the retenedor when you intermediate the sale and pay the seller. (Whether a specific arrangement makes you the retenedor is a scope question — confirm it with a contador.)

Second, once you’ve decided you are withholding, your code branches on RFC validity:

  • Branch A — valid RFC: withhold 2.5% ISR + 8% IVA on the correct base.
  • Branch B — no/invalid RFC: withhold 20% ISR + 16% IVA — the penalty path you do not want to silently eat.

So your data model needs, per seller: the RFC, its validation state, and the régimen (tax regime). Your per-sale code reads that state and picks the rate set. Validate at onboarding — here’s the illustrative shape (confirm validation against the SAT / your PAC):

// Illustrative — confirm RFC validation against SAT / your PAC's API.
type Regimen = "fisica" | "moral";

interface SellerTaxProfile {
  rfc: string;
  regimen: Regimen;
  rfcValidated: boolean; // hard gate — set true only after real validation
}

// RFC format: 13 chars for personas físicas, 12 for personas morales.
const RFC_FISICA = /^[A-ZÑ&]{4}\d{6}[A-Z0-9]{3}$/;
const RFC_MORAL = /^[A-ZÑ&]{3}\d{6}[A-Z0-9]{3}$/;

function isRfcShapeValid(rfc: string, regimen: Regimen): boolean {
  const r = rfc.trim().toUpperCase();
  return regimen === "fisica" ? RFC_FISICA.test(r) : RFC_MORAL.test(r);
}

// Onboarding gate: shape check is necessary but NOT sufficient.
// You still must confirm the RFC is real and active (e.g. SAT LCO /
// your PAC's validation endpoint) before flipping rfcValidated to true.
async function gateOnboarding(p: SellerTaxProfile): Promise<boolean> {
  if (!isRfcShapeValid(p.rfc, p.regimen)) return false;
  // const live = await pac.validateRfc(p.rfc); if (!live.active) return false;
  return p.rfcValidated;
}

Valid RFC (Branch A)

  • Seller passed the onboarding RFC gate
  • ISR retención: 2.5% of gross
  • IVA retención: 8% (half of 16%)
  • ~10.5% withheld, all creditable to the seller
  • The path you want every seller on

No / invalid RFC (Branch B)

  • RFC missing, malformed, or not validated
  • ISR retención: 20% of gross
  • IVA retención: 16% (100% of the IVA)
  • Also applies to foreign residents / foreign accounts
  • Penalty path — don't silently eat it

How do you compute and net the withholding? (the order-of-operations gotcha)

Now the calculator. Given a sale’s gross and the seller’s RFC state, return the ISR and IVA amounts to net out. One assumption to make explicit: the 8% IVA retención is 50% of the IVA the seller charged, which assumes gross is the IVA-inclusive operation amount for a standard 16% activity. For IVA-exempt, 0%-rate, or special-regime sellers, 8%-of-gross is the wrong base — confirm it with your contador before you ship.

// Illustrative — rates as of 2026 for goods/services; confirm current.
// Assumes gross is the IVA-inclusive amount for a standard 16% activity:
// the 8% IVA retención = 50% of the seller's 16% IVA. For IVA-exempt /
// 0%-rate / special-regime sellers, this base is wrong — confirm it.
interface Withholding {
  isr: number;
  iva: number;
  total: number;
}

function computeWithholding(grossCents: number, rfcValid: boolean): Withholding {
  // Branch A: 2.5% ISR + 8% IVA. Branch B (no valid RFC): 20% / 16%.
  const isrRate = rfcValid ? 0.025 : 0.20;
  const ivaRate = rfcValid ? 0.08 : 0.16;
  const isr = Math.round(grossCents * isrRate);
  const iva = Math.round(grossCents * ivaRate);
  return { isr, iva, total: isr + iva };
}

Here’s the operational moat — the part the rate blogs never mention. ORDER OF OPERATIONS matters. The tax withheld comes out of the seller’s gross BEFORE your marketplace fee / Connect application_fee. This is the exact same class of gotcha as “Mercado Pago commission comes out before your application_fee” — get the order wrong and the seller is over- or under-paid, and your books won’t reconcile.

The seller should receive: gross − tax − marketplace fee. Net the tax first, then your fee:

// Illustrative — netting withholding from a Stripe Connect / split payout.
// Confirm field semantics with your provider's current API.
function buildPayout(grossCents: number, rfcValid: boolean, feeBps: number) {
  const w = computeWithholding(grossCents, rfcValid);

  // ORDER: tax comes out of GROSS first, THEN your marketplace fee.
  // NOTE: whether your fee is computed on gross or on the post-tax base is a
  // BUSINESS decision. The only regulatory constraint is that the SAT
  // withholding is netted from gross first; the fee base is yours to set.
  const baseAfterTax = grossCents - w.total;
  const marketplaceFee = Math.round(grossCents * (feeBps / 10_000));
  const sellerNet = baseAfterTax - marketplaceFee;

  return {
    // amount the platform remits to SAT on the seller's behalf
    retentionToRemit: w.total,
    // your Connect application_fee — here computed on gross, charged after tax netted
    application_fee_amount: marketplaceFee,
    // what actually lands in the seller's balance
    sellerNet, // gross − tax − fee
  };
}

I net the withholding inside the same payout pipeline I described in marketplace payments with Stripe Connect — the withholding is just one more line item that comes off the top, ahead of application_fee.

Sale settlesA buyer pays for a seller's goods/services through your marketplace.
Compute the retenciónOn the gross base: ISR 2.5% + IVA 8% (or 20%/16% if no valid RFC).
Net before your feeSeller payout = gross − tax − marketplace fee. Tax comes off BEFORE application_fee.
Remit to SATForward the withheld ISR + IVA to SAT — as of 2026, reported by the 17th of the following month; confirm current.
Issue retención CFDI + constanciaTimbra the CFDI de retenciones so the seller can claim the credit.

How do you issue the retención CFDI through your PAC?

The withholding isn’t done when you net it — you still have to document it. The platform must issue a CFDI de retenciones e información de pagos (a withholding-and-payments tax receipt). This is a different CFDI type than the sale’s ingreso (income) CFDI — same PAC plumbing, different document.

It details the ISR + IVA withheld and serves as the seller’s constancia (the certificate they use to claim the credit). You report to the SAT monthly.

There are two distinct deadlines, and the remit one is the load-bearing date for your monthly job — don’t conflate them:

  • Remit (enterar) the withheld ISR + IVA to the SAT: as of 2026, by the 17th of the following month. This is the deadline your monthly remittance job has to hit.
  • Issue / share the constancia + retención CFDI: reported as the following month, with some sources putting it in the first ~5 days.

Confirm both exact current deadlines with your contador and PAC; treat them as time-sensitive.

Here’s the shape of a retención CFDI request — clearly illustrative; confirm field names and catalog values against your PAC’s API. I stay vendor-neutral on PACs here:

{
  "comment": "ILLUSTRATIVE shape of a CFDI de retenciones request — confirm exact field names AND catalog values with your PAC's API and the SAT plataformas-tecnologicas complemento.",
  "tipoComprobante": "Retenciones e informacion de pagos",
  "emisor": { "rfc": "PLATFORM_RFC", "nombre": "Marketplace S.A. de C.V." },
  "receptor": { "rfc": "SELLER_RFC", "nacionalidad": "Nacional" },
  "periodo": { "mesInicial": 6, "mesFinal": 6, "ejercicio": 2026 },
  "totales": {
    "montoTotOperacion": 1000.00,
    "montoTotGrav": 1000.00,
    "montoTotRet": 105.00
  },
  "impuestosRetenidos": [
    { "impuesto": "ISR", "montoRet": 25.00, "tipoPagoRet": "PLACEHOLDER_confirm_catalog_value" },
    { "impuesto": "IVA", "montoRet": 80.00, "tipoPagoRet": "PLACEHOLDER_confirm_catalog_value" }
  ]
}

Totals there are internally consistent — 2.5% of 1000 is 25, 8% is 80, for 105 total — but tipoPagoRet, montoTotGrav vs montoTotExento, and the rest are catalog/schema values you must confirm against your PAC and the SAT complemento, not hardcode from this sample.

If you’ve already wired CFDI timbrado for your sales, this reuses that pipeline — see auto-invoicing CFDI from Stripe/Mercado Pago. And the retención CFDI is one more mandatory CFDI obligation alongside things like the Carta Porte CFDI; the whole CFDI e-invoicing hub collects them.

The build, end to end: onboarding to monthly remittance

Pulling the whole pipeline together:

  1. 1. Validate RFC + régimen at onboardingHard gate. No validated RFC = penalty path. Don't let it become an afterthought.
  2. 2. Compute withholding per sale2.5% ISR + 8% IVA on the gross base — or 20%/16% fallback if RFC invalid.
  3. 3. Net BEFORE your marketplace feeSeller payout = gross − tax − fee. Order of operations is non-negotiable.
  4. 4. Issue the retención CFDI via your PACDifferent CFDI type, same timbrado plumbing as your sale CFDIs.
  5. 5. Reconcile, remit, issue constancia monthlyRemit ISR + IVA to SAT by the 17th; give the seller their constancia to claim the credit.

Opinion (labeled): the RFC-validation gate is the highest-leverage thing you can build first. Everything downstream — the rate you pick, the amount you net, the CFDI you issue — depends on it. Get that gate right and the rest is arithmetic and plumbing.

And again: I’m an engineer, not a contador. Confirm scope, rates, and deadlines with a contador and your compliance team.

FAQ: rates, deadlines, and edge cases

Does this apply to personas morales now? Yes — from January 1, 2026 (LIF 2026, DOF Nov 7, 2025), the regime also covers personas morales, not just personas físicas.

Is the 2.5% ISR for every activity? No. It’s for goods and services. Transporte is around 2.1%, hospedaje around 4%. Confirm the rate for your activity.

What if a seller has no valid RFC? ISR jumps to 20% and IVA to 16%. Branch your code on RFC validity and gate it at onboarding.

Is the seller losing this money? No — it’s creditable. The ISR is a pago provisional the seller credits; the IVA is creditable monthly. You’re prepaying their tax, not taking it.

Which CFDI do I issue? A CFDI de retenciones e información de pagos — separate from the sale’s ingreso CFDI.

When is it due? Two deadlines, as of 2026: remit (enterar) the withheld ISR + IVA to the SAT by the 17th of the following month, and issue/share the constancia + retención CFDI in the following month (some sources say within the first ~5 days). Confirm both current deadlines with your contador and PAC.

Am I definitely the retenedor? That’s a scope question. Whether a given arrangement makes you the retenedor depends on the facts — confirm with a contador.

Closing: build the gate before the first sale

The accountant and PAC blogs explain the rates. The engineering work is the pipeline: validate, compute, net, emit, remit. That’s where marketplaces actually succeed or fail at this.

If you take one thing away: build the RFC-validation gate before you take your first peso. Every rate decision and every CFDI downstream depends on it.

And one last time, because it’s regulated content and the figures move: I’m an engineer, not a contador. Treat the rates and dates here as time-sensitive — as of 2026, confirm current figures with a contador and your PAC.