Skip to content

Carta Porte 3.1 API, stamp from your own system

Send the JSON with the Carta Porte 3.1 complement and get the stamped CFDI back, ultra-fast and valid with the SAT, with its XML and PDF. Before stamping we check the SAT rules; if something fails, we tell you which field to fix with the error's CP code. The API is included: each stamped CFDI uses 1 folio.

What the Carta Porte API takes care of

The same complement you stamp on the web, from your TMS or your ERP.

Income and transfer

TipoDeComprobante I to bill the freight or T to move your own goods. On a transfer, the API sets SubTotal, Total and amounts to 0, the currency to XXX and the CFDI use to S01, as the SAT requires.

SAT rules before stamping

We check the rules of the Carta Porte 3.1 error matrix (CP104, CP107, CP109, CP130, CP141 and CP193, among others). If something fails, nothing is stamped and no folio is used.

Calculated totals

TotalDistRec, NumTotalMercancias and PesoBrutoTotal are calculated from your locations and your goods. You don't have to balance them by hand.

Automatic IdCCP

Send IdCCP with the value "AUTO" and the API generates the Carta Porte identifier in the SAT's format.

Road, sea and air

Locations, goods, transport figures and customs documents, with the Autotransporte, TransporteMaritimo and TransporteAereo nodes.

If you already build your XML

Send your sealed Carta Porte to /invoice/stampxmlfile as an .xml file up to 40 MB, or to /invoice/stampxml in Base64.

A freight from Monterrey to Saltillo, from request to response

An income Carta Porte 3.1 by road. The JSON goes in the json field of POST /invoice/create, with your key in the X-Api-Key header.

Endpoints
POST /invoice/create
JSON with the CartaPorte31 complement. We build the XML, seal it with your CSD and stamp it.
POST /invoice/stampxml
Your already-sealed XML, Base64-encoded (xmlbase64 field).
POST /invoice/stampxmlfile
Your already-sealed XML as a file (xml field), up to 40 MB.
  • IdCCP and Folio set to "AUTO": the response includes the assigned Serie and Folio.
  • The issuer's RFC and name are taken from your account.
  • No TotalDistRec, NumTotalMercancias or PesoBrutoTotal: the API calculates them.
  • By road, each destination carries its DistanciaRecorrida and the driver (figure 01) its NumLicencia.
Production
https://app.facturadigital.com.mx/api/v5
Sandbox
https://sandbox-app.facturadigital.com.mx/api/v5
timbrar-carta-porte.shSample data
# FD_API=https://sandbox-app.facturadigital.com.mx/api/v5
curl -X POST "$FD_API/invoice/create" \
  -H "X-Api-Key: $FD_API_KEY" \
  --data-urlencode "json@carta-porte.json"
