Base URL de Producción
https://pse.satelital.click
Introducción y Autenticación
Bienvenido a la API REST de facturación electrónica. Esta guía interactiva le permitirá integrar su software en minutos utilizando los ejemplos de código proporcionados. Toda solicitud a nuestra API debe ir acompañada de un Bearer Token en la cabecera HTTP de autorización.
Catálogo de Endpoints de la API
| Método | Ruta (Endpoint) | Descripción |
|---|---|---|
| Autenticación y Usuario | ||
| POST | /api/login | Autenticación y obtención de Token API. |
| GET | /api/user | Obtiene datos del usuario autenticado y su compañía. |
| Facturación Electrónica (v1) | ||
| POST | /api/v1/documents | Emisión de Facturas y Boletas Electrónicas a SUNAT. |
| GET | /api/v1/documents/satelital/pdf/{fileName} | Descarga la representación impresa en PDF. |
| GET | /api/v1/documents/satelital/cdr/{fileName} | Descarga la Constancia de Recepción (CDR) de SUNAT. |
| Administración de Recursos (v1/admin) | ||
| GET | /api/v1/admin/companies | Listado de todas las compañías registradas. |
| POST | /api/v1/admin/companies | Registra una nueva compañía en la plataforma. |
| GET | /api/v1/admin/companies/{company} | Ver detalles y credenciales SOL de la compañía. |
| PUT | /api/v1/admin/companies/{company} | Actualiza configuración de la compañía. |
| GET | /api/v1/admin/documents | Listar comprobantes de la plataforma/inquilino. |
| GET | /api/v1/admin/documents/{document} | Obtiene la información y estado de un comprobante. |
Estructura de la Cabecera
Emisión de Comprobantes
Cree facturas y boletas electrónicas firmadas digitalmente y enviadas a la SUNAT.
/api/v1/documents
01), las Boletas de Venta (03) no se envían individualmente a la SUNAT de forma inmediata. Al registrar una Boleta a través de la API, su estado quedará en Pendiente y se enviará de manera consolidada mediante un Resumen Diario de Boletas (RC), el cual puede ser generado y transmitido desde el panel de administración.
const token = 'TU_TOKEN_API_AQUI';
const payload = {
serie: 'F001',
numero: 12,
fecha: new Date().toISOString(),
fecha_vencimiento: '2026-06-30',
tipo_documento: '01', // 01: Factura, 03: Boleta
codigo_moneda: 'PEN', // PEN: Soles, USD: Dólares
simbolo_moneda: 'S/',
cliente: {
ruc: '20100066603',
razon_social: 'EMPRESA CLIENTE S.A.C.',
direccion_fiscal: 'AV. LOS INCAS 123',
distrito: 'LIMA',
provincia: 'LIMA',
departamento: 'LIMA'
},
forma_pago: 'Contado',
tributo: {
total: 18.00,
tipo: 'VAT',
nombre: 'IGV',
codigo: '1000'
},
total: {
valor_venta: 100.00,
precio_venta: 118.00,
descuento: 0.00,
cargo: 0.00,
anticipo: 0.00,
importe_total: 118.00
},
items: [
{
cantidad: 1.00,
codigo_unidad_medida: 'NIU',
descripcion: 'SERVICIO DE DESARROLLO',
codigo_interno: 'SRV001',
valor_venta: 100.00,
precio_venta_unitario: 118.00,
tipo_precio_venta: '01',
tributo_monto_total: 18.00,
tributo_total: 18.00,
tributo_porcentaje: 18.00,
tributo_afectacion: '10', // 10: Gravado - Operación Onerosa
tiene_isc: false,
tributo_tipo: 'VAT',
tributo_nombre: 'IGV',
tributo_codigo: '1000',
tiene_detracciones: false
}
]
};
fetch('https://pse.satelital.click/api/v1/documents', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
},
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => console.log('Éxito:', data))
.catch(error => console.error('Error:', error));
// npm install axios
const axios = require('axios');
const token = 'TU_TOKEN_API_AQUI';
const payload = {
serie: 'F001',
numero: 12,
fecha: new Date().toISOString(),
fecha_vencimiento: '2026-06-30',
tipo_documento: '01',
codigo_moneda: 'PEN',
simbolo_moneda: 'S/',
cliente: {
ruc: '20100066603',
razon_social: 'EMPRESA CLIENTE S.A.C.',
direccion_fiscal: 'AV. LOS INCAS 123',
distrito: 'LIMA',
provincia: 'LIMA',
departamento: 'LIMA'
},
forma_pago: 'Contado',
tributo: {
total: 18.00,
tipo: 'VAT',
nombre: 'IGV',
codigo: '1000'
},
total: {
valor_venta: 100.00,
precio_venta: 118.00,
descuento: 0.00,
cargo: 0.00,
anticipo: 0.00,
importe_total: 118.00
},
items: [
{
cantidad: 1.00,
codigo_unidad_medida: 'NIU',
descripcion: 'SERVICIO DE DESARROLLO',
codigo_interno: 'SRV001',
valor_venta: 100.00,
precio_venta_unitario: 118.00,
tipo_precio_venta: '01',
tributo_monto_total: 18.00,
tributo_total: 18.00,
tributo_porcentaje: 18.00,
tributo_afectacion: '10',
tiene_isc: false,
tributo_tipo: 'VAT',
tributo_nombre: 'IGV',
tributo_codigo: '1000',
tiene_detracciones: false
}
]
};
axios.post('https://pse.satelital.click/api/v1/documents', payload, {
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(response => console.log('Éxito:', response.data))
.catch(error => console.error('Error:', error.response ? error.response.data : error.message));
use Illuminate\Support\Facades\Http;
$token = 'TU_TOKEN_API_AQUI';
$response = Http::withHeaders([
'Accept' => 'application/json',
])->withToken($token)
->post('https://pse.satelital.click/api/v1/documents', [
'serie' => 'F001',
'numero' => 12,
'fecha' => now()->toIso8601String(),
'fecha_vencimiento' => '2026-06-30',
'tipo_documento' => '01',
'codigo_moneda' => 'PEN',
'simbolo_moneda' => 'S/',
'cliente' => [
'ruc' => '20100066603',
'razon_social' => 'EMPRESA CLIENTE S.A.C.',
'direccion_fiscal' => 'AV. LOS INCAS 123',
'distrito' => 'LIMA',
'provincia' => 'LIMA',
'departamento' => 'LIMA'
],
'forma_pago' => 'Contado',
'tributo' => [
'total' => 18.00,
'tipo' => 'VAT',
'nombre' => 'IGV',
'codigo' => '1000'
],
'total' => [
'valor_venta' => 100.00,
'precio_venta' => 118.00,
'descuento' => 0.00,
'cargo' => 0.00,
'anticipo' => 0.00,
'importe_total' => 118.00
],
'items' => [
[
'cantidad' => 1.00,
'codigo_unidad_medida' => 'NIU',
'descripcion' => 'SERVICIO DE DESARROLLO',
'codigo_interno' => 'SRV001',
'valor_venta' => 100.00,
'precio_venta_unitario' => 118.00,
'tipo_precio_venta' => '01',
'tributo_monto_total' => 18.00,
'tributo_total' => 18.00,
'tributo_porcentaje' => 18.00,
'tributo_afectacion' => '10',
'tiene_isc' => false,
'tributo_tipo' => 'VAT',
'tributo_nombre' => 'IGV',
'tributo_codigo' => '1000',
'tiene_detracciones' => false
]
]
]);
if ($response->successful()) {
$data = $response->json();
// Guardar: $data['external_id'], $data['pdf_url'], $data['hash']
} else {
$errors = $response->json();
}
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class FacturacionService {
private apiUrl = 'https://pse.satelital.click/api/v1/documents';
private token = 'TU_TOKEN_API_AQUI';
constructor(private http: HttpClient) {}
emitirDocumento(payload: any): Observable {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${this.token}`
});
return this.http.post(this.apiUrl, payload, { headers });
}
}
import requests
import datetime
url = "https://pse.satelital.click/api/v1/documents"
token = "TU_TOKEN_API_AQUI"
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": f"Bearer {token}"
}
payload = {
"serie": "F001",
"numero": 12,
"fecha": datetime.datetime.now().isoformat(),
"fecha_vencimiento": "2026-06-30",
"tipo_documento": "01",
"codigo_moneda": "PEN",
"simbolo_moneda": "S/",
"cliente": {
"ruc": "20100066603",
"razon_social": "EMPRESA CLIENTE S.A.C.",
"direccion_fiscal": "AV. LOS INCAS 123",
"distrito": "LIMA",
"provincia": "LIMA",
"departamento": "LIMA"
},
"forma_pago": "Contado",
"tributo": {
"total": 18.00,
"tipo": "VAT",
"nombre": "IGV",
"codigo": "1000"
},
"total": {
"valor_venta": 100.00,
"precio_venta": 118.00,
"descuento": 0.00,
"cargo": 0.00,
"anticipo": 0.00,
"importe_total": 118.00
},
"items": [
{
"cantidad": 1.00,
"codigo_unidad_medida": "NIU",
"descripcion": "SERVICIO DE DESARROLLO",
"codigo_interno": "SRV001",
"valor_venta": 100.00,
"precio_venta_unitario": 118.00,
"tipo_precio_venta": "01",
"tributo_monto_total": 18.00,
"tributo_total": 18.00,
"tributo_porcentaje": 18.00,
"tributo_afectacion": "10",
"tiene_isc": False,
"tributo_tipo": "VAT",
"tributo_nombre": "IGV",
"tributo_codigo": "1000",
"tiene_detracciones": False
}
]
}
response = requests.post(url, json=payload, headers=headers)
if response.status_code == 200:
print("Respuesta:", response.json())
else:
print("Error:", response.status_code, response.text)
| Campo | Tipo | Obligatorio | Descripción / Catálogo |
|---|---|---|---|
| serie | string | Sí | Serie del documento. Ej: F001 (Facturas), B001 (Boletas). |
| numero | integer | Sí | Número correlativo de emisión. Debe ser mayor a 0. |
| fecha | string (ISO 8601) | Sí | Fecha y hora de emisión del documento. Ej: 2026-06-14T14:30:00-05:00. |
| tipo_documento | string | Sí | SUNAT Tipo Doc. (01: Factura, 03: Boleta, 07: Nota de Crédito). |
| cliente | object | Sí | Objeto con datos del adquiriente. Ver sub-campos detallados a continuación. |
| ↳ ruc | string | Condicional | Número de RUC, DNI, Pasaporte o vacío. Obligatorio en Facturas (01). |
| ↳ tipo_documento | string | Opcional | Tipo de doc. según Catálogo 06 (DNI: 1, RUC: 6, Pasaporte: 7, Sin Doc: 0). Se auto-detecta según el tamaño si no se provee. |
| ↳ razon_social | string | Sí | Nombre completo, Razón Social o "Clientes Varios" (para boletas sin documento). |
| ↳ direccion_fiscal | string | Condicional | Dirección del cliente. Opcional para Boletas (03), recomendado para Facturas (01). |
| ↳ distrito, provincia, departamento | string | Condicional | Ubigeo geográfico del cliente. Opcional para Boletas (03), recomendado para Facturas (01). |
| items | array | Sí | Listado de productos o servicios facturados. Requiere cantidad, descripcion, afectacion, total. |
Respuestas del Servidor
{
"success": true,
"external_id": "c3580456-6218-472e-...",
"hash": "abc123xyz...",
"pdf_url": "https://pse.satelital.click/pdf/20100066603-01-F001-12.pdf",
"message": "Document processed and queued for SUNAT submission."
}
{
"success": true,
"external_id": "b7891234-5678-90ab-...",
"hash": "xyz789abc...",
"pdf_url": "https://pse.satelital.click/pdf/20100066603-03-B001-32.pdf",
"message": "Boleta registered and pending daily summary submission."
}
{
"message": "The given data was invalid.",
"errors": {
"serie": ["The serie field is required."],
"cliente.ruc": ["The client's RUC is invalid."]
}
}
Descarga del Archivo PDF
Obtenga la representación impresa en PDF del comprobante electrónico emitido.
/api/v1/documents/satelital/pdf/{fileName}
El parámetro {fileName} debe tener el formato estandarizado de SUNAT: {RUC}-{TIPO_DOCUMENTO}-{SERIE}-{NUMERO} (sin la extensión .pdf).
const token = 'TU_TOKEN_API_AQUI';
const fileName = '20100066603-01-F001-12'; // Formato: RUC-TIPO-SERIE-NUMERO
fetch(`https://pse.satelital.click/api/v1/documents/satelital/pdf/${fileName}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => {
if (!response.ok) throw new Error('Error al descargar PDF');
return response.blob();
})
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${fileName}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
})
.catch(error => console.error('Error de descarga:', error));
const axios = require('axios');
const token = 'TU_TOKEN_API_AQUI';
const fileName = '20100066603-01-F001-12';
axios.get(`https://pse.satelital.click/api/v1/documents/satelital/pdf/${fileName}`, {
headers: {
'Authorization': `Bearer ${token}`
},
responseType: 'blob'
})
.then(response => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `${fileName}.pdf`);
document.body.appendChild(link);
link.click();
link.remove();
})
.catch(error => console.error('Error al descargar PDF:', error));
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
$token = 'TU_TOKEN_API_AQUI';
$fileName = '20100066603-01-F001-12';
$response = Http::withToken($token)
->get("https://pse.satelital.click/api/v1/documents/satelital/pdf/{$fileName}");
if ($response->successful()) {
// Guarda el archivo PDF en su disco local
Storage::disk('local')->put("comprobantes/{$fileName}.pdf", $response->body());
echo "PDF Guardado Correctamente.";
} else {
echo "Error: " . $response->status();
}
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class PDFService {
private apiUrl = 'https://pse.satelital.click/api/v1/documents/satelital/pdf';
private token = 'TU_TOKEN_API_AQUI';
constructor(private http: HttpClient) {}
descargarPdf(fileName: string) {
const headers = new HttpHeaders({
'Authorization': `Bearer ${this.token}`
});
this.http.get(`${this.apiUrl}/${fileName}`, {
headers,
responseType: 'blob'
}).subscribe((blob: Blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${fileName}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
});
}
}
import requests
token = "TU_TOKEN_API_AQUI"
file_name = "20100066603-01-F001-12"
url = f"https://pse.satelital.click/api/v1/documents/satelital/pdf/{file_name}"
headers = {
"Authorization": f"Bearer {token}"
}
response = requests.get(url, headers=headers, stream=True)
if response.status_code == 200:
with open(f"{file_name}.pdf", "wb") as f:
f.write(response.content)
print("PDF descargado y guardado correctamente.")
else:
print(f"Error {response.status_code}: {response.text}")
Descarga del Archivo CDR (SUNAT)
Obtenga la Constancia de Recepción (CDR) devuelta por SUNAT en formato ZIP.
/api/v1/documents/satelital/cdr/{fileName}
Permite obtener el estado de aceptación de SUNAT. El parámetro {fileName} debe tener el formato: {RUC}-{TIPO_DOCUMENTO}-{SERIE}-{NUMERO} (el sistema retornará un ZIP con prefijo R-).
const token = 'TU_TOKEN_API_AQUI';
const fileName = '20100066603-01-F001-12';
fetch(`https://pse.satelital.click/api/v1/documents/satelital/cdr/${fileName}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => {
if (!response.ok) throw new Error('CDR no encontrado o aún procesando en SUNAT');
return response.blob();
})
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `R-${fileName}.zip`;
document.body.appendChild(a);
a.click();
a.remove();
})
.catch(error => console.error('Error:', error));
const axios = require('axios');
const token = 'TU_TOKEN_API_AQUI';
const fileName = '20100066603-01-F001-12';
axios.get(`https://pse.satelital.click/api/v1/documents/satelital/cdr/${fileName}`, {
headers: {
'Authorization': `Bearer ${token}`
},
responseType: 'blob'
})
.then(response => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `R-${fileName}.zip`);
document.body.appendChild(link);
link.click();
link.remove();
})
.catch(error => console.error('Error al descargar CDR:', error));
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
$token = 'TU_TOKEN_API_AQUI';
$fileName = '20100066603-01-F001-12';
$response = Http::withToken($token)
->get("https://pse.satelital.click/api/v1/documents/satelital/cdr/{$fileName}");
if ($response->successful()) {
Storage::disk('local')->put("comprobantes/R-{$fileName}.zip", $response->body());
echo "CDR ZIP guardado exitosamente.";
} else {
echo "Error o procesando: " . $response->status();
}
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class CDRService {
private apiUrl = 'https://pse.satelital.click/api/v1/documents/satelital/cdr';
private token = 'TU_TOKEN_API_AQUI';
constructor(private http: HttpClient) {}
descargarCdr(fileName: string) {
const headers = new HttpHeaders({
'Authorization': `Bearer ${this.token}`
});
this.http.get(`${this.apiUrl}/${fileName}`, {
headers,
responseType: 'blob'
}).subscribe((blob: Blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `R-${fileName}.zip`;
document.body.appendChild(a);
a.click();
a.remove();
});
}
}
import requests
token = "TU_TOKEN_API_AQUI"
file_name = "20100066603-01-F001-12"
url = f"https://pse.satelital.click/api/v1/documents/satelital/cdr/{file_name}"
headers = {
"Authorization": f"Bearer {token}"
}
response = requests.get(url, headers=headers, stream=True)
if response.status_code == 200:
with open(f"R-{file_name}.zip", "wb") as f:
f.write(response.content)
print("CDR descargado y guardado correctamente.")
else:
print(f"Error {response.status_code}: {response.text}")
Listado de Comprobantes
Obtenga una lista paginada de todos los comprobantes emitidos en el sistema.
/api/v1/admin/documents
Parámetros Query permitidos
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| page | integer | No (Default: 1) | Número de página para la paginación de resultados. |
| company_id | integer | No | Filtra los comprobantes por ID de empresa específica. |
const token = 'TU_TOKEN_API_AQUI';
// Obtiene la primera página de comprobantes
fetch('https://pse.satelital.click/api/v1/admin/documents?page=1', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${token}`
}
})
.then(response => response.json())
.then(data => {
console.log('Total de registros:', data.total);
console.log('Listado:', data.data);
})
.catch(error => console.error(error));
// npm install axios
const axios = require('axios');
const token = 'TU_TOKEN_API_AQUI';
axios.get('https://pse.satelital.click/api/v1/admin/documents', {
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
},
params: {
page: 1,
company_id: 1
}
})
.then(response => {
console.log('Total de registros:', response.data.total);
console.log('Listado:', response.data.data);
})
.catch(error => console.error('Error al listar comprobantes:', error));
use Illuminate\Support\Facades\Http;
$token = 'TU_TOKEN_API_AQUI';
$response = Http::withHeaders([
'Accept' => 'application/json',
])->withToken($token)
->get('https://pse.satelital.click/api/v1/admin/documents', [
'page' => 1,
'company_id' => 1
]);
if ($response->successful()) {
$pagination = $response->json();
$documents = $pagination['data'];
$total = $pagination['total'];
}
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class DocumentosService {
private apiUrl = 'https://pse.satelital.click/api/v1/admin/documents';
private token = 'TU_TOKEN_API_AQUI';
constructor(private http: HttpClient) {}
obtenerComprobantes(page: number = 1, companyId?: number) {
const headers = new HttpHeaders({
'Accept': 'application/json',
'Authorization': `Bearer ${this.token}`
});
let params = new HttpParams().set('page', page.toString());
if (companyId) {
params = params.set('company_id', companyId.toString());
}
return this.http.get(this.apiUrl, { headers, params });
}
}
import requests
url = "https://pse.satelital.click/api/v1/admin/documents"
token = "TU_TOKEN_API_AQUI"
headers = {
"Accept": "application/json",
"Authorization": f"Bearer {token}"
}
params = {
"page": 1,
"company_id": 1
}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
data = response.json()
print(f"Total registros: {data.get('total')}")
print("Registros:", data.get('data'))
else:
print(f"Error {response.status_code}: {response.text}")