curl --request POST \
--url https://api.tupana.ai/v1/credentials \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"user_rut": "12345678-9",
"password": "mi_password_segura",
"digital_certificate_password": "mi_password_certificado",
"master_entity_id": 123
}
'import requests
url = "https://api.tupana.ai/v1/credentials"
payload = {
"user_rut": "12345678-9",
"password": "mi_password_segura",
"digital_certificate_password": "mi_password_certificado",
"master_entity_id": 123
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
user_rut: '12345678-9',
password: 'mi_password_segura',
digital_certificate_password: 'mi_password_certificado',
master_entity_id: 123
})
};
fetch('https://api.tupana.ai/v1/credentials', 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/v1/credentials",
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([
'user_rut' => '12345678-9',
'password' => 'mi_password_segura',
'digital_certificate_password' => 'mi_password_certificado',
'master_entity_id' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"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.tupana.ai/v1/credentials"
payload := strings.NewReader("{\n \"user_rut\": \"12345678-9\",\n \"password\": \"mi_password_segura\",\n \"digital_certificate_password\": \"mi_password_certificado\",\n \"master_entity_id\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
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/v1/credentials")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"user_rut\": \"12345678-9\",\n \"password\": \"mi_password_segura\",\n \"digital_certificate_password\": \"mi_password_certificado\",\n \"master_entity_id\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tupana.ai/v1/credentials")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"user_rut\": \"12345678-9\",\n \"password\": \"mi_password_segura\",\n \"digital_certificate_password\": \"mi_password_certificado\",\n \"master_entity_id\": 123\n}"
response = http.request(request)
puts response.read_body{
"id": 1,
"user": "12345678-9",
"master_entity": {
"id": 123,
"name": "Empresa Ejemplo SpA",
"tax_id": "76543210-1"
},
"credential_type": {
"id": 70,
"name": "SII"
},
"status": "VALID",
"created_at": "2024-01-01T10:00:00Z"
}{
"enrollment_id": "cenr_3940730445066399260",
"status": "pending",
"user_rut": "12345678-9",
"error": null,
"credential": null,
"ws_channel": "cred-validation-129816",
"created_at": "2026-09-17T11:20:20.429990-03:00",
"finished_at": null,
"message": "Validando la credencial con el SII…"
}{
"error": "VALIDATION_ERROR",
"message": "<string>"
}{
"error": "VALIDATION_ERROR",
"message": "<string>"
}{
"error": "VALIDATION_ERROR",
"message": "<string>"
}{
"error": "VALIDATION_ERROR",
"message": "<string>"
}{
"error": "VALIDATION_ERROR",
"message": "<string>"
}Crear Credencial
Enrola una credencial. El login contra el SII no ocurre en el request: la API responde 202 con el enrolamiento en curso y su estado se consulta en GET /credentials/enrollments/. El flujo de certificado digital (.pfx), que no necesita login, sigue respondiendo 201 con la credencial.
curl --request POST \
--url https://api.tupana.ai/v1/credentials \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"user_rut": "12345678-9",
"password": "mi_password_segura",
"digital_certificate_password": "mi_password_certificado",
"master_entity_id": 123
}
'import requests
url = "https://api.tupana.ai/v1/credentials"
payload = {
"user_rut": "12345678-9",
"password": "mi_password_segura",
"digital_certificate_password": "mi_password_certificado",
"master_entity_id": 123
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
user_rut: '12345678-9',
password: 'mi_password_segura',
digital_certificate_password: 'mi_password_certificado',
master_entity_id: 123
})
};
fetch('https://api.tupana.ai/v1/credentials', 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/v1/credentials",
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([
'user_rut' => '12345678-9',
'password' => 'mi_password_segura',
'digital_certificate_password' => 'mi_password_certificado',
'master_entity_id' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"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.tupana.ai/v1/credentials"
payload := strings.NewReader("{\n \"user_rut\": \"12345678-9\",\n \"password\": \"mi_password_segura\",\n \"digital_certificate_password\": \"mi_password_certificado\",\n \"master_entity_id\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
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/v1/credentials")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"user_rut\": \"12345678-9\",\n \"password\": \"mi_password_segura\",\n \"digital_certificate_password\": \"mi_password_certificado\",\n \"master_entity_id\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tupana.ai/v1/credentials")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"user_rut\": \"12345678-9\",\n \"password\": \"mi_password_segura\",\n \"digital_certificate_password\": \"mi_password_certificado\",\n \"master_entity_id\": 123\n}"
response = http.request(request)
puts response.read_body{
"id": 1,
"user": "12345678-9",
"master_entity": {
"id": 123,
"name": "Empresa Ejemplo SpA",
"tax_id": "76543210-1"
},
"credential_type": {
"id": 70,
"name": "SII"
},
"status": "VALID",
"created_at": "2024-01-01T10:00:00Z"
}{
"enrollment_id": "cenr_3940730445066399260",
"status": "pending",
"user_rut": "12345678-9",
"error": null,
"credential": null,
"ws_channel": "cred-validation-129816",
"created_at": "2026-09-17T11:20:20.429990-03:00",
"finished_at": null,
"message": "Validando la credencial con el SII…"
}{
"error": "VALIDATION_ERROR",
"message": "<string>"
}{
"error": "VALIDATION_ERROR",
"message": "<string>"
}{
"error": "VALIDATION_ERROR",
"message": "<string>"
}{
"error": "VALIDATION_ERROR",
"message": "<string>"
}{
"error": "VALIDATION_ERROR",
"message": "<string>"
}Que hace
- Inicia el enrolamiento de una credencial para autenticacion en el SII
- Valida la clave contra el SII y, si es correcta, crea la credencial y la asocia a la entidad maestra
- Deja andando la carga inicial de la empresa (documentos, libros y boletas de honorarios)
La respuesta es 202, no 201
El login contra el SII se hace con un navegador real y demora del orden de 15 segundos, asi que no ocurre dentro del request. Este endpoint responde202 Accepted con un enrolamiento en curso:
{
"enrollment_id": "cenr_3940730445066399260",
"status": "pending",
"user_rut": "12345678-9",
"credential": null,
"message": "Validando la credencial con el SII…"
}
Location trae la URL del estado. Para saber si la credencial
quedo enrolada hay que consultar
el estado del enrolamiento
hasta que status deje de ser pending:
curl https://api.tupana.ai/v1/credentials/enrollments/cenr_3940730445066399260/ \
-H "Authorization: Api-Key TU_API_KEY"
enrollment_id en vez
de gastar otro login contra el SII (el SII limita los logins por RUT)..pfx) no necesita login y sigue
respondiendo 201 con la credencial, como antes.Ejemplos de uso
- Configurar credenciales del SII para una nueva empresa
- Agregar credenciales adicionales para una entidad existente
- Reemplazar credenciales expiradas o invalidas
- Configurar multiples credenciales para diferentes entidades
Obtener el master_entity_id
Elmaster_entity_id es el ID unico de la empresa en Tupana que se esta asociando con estas credenciales. Para obtener este ID, debes usar el endpoint /master-entities:
- Buscar la entidad por RUT usando
GET /master-entities?rut=76543210-1 - Obtener el ID de la respuesta (campo
id) - Usar ese ID como
master_entity_iden la creacion de credenciales
Tipos de Credenciales
Puedes usarcredential_type (string) o credential_type_id (numerico) para indicar el tipo de credencial. Consulta la referencia completa de tipos de credenciales para mas detalles.
Tipo (credential_type) | ID (credential_type_id) | Descripcion |
|---|---|---|
sii | 70 | Servicio de Impuestos Internos (clave tributaria) |
sii_company | 73 | SII a nivel de empresa (clave de empresa) |
certificate | 75 | Certificado digital (.pfx) |
bank_chile | 84 | Banco de Chile |
bank_estado | 85 | BancoEstado |
bank_santander | 86 | Santander |
bank_scotiabank | 87 | Scotiabank |
Certificado digital (.pfx) por archivo
Si necesitas subir un certificado digital, el archivo.pfx se envia en el payload JSON como string base64.
- Convierte primero el archivo
.pfxa base64 - Envia ese valor en el campo
digital_certificate_base64 - Envia
digital_certificate_passwordsi corresponde - Envia
credential_type: "certificate"para guardarlo como credencial de certificado digital
Ejemplo de payload
{
"master_entity_id": 123,
"credential_type": "certificate",
"digital_certificate_password": "clave-del-pfx",
"digital_certificate_base64": "MIIK..."
}
Importante
- El
.pfxse envia como string base64 endigital_certificate_base64 - En este flujo no se envian
user_rutnipassword - El backend guarda la credencial como tipo certificado digital
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)
Body
RUT del usuario (sin puntos y con guión)
^[0-9]+-[0-9kK]$"12345678-9"
Contraseña del usuario en el SII
"mi_password_segura"
Contraseña del certificado digital
"mi_password_certificado"
ID de la entidad maestra a la que pertenece la credencial
123
ID del tipo de credencial (opcional, por defecto SII)
70
Response
Credencial de certificado digital creada (solo el flujo con digital_certificate_base64, que no requiere login en el SII)
ID único de la credencial creada
1
RUT del usuario de la credencial
"12345678-9"
Información de la entidad maestra asociada
Show child attributes
Show child attributes
Tipo de credencial
Show child attributes
Show child attributes
Estado de la credencial
VALID, INVALID, EXPIRED "VALID"
Fecha de creación de la credencial
"2024-01-01T10:00:00Z"
