Skip to content
Documentation sections

Migrating from a PAC? Use stampxml

If your system already generates and seals the CFDI 4.0 XML, you can migrate to Factura Digital without rewriting that part. You send the same sealed XML to invoice/stampxml or invoice/stampxmlfile and the API stamps it. This guide describes the changes to your integration and how to test them in the sandbox before using your production certificate.

POST/invoice/stampxml
POST/invoice/stampxmlfile

What stays and what changes

In your integration
XML and original string generationThey stay. Your system keeps generating the CFDI 4.0 according to the SAT's Anexo 20.
Seal with your CSDIt stays. You do not need to upload your CSD to the account to stamp.
URL and authenticationThey change. Requests go to the API v5 with the X-Api-Key header; details are in Keys and environments.
Sending the XMLIt changes. The XML travels in Base64 in the xmlbase64 field (stampxml) or as a file in the xml field of a multipart request (stampxmlfile).
ResponseIt changes. It is a JSON with the UUID, the stamp data and the full stamped XML in cfdi.XmlBase64.
PDF and email deliveryThey stay in your system. stampxml does not generate a PDF, and the CFDI does not appear in your account listings or get sent with invoice/send.
CancellationIt is done with invoice/cancelwithcsd, sending your CSD in the request. See the cancellation guide.

Migration steps

1. Create your sandbox account

The sandbox is free and uses the same API as production. Get the API key of your sandbox account and set it up with the sandbox base URL, as described in Keys and environments.

2. Test the connection with a test XML

Generate a sealed XML in the test XML generator and send it to the sandbox invoice/stampxml. An HTTP 200 response confirms that the key, the URL and the request format are correct. The generator includes the send commands with the downloaded file name.

3. Check your system's sealing

Generate an XML with the “Unsealed” option, download the test issuer's .cer and .key and seal the XML with your code. Then check it in the XML validator, which recomputes the original string with the SAT XSLT and reports whether the seal matches. This confirms that your system seals correctly before you install your production certificate.

4. Replace the stamping call

Replace the call to your current provider with the request to invoice/stampxml. FD_API is the environment base URL and FD_API_KEY is the account API key. To send the file without encoding it, use invoice/stampxmlfile with the xml field.

curl -sS -X POST "$FD_API/invoice/stampxml" \
  -H "X-Api-Key: $FD_API_KEY" \
  --data-urlencode "xmlbase64=$(base64 < factura-sellada.xml | tr -d '\n')"

5. Adapt how you read the response

Both methods return the same response. Store the stamped XML from cfdi.XmlBase64, which is the CFDI with the TimbreFiscalDigital.

200
{
  "message": "XML stamped successfully",
  "code": 200,
  "cfdi": {
    "UUID": "6F0C2E1A-9B3D-4C7E-8A51-2D4F6B8C0E13",
    "FechaTimbrado": "2026-11-04T10:15:30",
    "NoCertificado": "30001000000500003416",
    "SelloCFD": "Q2V4...Zm9vYmFy",
    "NoCertificadoSAT": "30001000000500003456",
    "SelloSAT": "Tm9w...ZGF0YQ==",
    "RfcProvCertif": "AAA010101AAA",
    "CadenaOrigTFD": "||1.1|6F0C2E1A-9B3D-4C7E-8A51-2D4F6B8C0E13|2026-11-04T10:15:30|…||",
    "CadenaQR": "https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?id=6F0C2E1A-…",
    "XmlBase64": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4..."
  }
}

cfdi fields

UUIDstring
Tax folio assigned at stamping.
XmlBase64string
Full stamped XML in Base64. This is the CFDI you must store.
FechaTimbradostring
Stamping date and time.
SelloSAT and NoCertificadoSATstring
Stamp seal and SAT certificate number, for your printed representation.
CadenaOrigTFDstring
Original string of the digital tax stamp, for your PDF.
CadenaQRstring
SAT verification URL for your PDF's QR code.

6. Handle errors and retries

  • HTTP 400 with a SAT code at the start of message means the XML was rejected. Look up the code in the error matrix and fix the XML.
  • timbre_previo means that XML was already stamped. context.uuid carries the original UUID and no other folio is used, so you must not resend it.
  • 601 means the account has no folios available.
  • 5037 means the stamping service could not be reached and nothing was sent. You can retry the same request.
  • 5034 means no response arrived in time and the CFDI may have been stamped. If context.uuid is in the response, that is the UUID; otherwise, verify before retrying.
  • Set a timeout of at least 120 seconds in your HTTP client.

7. Move to production

Switch the base URL to production, use your production account API key and seal with your CSD. Each stamped CFDI uses one folio; a rejection does not use folios. The full reference for both methods is in Stamp sealed XML.

Migration tools

Checked against the production API v5 on 2026-11-03.