carta-porte.jsonSample data
{
  "Version": "4.0",
  "Serie": "CP",
  "Folio": "AUTO",
  "Fecha": "AUTO",
  "FormaPago": "03",
  "MetodoPago": "PUE",
  "Moneda": "MXN",
  "TipoDeComprobante": "I",
  "Exportacion": "01",
  "LugarExpedicion": "64000",
  "SubTotal": "5000.00",
  "Total": "5800.00",
  "Emisor": { "RegimenFiscal": "601" },
  "Receptor": {
    "Rfc": "XIA190128J61",
    "Nombre": "XENON INDUSTRIAL ARTICLES",
    "DomicilioFiscalReceptor": "76343",
    "RegimenFiscalReceptor": "601",
    "UsoCFDI": "G03"
  },
  "Conceptos": [{
    "ClaveProdServ": "78101802",
    "Cantidad": "1",
    "ClaveUnidad": "E48",
    "Descripcion": "Flete Monterrey a Saltillo",
    "ValorUnitario": "5000.00",
    "Importe": "5000.00",
    "ObjetoImp": "02",
    "Impuestos": { "Traslados": [{ ... }] }
  }],
  "Impuestos": { ... },
  "Complemento": {
    "CartaPorte31": {
      "Version": "3.1",
      "IdCCP": "AUTO",
      "TranspInternac": "No",
      "Ubicaciones": [
        {
          "TipoUbicacion": "Origen",
          "RFCRemitenteDestinatario": "XIA190128J61",
          "FechaHoraSalidaLlegada": "2026-09-28T08:00:00",
          "Domicilio": {
            "Estado": "NLE", "Pais": "MEX", "CodigoPostal": "64000"
          }
        },
        {
          "TipoUbicacion": "Destino",
          "RFCRemitenteDestinatario": "XIA190128J61",
          "FechaHoraSalidaLlegada": "2026-09-28T10:30:00",
          "DistanciaRecorrida": "85",
          "Domicilio": {
            "Estado": "COA", "Pais": "MEX", "CodigoPostal": "25000"
          }
        }
      ],
      "Mercancias": {
        "UnidadPeso": "KGM",
        "Mercancia": [{
          "BienesTransp": "31161500",
          "Descripcion": "Tornillería",
          "Cantidad": "10",
          "ClaveUnidad": "H87",
          "PesoEnKg": "1200"
        }],
        "Autotransporte": {
          "PermSCT": "TPAF01",
          "NumPermisoSCT": "PERMISO-DE-MUESTRA",
          "IdentificacionVehicular": {
            "ConfigVehicular": "C2",
            "PesoBrutoVehicular": "10.5",
            "PlacaVM": "123AB4",
            "AnioModeloVM": "2022"
          },
          "Seguros": {
            "AseguraRespCivil": "ASEGURADORA DE MUESTRA",
            "PolizaRespCivil": "POL-000123"
          }
        }
      },
      "FiguraTransporte": [{
        "TipoFigura": "01",
        "RFCFigura": "RFC_DEL_OPERADOR",
        "NumLicencia": "LIC-000123",
        "NombreFigura": "NOMBRE DEL OPERADOR"
      }]
    }
  }
}
respuesta-200.jsonSample data
{
  "message": "The document was generated successfully",
  "code": 200,
  "cfdi": {
    "UUID": "6FA90F39-2D7A-4F1C-9B3E-5C1D8A0E7B42",
    "FechaTimbrado": "2026-09-28T08:01:12",
    "CadenaQR": "https://verificacfdi.facturaelectronica.sat.gob.mx/...",
    "XmlBase64": "PD94bWwgdmVyc2lvbj0iMS4wIi...",
    "PDF": "https://app.facturadigital.com.mx/docs/pdf/6FA90F39-...",
    "XML": "https://app.facturadigital.com.mx/docs/xml/...",
    "Serie": "CP",
    "Folio": "1042",
    ...
  }
}

Integrate it in 4 steps

From the sandbox to your first Carta Porte stamped in production.

  1. 01

    Create your sandbox account

    It's free and stamps with a test PAC, with no tax validity. Upload your CSD and copy your key from Configuración → Datos de facturación.

  2. 02

    Set up your series

    If you send Folio "AUTO", create the series for the document type (I or T) in Configuración → Series y Folios.

  3. 03

    Map your trips

    Each trip in your system becomes a CartaPorte31: origin and destinations with their distance, goods with their weight, the vehicle and the driver.

  4. 04

    Stamp and go live

    Call POST /invoice/create and store the UUID, Serie and Folio. To go live you switch the base URL and the key; your code stays the same.

Common errors and how to fix them

Errors respond with HTTP 400 and a code in the body. Carta Porte errors also include, in errors, the SAT's CP code and the field path.

