curl --request GET \
--url https://api.ipsofactura.com/cfdi/exports/{id} \
--header 'x-api: <api-key>'import requests
url = "https://api.ipsofactura.com/cfdi/exports/{id}"
headers = {"x-api": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api': '<api-key>'}};
fetch('https://api.ipsofactura.com/cfdi/exports/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ipsofactura.com/cfdi/exports/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.ipsofactura.com/cfdi/exports/{id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.ipsofactura.com/cfdi/exports/{id}")
.header("x-api", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ipsofactura.com/cfdi/exports/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"desde": "2026-08-01",
"estatus": "listo",
"hasta": "2026-08-31",
"id": "9a4f07ff-3abc-435f-b7a6-88c2bc65b4c1",
"tamano_bytes": 5242880,
"total_cfdis": 1043,
"url": "https://storage.ipsofactura.com/exports/9a4f07ff.zip?sig=..."
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}Consultar export masivo
Devuelve el estado del export y, cuando está listo, una URL firmada para descargar el ZIP. La URL es de solo lectura y vive 15 minutos desde que se genera: no la almacenes, guarda el id y vuelve a llamar a este endpoint.
estatus es pendiente, en_proceso, listo o fallido. Un export listo con expirado: true y sin url se generó bien pero su archivo ya se borró por la política de retención (7 días): hay que volver a pedirlo, no es un error.
curl --request GET \
--url https://api.ipsofactura.com/cfdi/exports/{id} \
--header 'x-api: <api-key>'import requests
url = "https://api.ipsofactura.com/cfdi/exports/{id}"
headers = {"x-api": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api': '<api-key>'}};
fetch('https://api.ipsofactura.com/cfdi/exports/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ipsofactura.com/cfdi/exports/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.ipsofactura.com/cfdi/exports/{id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.ipsofactura.com/cfdi/exports/{id}")
.header("x-api", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ipsofactura.com/cfdi/exports/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"desde": "2026-08-01",
"estatus": "listo",
"hasta": "2026-08-31",
"id": "9a4f07ff-3abc-435f-b7a6-88c2bc65b4c1",
"tamano_bytes": 5242880,
"total_cfdis": 1043,
"url": "https://storage.ipsofactura.com/exports/9a4f07ff.zip?sig=..."
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}{
"code": "VALIDATION_ERROR",
"id": "<string>",
"idempotencyKey": "<string>",
"message": "CFDI40147: El RFC del receptor no se encuentra en la lista de contribuyentes inscritos no cancelados del SAT",
"retryAfter": 123,
"sat_code": "CFDI40147"
}Authorizations
API key emitida por Ipsofactura, enviada en el header x-api.
Path Parameters
Response
Estado del export
Estado de un export masivo de XML
Cuándo terminó de generarse o de fallar.
Cuándo se pidió el export.
Primer día del rango, inclusive.
"2026-08-01"
Por qué falló, cuando el estatus es fallido. Código estable; el texto de error_message es informativo y no debe parsearse.
"EXPORT_TOO_LARGE"
Descripción del fallo, para quien lo lea.
pendiente (en cola), en_proceso (armando el archivo), listo (descargable) o fallido.
"pendiente"
true cuando el export se generó correctamente pero su archivo ya se borró por la política de retención. No es un error: hay que volver a pedir el export.
false
Último día del rango, inclusive.
"2026-08-31"
Id del export. Es lo que se debe almacenar: la URL de descarga se vuelve a pedir con él.
"9a4f07ff-3abc-435f-b7a6-88c2bc65b4c1"
Emisor al que se limitó el export, si se pidió así.
"EKU9003173C9"
Tamaño del ZIP en bytes. Sólo cuando el export está listo.
5242880
CFDIs incluidos en el archivo. Sólo cuando el export está listo. Puede ser 0: un rango sin CFDIs produce un ZIP válido y vacío.
1043
URL firmada, de solo lectura, con vigencia de 15 minutos desde que se genera. No la almacenes: guarda el id y vuelve a llamar a GET /cfdi/exports/{id}. El ZIP contiene un XML por CFDI, nombrado por folio fiscal, más un manifiesto.csv que los relaciona con serie, folio, receptor, total y estatus.
"https://storage.ipsofactura.com/exports/9a4f07ff.zip?sig=..."