SatelitalPSE Docs

Documentación de la API

API v1.0 Activa

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

Authorization: Bearer TU_TOKEN_API_PROPORCIONADO
Accept: application/json
Puede generar y revocar tokens API directamente desde la pantalla de Inicio (Dashboard).

Emisión de Comprobantes

Cree facturas y boletas electrónicas firmadas digitalmente y enviadas a la SUNAT.

POST /api/v1/documents
Importante: Envío de Boletas de Venta (Tipo 03) A diferencia de las Facturas (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.
Ejemplo interactivo en: Use la barra lateral para cambiar de lenguaje
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

Éxito Factura / Nota (200 OK)
{
  "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."
}
Éxito Boleta (200 OK)
{
  "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."
}
Error de Validación (422)
{
  "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.

GET /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.

GET /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.

GET /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}")