Create extraction
curl --request POST \
--url https://api.taxo.co/v1/extractions \
--header 'Content-Type: application/json' \
--data '
{
"subject": {
"identifier": "<string>",
"name": "<string>"
},
"credentials": {
"type": "<string>",
"password": "<string>",
"privateKey": "<string>",
"certificate": "<string>"
},
"options": {
"informationType": "<string>",
"period": {
"from": "<string>",
"to": "<string>"
},
"direction": "<string>"
},
"filters": {
"emitters": [
{}
],
"receivers": [
{}
],
"minAmount": 123,
"maxAmount": 123
}
}
'import requests
url = "https://api.taxo.co/v1/extractions"
payload = {
"subject": {
"identifier": "<string>",
"name": "<string>"
},
"credentials": {
"type": "<string>",
"password": "<string>",
"privateKey": "<string>",
"certificate": "<string>"
},
"options": {
"informationType": "<string>",
"period": {
"from": "<string>",
"to": "<string>"
},
"direction": "<string>"
},
"filters": {
"emitters": [{}],
"receivers": [{}],
"minAmount": 123,
"maxAmount": 123
}
}
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({
subject: {identifier: '<string>', name: '<string>'},
credentials: {
type: '<string>',
password: '<string>',
privateKey: '<string>',
certificate: '<string>'
},
options: {
informationType: '<string>',
period: {from: '<string>', to: '<string>'},
direction: '<string>'
},
filters: {emitters: [{}], receivers: [{}], minAmount: 123, maxAmount: 123}
})
};
fetch('https://api.taxo.co/v1/extractions', 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.taxo.co/v1/extractions",
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([
'subject' => [
'identifier' => '<string>',
'name' => '<string>'
],
'credentials' => [
'type' => '<string>',
'password' => '<string>',
'privateKey' => '<string>',
'certificate' => '<string>'
],
'options' => [
'informationType' => '<string>',
'period' => [
'from' => '<string>',
'to' => '<string>'
],
'direction' => '<string>'
],
'filters' => [
'emitters' => [
[
]
],
'receivers' => [
[
]
],
'minAmount' => 123,
'maxAmount' => 123
]
]),
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.taxo.co/v1/extractions"
payload := strings.NewReader("{\n \"subject\": {\n \"identifier\": \"<string>\",\n \"name\": \"<string>\"\n },\n \"credentials\": {\n \"type\": \"<string>\",\n \"password\": \"<string>\",\n \"privateKey\": \"<string>\",\n \"certificate\": \"<string>\"\n },\n \"options\": {\n \"informationType\": \"<string>\",\n \"period\": {\n \"from\": \"<string>\",\n \"to\": \"<string>\"\n },\n \"direction\": \"<string>\"\n },\n \"filters\": {\n \"emitters\": [\n {}\n ],\n \"receivers\": [\n {}\n ],\n \"minAmount\": 123,\n \"maxAmount\": 123\n }\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.taxo.co/v1/extractions")
.header("Content-Type", "application/json")
.body("{\n \"subject\": {\n \"identifier\": \"<string>\",\n \"name\": \"<string>\"\n },\n \"credentials\": {\n \"type\": \"<string>\",\n \"password\": \"<string>\",\n \"privateKey\": \"<string>\",\n \"certificate\": \"<string>\"\n },\n \"options\": {\n \"informationType\": \"<string>\",\n \"period\": {\n \"from\": \"<string>\",\n \"to\": \"<string>\"\n },\n \"direction\": \"<string>\"\n },\n \"filters\": {\n \"emitters\": [\n {}\n ],\n \"receivers\": [\n {}\n ],\n \"minAmount\": 123,\n \"maxAmount\": 123\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.taxo.co/v1/extractions")
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 \"subject\": {\n \"identifier\": \"<string>\",\n \"name\": \"<string>\"\n },\n \"credentials\": {\n \"type\": \"<string>\",\n \"password\": \"<string>\",\n \"privateKey\": \"<string>\",\n \"certificate\": \"<string>\"\n },\n \"options\": {\n \"informationType\": \"<string>\",\n \"period\": {\n \"from\": \"<string>\",\n \"to\": \"<string>\"\n },\n \"direction\": \"<string>\"\n },\n \"filters\": {\n \"emitters\": [\n {}\n ],\n \"receivers\": [\n {}\n ],\n \"minAmount\": 123,\n \"maxAmount\": 123\n }\n}"
response = http.request(request)
puts response.read_body{
"error": {
"code": "INVALID_RFC",
"message": "The provided RFC does not have a valid format",
"details": {
"field": "subject.identifier",
"provided": "ABC01010",
"expected": "RFC of 10 or 13 characters"
}
}
}
{
"error": {
"code": "INVALID_CREDENTIALS",
"message": "The CIEC credentials are incorrect",
"details": {
"field": "credentials.password",
"hint": "Verify that the password is encoded in base64"
}
}
}
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "You have exceeded the limit of 10 extractions per hour",
"details": {
"limit": 10,
"window": "1 hour",
"resetAt": "2025-01-04T14:00:00Z"
}
}
}
SAT API Reference
Create extraction
Start a new process for extracting tax documents from SAT
POST
/
v1
/
extractions
Create extraction
curl --request POST \
--url https://api.taxo.co/v1/extractions \
--header 'Content-Type: application/json' \
--data '
{
"subject": {
"identifier": "<string>",
"name": "<string>"
},
"credentials": {
"type": "<string>",
"password": "<string>",
"privateKey": "<string>",
"certificate": "<string>"
},
"options": {
"informationType": "<string>",
"period": {
"from": "<string>",
"to": "<string>"
},
"direction": "<string>"
},
"filters": {
"emitters": [
{}
],
"receivers": [
{}
],
"minAmount": 123,
"maxAmount": 123
}
}
'import requests
url = "https://api.taxo.co/v1/extractions"
payload = {
"subject": {
"identifier": "<string>",
"name": "<string>"
},
"credentials": {
"type": "<string>",
"password": "<string>",
"privateKey": "<string>",
"certificate": "<string>"
},
"options": {
"informationType": "<string>",
"period": {
"from": "<string>",
"to": "<string>"
},
"direction": "<string>"
},
"filters": {
"emitters": [{}],
"receivers": [{}],
"minAmount": 123,
"maxAmount": 123
}
}
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({
subject: {identifier: '<string>', name: '<string>'},
credentials: {
type: '<string>',
password: '<string>',
privateKey: '<string>',
certificate: '<string>'
},
options: {
informationType: '<string>',
period: {from: '<string>', to: '<string>'},
direction: '<string>'
},
filters: {emitters: [{}], receivers: [{}], minAmount: 123, maxAmount: 123}
})
};
fetch('https://api.taxo.co/v1/extractions', 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.taxo.co/v1/extractions",
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([
'subject' => [
'identifier' => '<string>',
'name' => '<string>'
],
'credentials' => [
'type' => '<string>',
'password' => '<string>',
'privateKey' => '<string>',
'certificate' => '<string>'
],
'options' => [
'informationType' => '<string>',
'period' => [
'from' => '<string>',
'to' => '<string>'
],
'direction' => '<string>'
],
'filters' => [
'emitters' => [
[
]
],
'receivers' => [
[
]
],
'minAmount' => 123,
'maxAmount' => 123
]
]),
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.taxo.co/v1/extractions"
payload := strings.NewReader("{\n \"subject\": {\n \"identifier\": \"<string>\",\n \"name\": \"<string>\"\n },\n \"credentials\": {\n \"type\": \"<string>\",\n \"password\": \"<string>\",\n \"privateKey\": \"<string>\",\n \"certificate\": \"<string>\"\n },\n \"options\": {\n \"informationType\": \"<string>\",\n \"period\": {\n \"from\": \"<string>\",\n \"to\": \"<string>\"\n },\n \"direction\": \"<string>\"\n },\n \"filters\": {\n \"emitters\": [\n {}\n ],\n \"receivers\": [\n {}\n ],\n \"minAmount\": 123,\n \"maxAmount\": 123\n }\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.taxo.co/v1/extractions")
.header("Content-Type", "application/json")
.body("{\n \"subject\": {\n \"identifier\": \"<string>\",\n \"name\": \"<string>\"\n },\n \"credentials\": {\n \"type\": \"<string>\",\n \"password\": \"<string>\",\n \"privateKey\": \"<string>\",\n \"certificate\": \"<string>\"\n },\n \"options\": {\n \"informationType\": \"<string>\",\n \"period\": {\n \"from\": \"<string>\",\n \"to\": \"<string>\"\n },\n \"direction\": \"<string>\"\n },\n \"filters\": {\n \"emitters\": [\n {}\n ],\n \"receivers\": [\n {}\n ],\n \"minAmount\": 123,\n \"maxAmount\": 123\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.taxo.co/v1/extractions")
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 \"subject\": {\n \"identifier\": \"<string>\",\n \"name\": \"<string>\"\n },\n \"credentials\": {\n \"type\": \"<string>\",\n \"password\": \"<string>\",\n \"privateKey\": \"<string>\",\n \"certificate\": \"<string>\"\n },\n \"options\": {\n \"informationType\": \"<string>\",\n \"period\": {\n \"from\": \"<string>\",\n \"to\": \"<string>\"\n },\n \"direction\": \"<string>\"\n },\n \"filters\": {\n \"emitters\": [\n {}\n ],\n \"receivers\": [\n {}\n ],\n \"minAmount\": 123,\n \"maxAmount\": 123\n }\n}"
response = http.request(request)
puts response.read_body{
"error": {
"code": "INVALID_RFC",
"message": "The provided RFC does not have a valid format",
"details": {
"field": "subject.identifier",
"provided": "ABC01010",
"expected": "RFC of 10 or 13 characters"
}
}
}
{
"error": {
"code": "INVALID_CREDENTIALS",
"message": "The CIEC credentials are incorrect",
"details": {
"field": "credentials.password",
"hint": "Verify that the password is encoded in base64"
}
}
}
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "You have exceeded the limit of 10 extractions per hour",
"details": {
"limit": 10,
"window": "1 hour",
"resetAt": "2025-01-04T14:00:00Z"
}
}
}
Description
This endpoint starts a process for extracting tax documents from SAT. Extraction is an asynchronous process that can take several minutes depending on the volume of documents.The extraction process is asynchronous. Use the returned
publicId to check status or configure webhooks to receive notifications.Request
object
required
object
required
object
required
Extraction options
Show Propiedades de options
Show Propiedades de options
object
Response
string
Unique extraction ID for subsequent queries
string
Current status:
PENDING, PROCESSING, COMPLETED, FAILEDstring
Creation timestamp in ISO 8601 format
object
Copy of the options sent in the request
object
number
Number of documents found (0 initially)
number
Number of documents processed successfully
number
Number of documents that failed to process
Examples
curl -X POST "https://api.taxo.co/v1/extractions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"identifier": "ABC010101ABC",
"name": "Empresa ABC S.A. de C.V."
},
"credentials": {
"type": "CIEC",
"password": "bXlQYXNzd29yZDEyM0A="
},
"options": {
"informationType": "INVOICE",
"period": {
"from": "2024-01-01",
"to": "2024-12-31"
},
"direction": "RECEIVED"
},
"filters": {
"emitters": ["XYZ020202XYZ"],
"minAmount": 1000
}
}'
const response = await fetch('https://api.taxo.co/v1/extractions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.TAXO_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
subject: {
identifier: 'ABC010101ABC',
name: 'Empresa ABC S.A. de C.V.'
},
credentials: {
type: 'CIEC',
password: Buffer.from('myPassword123@').toString('base64')
},
options: {
informationType: 'INVOICE',
period: {
from: '2024-01-01',
to: '2024-12-31'
},
direction: 'RECEIVED'
},
filters: {
emitters: ['XYZ020202XYZ'],
minAmount: 1000
}
})
});
const extraction = await response.json();
console.log('Extracción creada:', extraction.publicId);
import requests
import base64
# Encode password
password_b64 = base64.b64encode('myPassword123@'.encode()).decode()
payload = {
'subject': {
'identifier': 'ABC010101ABC',
'name': 'Empresa ABC S.A. de C.V.'
},
'credentials': {
'type': 'CIEC',
'password': password_b64
},
'options': {
'informationType': 'INVOICE',
'period': {
'from': '2024-01-01',
'to': '2024-12-31'
},
'direction': 'RECEIVED'
},
'filters': {
'emitters': ['XYZ020202XYZ'],
'minAmount': 1000
}
}
response = requests.post(
'https://api.taxo.co/v1/extractions',
json=payload,
headers={
'Authorization': f'Bearer {os.environ["TAXO_API_KEY"]}',
'Content-Type': 'application/json'
}
)
extraction = response.json()
print(f'Extraction created: {extraction["publicId"]}')
// Usando Spring RestTemplate
RestTemplate restTemplate = new RestTemplate();
Map<String, Object> payload = new HashMap<>();
payload.put("subject", Map.of(
"identifier", "ABC010101ABC",
"name", "Empresa ABC S.A. de C.V."
));
payload.put("credentials", Map.of(
"type", "CIEC",
"password", Base64.getEncoder().encodeToString("myPassword123@".getBytes())
));
payload.put("options", Map.of(
"informationType", "INVOICE",
"period", Map.of(
"from", "2024-01-01",
"to", "2024-12-31"
),
"direction", "RECEIVED"
));
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + System.getenv("TAXO_API_KEY"));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Map<String, Object>> request = new HttpEntity<>(payload, headers);
ResponseEntity<Map> response = restTemplate.postForEntity(
"https://api.taxo.co/v1/extractions",
request,
Map.class
);
System.out.println("Extraction created: " + response.getBody().get("publicId"));
Successful response
{
"publicId": "JOB20250104123456789A",
"status": "PENDING",
"createdAt": "2025-01-04T12:34:56.789Z",
"options": {
"informationType": "INVOICE",
"period": {
"from": "2024-01-01",
"to": "2024-12-31"
},
"direction": "RECEIVED"
},
"subject": {
"identification": "ABC010101ABC",
"fullName": "Empresa ABC S.A. de C.V.",
"personType": "MORAL"
},
"discoveryCount": 0,
"completedCount": 0,
"failedCount": 0
}
Common errors
{
"error": {
"code": "INVALID_RFC",
"message": "The provided RFC does not have a valid format",
"details": {
"field": "subject.identifier",
"provided": "ABC01010",
"expected": "RFC of 10 or 13 characters"
}
}
}
{
"error": {
"code": "INVALID_CREDENTIALS",
"message": "The CIEC credentials are incorrect",
"details": {
"field": "credentials.password",
"hint": "Verify that the password is encoded in base64"
}
}
}
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "You have exceeded the limit of 10 extractions per hour",
"details": {
"limit": 10,
"window": "1 hour",
"resetAt": "2025-01-04T14:00:00Z"
}
}
}
Important notes
Passwords: Always encode passwords in base64 before sending them. Plain text passwords will be rejected.
Large periods: For date ranges greater than 3 months, consider splitting the extraction into multiple requests for better performance.
Asynchronous status: Once the extraction is created, use the Check status endpoint to monitor progress.
⌘I