400 · CP193 / CP194There's road transport, but no transport figure is sent or none of them is the driver (TipoFigura 01).Add the driver in FiguraTransporte: it's required by road.
400 · CP196The driver has no NumLicencia.Send the license number of figure 01.
400 · CP141A destination is missing its DistanciaRecorrida, or the origin has one.By road, each destination carries its distance in kilometers; the origin carries none.
400 · CP109On an income Carta Porte, the line item's ClaveProdServ isn't a transport service.Use one of the 41 transport codes the SAT accepts, such as 78101802.
400 · CP107A transfer (T) with a receiver other than your company.When you move your own goods, the receiver is your own RFC.
702The document doesn't match the SAT schema.Check errors: each one includes the element, the field and the message in Spanish.
601 · 602Your account has no folios left (601) or no active CSD (602).Check your balance with GET /account/balance and upload your CSD in Configuración → Certificados.
5037 · 50345037: stamping couldn't connect. 5034: stamping got no response.With 5037 you can retry. With 5034 the CFDI may have been stamped: look it up with the SAT using the Serie and Folio in the response before retrying.

What a Carta Porte error looks like

errorType is cartaporte_validation and each item in errors carries the CP code, the field path and the message in Spanish. The docs link points to the guide for these errors.

respuesta-400.jsonSample data
{
  "message": "Invalid 'CartaPorte31' complement: CP193: Falta la figura del transporte. ...",
  "code": 400,
  "errorType": "cartaporte_validation",
  "docs": "https://docs.facturadigital.com.mx/errores/cartaporte",
  "errors": [{
    "severity": "error",
    "code": "CP193",
    "field": "Complemento.CartaPorte31.FiguraTransporte",
    "message": "Falta la figura del transporte. Con autotransporte tienes que registrar al menos al operador (quien maneja la unidad)."
  }]
}

Keep going

Payment complement

Stamp the REP for your PPD invoices with the same endpoint and the same key.

Cancellation

Cancel a CFDI with reasons 01 to 04 and get the SAT acknowledgment. Cancelling uses no folio.

Carta Porte on the web

Types, rules and how to fill in the complement if you stamp it from the app.

Sandbox

A free test environment with the same API v5 as production.

Official SDKs

Libraries to call API v5 from your language, with the same endpoints.

API v5

Authentication, endpoints and the three ways to stamp: JSON, Base64 XML or an XML file.

Carta Porte API questions

Something missing? Message us or check the full reference.

Can I stamp Carta Porte 3.1 via API?

Yes. Send the CFDI with Complemento.CartaPorte31 to POST /invoice/create, as income (I) or transfer (T), and you get the stamped CFDI with its XML and PDF. If you already build and seal your XML, stamp it at /invoice/stampxml (Base64) or /invoice/stampxmlfile (a file up to 40 MB).

Which transport modes does the API cover?

Road, sea and air transport. The API doesn't generate the TransporteFerroviario node: if you move goods by rail, message us before you integrate.

What if my system still sends Carta Porte 3.0?

A CartaPorte30 is converted to 3.1 before stamping, including the change from RegimenAduanero to RegimenesAduaneros. It's then validated just like a 3.1.

Do I have to calculate TotalDistRec, NumTotalMercancias and PesoBrutoTotal?

No. The API calculates them from the destinations' distances, the number of goods and their weights. If a weight or a quantity isn't a valid number, you get CP149 or CP154 so you can fix that value.

How do I stamp a transfer of my own goods?

With TipoDeComprobante T and your own RFC as the receiver (rule CP107). The API sets SubTotal, Total and amounts to 0, the currency to XXX and the CFDI use to S01, removes the payment form and method, and marks the line items as not subject to tax.

What happens if the Carta Porte breaks a SAT rule?

Nothing is stamped and no folio is used. You get HTTP 400 with errorType cartaporte_validation and the errors list: the SAT's CP code, the field path and the message in Spanish.

How much does the Carta Porte API cost?

The API is included: you pay for folios, not for the API. Each stamped CFDI uses 1 folio, same as on the web, and folios never expire. The sandbox is free.

Stamp your first Carta Porte in the sandbox

It's free and uses the same API v5 as production. Once it works, you switch the base URL and the key.