Upload Invoice
curl --request POST \
--url https://api.example.com/api/invoices/upload \
--header 'Content-Type: application/json' \
--data '
{
"profileId": "<string>"
}
'import requests
url = "https://api.example.com/api/invoices/upload"
payload = { "profileId": "<string>" }
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({profileId: '<string>'})
};
fetch('https://api.example.com/api/invoices/upload', 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.example.com/api/invoices/upload",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'profileId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/invoices/upload"
payload := strings.NewReader("{\n \"profileId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/invoices/upload")
.header("Content-Type", "application/json")
.body("{\n \"profileId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/invoices/upload")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"profileId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"message": "<string>",
"data": {
"id": "<string>",
"profile_id": "<string>",
"uuid": "<string>",
"fecha": "<string>",
"mes": 123,
"año": 123,
"total": 123,
"subtotal": 123,
"iva": 123,
"iva_amount": 123,
"retencion_iva_amount": 123,
"retencion_isr_amount": 123,
"tipo": {},
"rfc_emisor": "<string>",
"nombre_emisor": "<string>",
"regimen_fiscal_emisor": "<string>",
"rfc_receptor": "<string>",
"nombre_receptor": "<string>",
"regimen_fiscal_receptor": "<string>",
"concepto": "<string>",
"pagos": [
{}
],
"complemento_pago": {},
"validacion": {},
"created_at": "<string>",
"updated_at": "<string>"
},
"validacion": {
"rfcVerificado": true,
"regimenFiscalVerificado": true,
"uuidDuplicado": true,
"advertencias": [
"<string>"
],
"errores": [
"<string>"
],
"valido": true
},
"tipo": {}
}Invoices
Upload Invoice
Upload a CFDI XML invoice file
POST
/
api
/
invoices
/
upload
Upload Invoice
curl --request POST \
--url https://api.example.com/api/invoices/upload \
--header 'Content-Type: application/json' \
--data '
{
"profileId": "<string>"
}
'import requests
url = "https://api.example.com/api/invoices/upload"
payload = { "profileId": "<string>" }
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({profileId: '<string>'})
};
fetch('https://api.example.com/api/invoices/upload', 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.example.com/api/invoices/upload",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'profileId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/invoices/upload"
payload := strings.NewReader("{\n \"profileId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/invoices/upload")
.header("Content-Type", "application/json")
.body("{\n \"profileId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/invoices/upload")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"profileId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"message": "<string>",
"data": {
"id": "<string>",
"profile_id": "<string>",
"uuid": "<string>",
"fecha": "<string>",
"mes": 123,
"año": 123,
"total": 123,
"subtotal": 123,
"iva": 123,
"iva_amount": 123,
"retencion_iva_amount": 123,
"retencion_isr_amount": 123,
"tipo": {},
"rfc_emisor": "<string>",
"nombre_emisor": "<string>",
"regimen_fiscal_emisor": "<string>",
"rfc_receptor": "<string>",
"nombre_receptor": "<string>",
"regimen_fiscal_receptor": "<string>",
"concepto": "<string>",
"pagos": [
{}
],
"complemento_pago": {},
"validacion": {},
"created_at": "<string>",
"updated_at": "<string>"
},
"validacion": {
"rfcVerificado": true,
"regimenFiscalVerificado": true,
"uuidDuplicado": true,
"advertencias": [
"<string>"
],
"errores": [
"<string>"
],
"valido": true
},
"tipo": {}
}Authentication
This endpoint requires authentication. Include your access token in the Authorization header.Authorization: Bearer YOUR_ACCESS_TOKEN
Request Body
This endpoint expects a multipart/form-data request with the following fields:file
required
XML file containing the CFDI invoice. The file must be a valid Mexican CFDI XML.
string
required
Profile ID to associate the invoice with. The system automatically determines if the invoice is an income (factura) or expense (gasto) based on the RFC in the XML.
Response
string
Success message
Invoice
The created invoice object
Show Invoice
Show Invoice
string
Unique identifier for the invoice
string
Profile ID this invoice belongs to
string
CFDI UUID (Folio Fiscal)
string
Invoice date in ISO format
number
Month extracted from invoice date (1-12)
number
Year extracted from invoice date
number
Total amount of the invoice
number
Subtotal before taxes
number
IVA percentage rate
number
IVA transferred amount
number
IVA withholding amount
number
ISR withholding amount
enum
Payment type:
PUE, PPD, or COMPLEMENTO_PAGOstring
RFC of the issuer
string
Name of the issuer
string
Tax regime code of the issuer
string
RFC of the recipient
string
Name of the recipient
string
Tax regime code of the recipient
string
Invoice concept or description
array
Array of payment records
object
Payment complement information (for COMPLEMENTO_PAGO type)
object
Validation results for the uploaded invoice
string
Creation timestamp in ISO format
string
Last update timestamp in ISO format
object
Validation state of the uploaded invoice
Show ValidationState
Show ValidationState
enum
Classification of the invoice:
factura (income) or gasto (expense)Example Request
curl -X POST "https://api.contafy.com/api/invoices/upload" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-F "xml=@invoice.xml" \
-F "profileId=prof_123"
const formData = new FormData();
formData.append('xml', file);
formData.append('profileId', 'prof_123');
const response = await fetch('https://api.contafy.com/api/invoices/upload', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: formData
});
const data = await response.json();
Example Response
{
"message": "Factura procesada exitosamente",
"data": {
"id": "inv_abc123",
"profile_id": "prof_123",
"uuid": "12345678-90AB-CDEF-1234-567890ABCDEF",
"fecha": "2026-03-15T10:30:00Z",
"mes": 3,
"año": 2026,
"total": 11600.00,
"subtotal": 10000.00,
"iva": 16,
"iva_amount": 1600.00,
"tipo": "PUE",
"rfc_emisor": "XAXX010101000",
"nombre_emisor": "Empresa Ejemplo SA de CV",
"regimen_fiscal_emisor": "601",
"rfc_receptor": "BAXX010101000",
"nombre_receptor": "Cliente Ejemplo",
"regimen_fiscal_receptor": "612",
"concepto": "Servicios de consultoría",
"pagos": [],
"complemento_pago": null,
"validacion": {
"rfcVerificado": true,
"regimenFiscalVerificado": true,
"uuidDuplicado": false,
"advertencias": [],
"errores": [],
"valido": true
},
"created_at": "2026-03-15T10:35:00Z",
"updated_at": "2026-03-15T10:35:00Z"
},
"validacion": {
"rfcVerificado": true,
"regimenFiscalVerificado": true,
"uuidDuplicado": false,
"advertencias": [],
"errores": [],
"valido": true
},
"tipo": "factura"
}
Error Responses
{
"error": "Unauthorized",
"message": "Invalid or missing access token"
}
{
"error": "Bad Request",
"message": "Invalid XML file or missing required fields"
}
{
"error": "Conflict",
"message": "Invoice with this UUID already exists",
"validacion": {
"uuidDuplicado": true,
"valido": false
}
}
{
"error": "Unprocessable Entity",
"message": "Invalid CFDI XML format",
"validacion": {
"errores": ["Invalid XML structure"],
"valido": false
}
}
{
"error": "Internal Server Error",
"message": "An unexpected error occurred"
}
⌘I