curl --request POST \
--url https://api.tupana.ai/v2/folio-requests/ \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"master_entity_id": "ment_4829301923847",
"dte_type": 33,
"quantity": 50,
"sii_environment": "certification"
}
'import requests
url = "https://api.tupana.ai/v2/folio-requests/"
payload = {
"master_entity_id": "ment_4829301923847",
"dte_type": 33,
"quantity": 50,
"sii_environment": "certification"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
master_entity_id: 'ment_4829301923847',
dte_type: 33,
quantity: 50,
sii_environment: 'certification'
})
};
fetch('https://api.tupana.ai/v2/folio-requests/', 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.tupana.ai/v2/folio-requests/",
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([
'master_entity_id' => 'ment_4829301923847',
'dte_type' => 33,
'quantity' => 50,
'sii_environment' => 'certification'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.tupana.ai/v2/folio-requests/"
payload := strings.NewReader("{\n \"master_entity_id\": \"ment_4829301923847\",\n \"dte_type\": 33,\n \"quantity\": 50,\n \"sii_environment\": \"certification\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "<api-key>")
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.tupana.ai/v2/folio-requests/")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"master_entity_id\": \"ment_4829301923847\",\n \"dte_type\": 33,\n \"quantity\": 50,\n \"sii_environment\": \"certification\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tupana.ai/v2/folio-requests/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"master_entity_id\": \"ment_4829301923847\",\n \"dte_type\": 33,\n \"quantity\": 50,\n \"sii_environment\": \"certification\"\n}"
response = http.request(request)
puts response.read_body{
"id": "fir_8d4a2f7c1e9b5",
"dte_type": 33,
"status": "completed",
"requested_quantity": 50,
"granted_quantity": 50,
"partially_granted": true,
"sii_max_per_request": 9,
"folio_start": 539,
"folio_end": 588,
"caf_xml": "<AUTORIZACION><CAF version=\"1.0\">…</CAF></AUTORIZACION>",
"idempotency_key": "pedido-facturas-2026-08-27-01",
"error": "",
"created_at": "2026-08-27T14:30:00Z",
"completed_at": "2026-08-27T14:32:11Z",
"sii_environment": "production",
"error_code": ""
}{
"id": "fir_8d4a2f7c1e9b5",
"dte_type": 33,
"status": "pending",
"requested_quantity": 50,
"granted_quantity": null,
"folio_start": null,
"folio_end": null,
"caf_xml": null,
"idempotency_key": "pedido-facturas-2026-08-27-01",
"error": "",
"created_at": "2026-08-27T14:30:00Z",
"completed_at": null,
"sii_environment": "production",
"error_code": ""
}{
"error": "La cabecera Idempotency-Key es obligatoria: sin ella un reintento timbraría folios de nuevo."
}{
"detail": "No tienes acceso a esta entidad."
}{
"error": "La clave de idempotencia 'pedido-01' ya se usó en production y ahora se pide en certification. Usa una clave distinta por ambiente.",
"error_code": "idempotency_environment_conflict"
}{
"error": "Ambiente 'staging' desconocido. Valores válidos: certification, production.",
"error_code": "invalid_environment"
}{
"error": "Cuota de timbrajes agotada: 3 de 3 por hora.",
"limit": 3,
"window": "hora",
"used": 3,
"resets_at": "2023-11-07T05:31:56Z"
}Solicitar timbraje de folios
Pide folios al SII para tu empresa y te devuelve el CAF en XML para que emitas con tu propio facturador.
Es un recurso asíncrono: el trámite ante el SII son cuatro pasos y puede tardar minutos, así que la API registra el pedido, responde 201 con status: "pending" y el timbraje corre en segundo plano. Consulta el pedido con GET /folio-requests/{id} o suscríbete al webhook folio_request.completed.
La cabecera Idempotency-Key es obligatoria. Un folio timbrado no se puede devolver: si repites la llamada con la misma clave te devolvemos el pedido original (200) en vez de timbrar de nuevo. Usa una clave distinta por cada pedido real.
Requisitos: tu empresa debe tener cargado en Tupana un certificado digital vigente, y la persona del certificado debe estar autorizada ante el SII para timbrar por la empresa.
curl --request POST \
--url https://api.tupana.ai/v2/folio-requests/ \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"master_entity_id": "ment_4829301923847",
"dte_type": 33,
"quantity": 50,
"sii_environment": "certification"
}
'import requests
url = "https://api.tupana.ai/v2/folio-requests/"
payload = {
"master_entity_id": "ment_4829301923847",
"dte_type": 33,
"quantity": 50,
"sii_environment": "certification"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
master_entity_id: 'ment_4829301923847',
dte_type: 33,
quantity: 50,
sii_environment: 'certification'
})
};
fetch('https://api.tupana.ai/v2/folio-requests/', 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.tupana.ai/v2/folio-requests/",
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([
'master_entity_id' => 'ment_4829301923847',
'dte_type' => 33,
'quantity' => 50,
'sii_environment' => 'certification'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.tupana.ai/v2/folio-requests/"
payload := strings.NewReader("{\n \"master_entity_id\": \"ment_4829301923847\",\n \"dte_type\": 33,\n \"quantity\": 50,\n \"sii_environment\": \"certification\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "<api-key>")
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.tupana.ai/v2/folio-requests/")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"master_entity_id\": \"ment_4829301923847\",\n \"dte_type\": 33,\n \"quantity\": 50,\n \"sii_environment\": \"certification\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tupana.ai/v2/folio-requests/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"master_entity_id\": \"ment_4829301923847\",\n \"dte_type\": 33,\n \"quantity\": 50,\n \"sii_environment\": \"certification\"\n}"
response = http.request(request)
puts response.read_body{
"id": "fir_8d4a2f7c1e9b5",
"dte_type": 33,
"status": "completed",
"requested_quantity": 50,
"granted_quantity": 50,
"partially_granted": true,
"sii_max_per_request": 9,
"folio_start": 539,
"folio_end": 588,
"caf_xml": "<AUTORIZACION><CAF version=\"1.0\">…</CAF></AUTORIZACION>",
"idempotency_key": "pedido-facturas-2026-08-27-01",
"error": "",
"created_at": "2026-08-27T14:30:00Z",
"completed_at": "2026-08-27T14:32:11Z",
"sii_environment": "production",
"error_code": ""
}{
"id": "fir_8d4a2f7c1e9b5",
"dte_type": 33,
"status": "pending",
"requested_quantity": 50,
"granted_quantity": null,
"folio_start": null,
"folio_end": null,
"caf_xml": null,
"idempotency_key": "pedido-facturas-2026-08-27-01",
"error": "",
"created_at": "2026-08-27T14:30:00Z",
"completed_at": null,
"sii_environment": "production",
"error_code": ""
}{
"error": "La cabecera Idempotency-Key es obligatoria: sin ella un reintento timbraría folios de nuevo."
}{
"detail": "No tienes acceso a esta entidad."
}{
"error": "La clave de idempotencia 'pedido-01' ya se usó en production y ahora se pide en certification. Usa una clave distinta por ambiente.",
"error_code": "idempotency_environment_conflict"
}{
"error": "Ambiente 'staging' desconocido. Valores válidos: certification, production.",
"error_code": "invalid_environment"
}{
"error": "Cuota de timbrajes agotada: 3 de 3 por hora.",
"limit": 3,
"window": "hora",
"used": 3,
"resets_at": "2023-11-07T05:31:56Z"
}Authorizations
API Key para autenticación. Debe proporcionarse en el header Authorization con el formato: 'Api-Key YOUR-API-KEY' (incluye el prefijo 'Api-Key ' seguido de tu API key)
Headers
Clave única del pedido. Repetirla devuelve el pedido original sin timbrar de nuevo.
100Body
ID de la entidad maestra. El public ID de la entidad (ment_...).
"ment_4829301923847"
Código del tipo de documento a timbrar.
33, 34, 39, 41, 43, 46, 52, 56, 61, 110, 111, 112 33
Folios a pedir. El SII acota cada solicitud con su propio máximo autorizado, que sube con el uso: es normal recibir menos de los pedidos. Consulta el tope vigente en GET /folios.
1 <= x <= 100050
Ambiente del SII contra el que se hace la operación. production (palena) entrega folios REALES, que no se devuelven; certification (maullin) entrega folios de prueba, que NO sirven para emitir. Si se omite, producción. Un valor distinto de los dos se rechaza con 422 en vez de asumir un default.
production, certification "certification"
Response
Ya existía un pedido con esa Idempotency-Key: se devuelve el original, sin timbrar de nuevo
Pedido de timbraje de folios ante el SII.
"fir_8d4a2f7c1e9b5"
Tipo de documento timbrado.
33
authorized_without_caf significa que el SII autorizó el rango y no entregó el archivo: esos folios ya salieron de tu stock.
pending, processing, completed, failed, authorized_without_caf "completed"
Folios que pediste.
50
Folios que el SII autorizó. Puede ser menor al pedido: el tope por solicitud lo pone el SII y sube con el uso.
50
true cuando el SII entregó menos folios de los que pediste. Es un desenlace normal: el tope por solicitud lo fija el SII y sube con el uso de la empresa.
true
Tope por solicitud que el SII publicó al hacer este trámite: el motivo por el que se entregó menos de lo pedido.
9
539
588
CAF entregado por el SII. Contiene la llave privada con la que se firman tus DTE: trátalo como secreto. Es null hasta que el pedido queda completed.
"<AUTORIZACION><CAF version=\"1.0\">…</CAF></AUTORIZACION>"
La clave que enviaste al crear el pedido.
"pedido-facturas-2026-08-27-01"
Motivo del SII cuando el pedido no terminó bien.
""
"2026-08-27T14:30:00Z"
"2026-08-27T14:32:11Z"
Ambiente del SII en el que se hizo la operación. Un CAF de certification NO sirve para emitir.
production, certification Vocabulario cerrado del desenlace fallido; vacío si no hubo error. Ver la página de códigos de error.
, certification_not_enabled, missing_certificate, no_folios_authorized, sii_unavailable, sii_unrecognized_page 