# Quickstart

> Crea tu API key de sandbox en app.simplo.cl y emite tu primer DTE (factura o boleta electrónica chilena) en minutos, sin certificado ni CAF — contra la misma API REST que producción, con curl, C#, Java, Python o el SDK TypeScript.

Emite tu primer DTE (Documento Tributario Electrónico — una factura o boleta
electrónica chilena) en el **sandbox de tu propia empresa**: el mismo modelo
de Stripe, donde el ambiente de prueba no es otra cuenta sino un **modo** de
la tuya, seleccionado por la API key (`sk_simplo_sandbox_…` vs
`sk_simplo_…`). Certificado y folios (CAF) sintéticos se aprovisionan solos —
sin comprar un certificado digital, sin tramitar folios en el SII, sin
hablar con ventas. Simplo es una **API REST**: cualquier lenguaje que hable
HTTP + JSON sirve. Aquí el mismo flujo en curl, C#, Java, Python y el SDK
TypeScript.

Los montos y el cálculo tributario (IVA) del sandbox **no son ficticios** —
es el mismo motor que produce facturas reales. Lo único simulado es el SII:
el documento nunca llega al SII de verdad ni tiene validez tributaria.
Cuando estés listo para emitir documentos reales, ver
[Pasar a producción](/comienza/pasar-a-produccion/).

## 1. Crea tu key de sandbox

Con tu cuenta de Simplo creada (y tu empresa con su RUT y razón social
reales), entra a **app.simplo.cl → Desarrolladores** y crea una **API key de
sandbox**. Eso es todo el trámite: cualquier plan con Facturación incluye el
sandbox, self-serve.

La key se muestra **una sola vez** — guárdala ahora:

```bash
export SIMPLO_API_KEY="sk_simplo_sandbox_3f9a...e1"
```

¿Prefieres API? El mismo mint existe como endpoint (con tu sesión JWT, rol
dueño o administrador — ver [Autenticación](/comienza/autenticacion/)):

```bash
curl -sS -X POST https://api.simplo.cl/api/v1/api-keys \
  -H "Authorization: Bearer $SIMPLO_JWT" \
  -H "Content-Type: application/json" \
  -d '{"name": "mi integración", "environment": "sandbox", "scopes": ["billing:dte"]}'
```

```json
// 201 Created
{
  "id": "a1b2c3d4-...",
  "name": "mi integración",
  "prefix": "sk_simpl",
  "is_sandbox": true,
  "key": "sk_simplo_sandbox_3f9a...e1"
}
```

Si tu empresa aún no tiene RUT o razón social, el mint responde `422`
(`COMPANY_RUT_REQUIRED_FOR_SANDBOX` /
`COMPANY_RAZON_SOCIAL_REQUIRED_FOR_SANDBOX`) — completa la identidad de tu
empresa en la app y reintenta. No hay paso de certificado ni de CAF: al
crear la key, el sandbox de tu empresa queda aprovisionado con certificado y
folios sintéticos, listos para emitir.

## 2. Emite una factura

Exactamente el mismo endpoint que producción — `POST /api/v1/billing/dte`,
con header `Idempotency-Key` (UUID) para que un reintento nunca duplique la
factura. **Ni una línea del ejemplo cambia** entre sandbox y producción; lo
único distinto es qué API key usas.

#### curl

```bash
curl -X POST https://api.simplo.cl/api/v1/billing/dte \
  -H "X-Api-Key: $SIMPLO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "tipo_dte": 33,
    "receptor": {
      "rut": "76543210-3",
      "razon_social": "Cliente Ejemplo SpA",
      "giro": "Servicios de software",
      "direccion": "Av. Providencia 1234",
      "comuna": "Providencia"
    },
    "detalle": [
      { "nombre": "Servicios de consultoría", "cantidad": 10, "precio": 50000 }
    ]
  }'
```

```json
// 201 Created
{
  "id": "4f9c9c2e-8a49-4f2e-9d5f-0d8f3a1b2c3d",
  "folio": 1042,
  "tipo_dte": 33,
  "estado": "firmado",
  "monto_total": 595000,
  "created_at": "2026-08-01T14:30:00Z"
}
```

#### C#

```csharp
using System.Net.Http.Json;
using System.Text.Json;

var http = new HttpClient { BaseAddress = new Uri("https://api.simplo.cl") };
http.DefaultRequestHeaders.Add("X-Api-Key",
    Environment.GetEnvironmentVariable("SIMPLO_API_KEY"));

var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1/billing/dte")
{
    Content = JsonContent.Create(new
    {
        tipo_dte = 33, // Factura Electrónica
        receptor = new
        {
            rut = "76543210-3",
            razon_social = "Cliente Ejemplo SpA",
            giro = "Servicios de software",
            direccion = "Av. Providencia 1234",
            comuna = "Providencia",
        },
        detalle = new[]
        {
            new { nombre = "Servicios de consultoría", cantidad = 10, precio = 50000 },
        },
    })
};
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());

var response = await http.SendAsync(request);
response.EnsureSuccessStatusCode(); // 201

var dte = await response.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"folio {dte.GetProperty("folio")} — {dte.GetProperty("estado")}");
// folio 1042 — firmado
```

#### Java

```java
import java.net.URI;
import java.net.http.*;
import java.util.UUID;

var body = """
    {
      "tipo_dte": 33,
      "receptor": {
        "rut": "76543210-3",
        "razon_social": "Cliente Ejemplo SpA",
        "giro": "Servicios de software",
        "direccion": "Av. Providencia 1234",
        "comuna": "Providencia"
      },
      "detalle": [
        { "nombre": "Servicios de consultoría", "cantidad": 10, "precio": 50000 }
      ]
    }""";

HttpClient http = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.simplo.cl/api/v1/billing/dte"))
    .header("X-Api-Key", System.getenv("SIMPLO_API_KEY"))
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response =
    http.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 201
System.out.println(response.body());
// {"id":"4f9c…","folio":1042,"estado":"firmado",…}
```

#### Python

```python
import http.client, json, os, uuid

conn = http.client.HTTPSConnection("api.simplo.cl")
conn.request(
    "POST",
    "/api/v1/billing/dte",
    body=json.dumps({
        "tipo_dte": 33,  # Factura Electrónica
        "receptor": {
            "rut": "76543210-3",
            "razon_social": "Cliente Ejemplo SpA",
            "giro": "Servicios de software",
            "direccion": "Av. Providencia 1234",
            "comuna": "Providencia",
        },
        "detalle": [
            {"nombre": "Servicios de consultoría", "cantidad": 10, "precio": 50000}
        ],
    }),
    headers={
        "X-Api-Key": os.environ["SIMPLO_API_KEY"],
        "Content-Type": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
)

dte = json.loads(conn.getresponse().read())
print(dte["folio"], dte["estado"])  # 1042 firmado
```

#### SDK TypeScript (no publicado)

> **Aún no publicado:**
> `@simplohq/sdk` todavía no está publicado en npm; **no ejecutes
> `npm install @simplohq/sdk` todavía**. Usa la pestaña **curl** (o el cliente
> HTTP de tu lenguaje) para integrar hoy. Detalles: [SDK TypeScript](/agentes/sdk/).

Vista previa de cómo se verá una vez publicado:

```ts
import Simplo from '@simplohq/sdk';

const simplo = new Simplo(); // lee SIMPLO_API_KEY

const dte = await simplo.dtes.emit({
  tipo_dte: 33, // Factura Electrónica
  receptor: {
    rut: '76543210-3',
    razon_social: 'Cliente Ejemplo SpA',
    giro: 'Servicios de software',
    direccion: 'Av. Providencia 1234',
    comuna: 'Providencia',
  },
  detalle: [{ nombre: 'Servicios de consultoría', cantidad: 10, precio: 50000 }],
});

console.log(dte.folio, dte.estado); // 1042 "firmado"
```

El SDK generará la `Idempotency-Key` y reintentará con backoff por ti — ver
[SDK TypeScript](/agentes/sdk/).

La respuesta `201` retorna en cuanto el documento queda firmado
(`estado: "firmado"`): folio asignado desde el CAF activo, XML generado,
timbre electrónico (TED) y firma digital listos. El envío al SII (o, en
sandbox, al simulador del SII) ocurre de forma **asíncrona**.

Los montos son pesos chilenos (CLP) enteros. El IVA (19%) lo calcula la
API — tú envías precios netos.

## 3. Mira los estados

Por polling sobre `GET /api/v1/billing/dte/{id}`. En sandbox, el ciclo
completo ocurre delante de ti en cuestión de segundos —
`firmado → enviando → procesando → aceptado` — para que veas de verdad que
el SII (real o simulado) es **asíncrono**, no una llamada síncrona más:

#### curl

```bash
curl https://api.simplo.cl/api/v1/billing/dte/4f9c9c2e-8a49-4f2e-9d5f-0d8f3a1b2c3d \
  -H "X-Api-Key: $SIMPLO_API_KEY"
```

```json
// 200 OK (extracto)
{
  "estado": "aceptado",
  "tracking": { "track_id": "1234567890", "estado_envio": "aceptado" }
}
```

#### C#

```csharp
var current = await http.GetFromJsonAsync<JsonElement>(
    $"/api/v1/billing/dte/{dte.GetProperty("id")}");
Console.WriteLine(current.GetProperty("estado"));
// "enviando" | "procesando" | "aceptado" | "rechazado" | "con_reparos"
```

#### Java

```java
HttpRequest poll = HttpRequest.newBuilder()
    .uri(URI.create("https://api.simplo.cl/api/v1/billing/dte/" + dteId))
    .header("X-Api-Key", System.getenv("SIMPLO_API_KEY"))
    .GET()
    .build();
System.out.println(http.send(poll, HttpResponse.BodyHandlers.ofString()).body());
// "estado": "enviando" | "procesando" | "aceptado" | "rechazado" | "con_reparos"
```

#### Python

```python
conn.request(
    "GET",
    f"/api/v1/billing/dte/{dte['id']}",
    headers={"X-Api-Key": os.environ["SIMPLO_API_KEY"]},
)
current = json.loads(conn.getresponse().read())
print(current["estado"])
# "enviando" | "procesando" | "aceptado" | "rechazado" | "con_reparos"
```

#### SDK TypeScript (no publicado)

Vista previa — el SDK aún no está publicado, ver la pestaña **curl**:

```ts
const current = await simplo.dtes.retrieve(dte.id);
console.log(current.estado); // "enviando" | "procesando" | "aceptado" | …
console.log(current.tracking?.track_id); // track ID del SII una vez enviado
```

El ciclo completo de estados está documentado en
[Estados](/referencia/estados/). En sandbox puedes **forzar** un veredicto
(`rechazado`, `con_reparos`, folios agotados) con RUTs mágicos de receptor
en vez de esperar el camino feliz — ver el paso 5.

> La entrega de webhooks **aún no está activa** — el veredicto se sigue por
> polling de `GET /api/v1/billing/dte/{id}`, como arriba. Ver
> [Webhooks](/referencia/webhooks/).

## 4. Emite una boleta (tipo 39)

Una boleta a consumidor final es el mismo endpoint con `tipo_dte: 39` y un
campo extra **obligatorio**: `ind_servicio` (usa `3` — boleta de venta y
servicios). Omitirlo es el `400` más común al integrar boletas:

```bash
curl -X POST https://api.simplo.cl/api/v1/billing/dte \
  -H "X-Api-Key: $SIMPLO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "tipo_dte": 39,
    "ind_servicio": 3,
    "receptor": { "rut": "66666666-6", "razon_social": "Cliente Boleta" },
    "detalle": [
      { "nombre": "Producto", "cantidad": 1, "precio": 10000 }
    ]
  }'
```

Una diferencia con la factura: en boletas `precio` es **bruto** (IVA
incluido, como en la vitrina) — `monto_total` queda en `10000` y el motor
desglosa el IVA por dentro (`monto_neto: 8403`). En facturas, `precio` es
neto y la API agrega el IVA. La respuesta es `201` con `estado: "firmado"`,
igual que la factura.

## 5. Prueba los casos infelices

Un DTE aceptado en el primer intento es el caso fácil. Para probar tu
manejo de errores —rechazo del SII, folios agotados, un DTE que se queda
pegado en `procesando`— sin esperar a que ocurra por azar, el sandbox trae
**RUTs mágicos de receptor** que fuerzan cada resultado de forma
determinística. Ver
[Prueba los casos infelices](/comienza/casos-infelices/).

## 6. Descarga el PDF y el XML

```bash
# PDF con timbre electrónico PDF417 (agrega ?cedible=true para factoring)
curl -o factura.pdf \
  "https://api.simplo.cl/api/v1/billing/dte/$DTE_ID/pdf" \
  -H "X-Api-Key: $SIMPLO_API_KEY"

# XML firmado (ISO-8859-1)
curl -o factura.xml \
  "https://api.simplo.cl/api/v1/billing/dte/$DTE_ID/xml" \
  -H "X-Api-Key: $SIMPLO_API_KEY"
```

Con el SDK (cuando se publique): `simplo.dtes.pdf(dte.id, { cedible: true })` y
`simplo.dtes.xml(dte.id)`.

## Qué puede hacer tu API key

Una key `billing:dte` (sandbox o live) alcanza **exactamente seis rutas** —
las que acabas de usar, más el envelope de boletas. Todo lo demás de la API de
facturación se gestiona con tu sesión en app.simplo.cl, nunca con la key:

| Operación | ¿Por API key? |
| --- | --- |
| `POST /api/v1/billing/dte` — emitir (exige `Idempotency-Key`) | ✅ |
| `GET /api/v1/billing/dte` — listar | ✅ |
| `GET /api/v1/billing/dte/{id}` — detalle y estado | ✅ |
| `GET /api/v1/billing/dte/{id}/pdf` · `…/xml` — descargas | ✅ |
| [`POST /api/v1/billing/dte/send-boletas`](/referencia/emision/#boletas-el-conjunto-va-en-un-envelope) — enviar un conjunto de boletas en un envelope (exige `Idempotency-Key`) | ✅ |
| CAF/folios, empresa, certificado, libros, webhooks, clientes, productos | ❌ `403 BILLING_API_KEY_ROUTE_NOT_ALLOWED` — solo sesión |
| `POST /api/v1/mcp` (MCP para agentes) | ❌ `401` — el MCP usa keys `agent:read` u OAuth, no `billing:dte` |

No necesitas "preflight": en sandbox el certificado y los folios ya están
aprovisionados — emite directamente. Si una llamada tuya devuelve
`403 BILLING_API_KEY_ROUTE_NOT_ALLOWED`, no es un problema de tu cuenta: esa
ruta simplemente no es parte de la superficie por key.

## Siguientes pasos

- [Prueba los casos infelices](/comienza/casos-infelices/) — RUTs mágicos
  y el catálogo de errores estructurados
- [Pasar a producción](/comienza/pasar-a-produccion/) — la checklist honesta
  de go-live: certificado real, certificación SII, CAF real
- [El contrato OpenAPI](/referencia/contrato-openapi/) — descarga la spec y
  genera un cliente C#, Java o TypeScript
- [Referencia por endpoint](/api/) — los 27 endpoints, con ejemplos en curl,
  C#, Java y JavaScript
- [Autenticación](/comienza/autenticacion/) — API keys y auth avanzada
- [Tipos de DTE](/referencia/tipos-de-dte/) — los 12 tipos de documento
- [Errores](/referencia/errores/) — manejo de errores y reintentos
- [Paginación](/referencia/paginacion/) — listados con cursor
- [Webhooks](/referencia/webhooks/) — el contrato de entregas (aún no activo; usa polling)
- [Multi-empresa](/comienza/multi-empresa/) — operar más de una empresa
- [Agentes](/agentes/conecta-tu-agente/) — punteros para coding agents

---

Versión HTML: https://docs.simplo.cl/comienza/quickstart/ · Índice para agentes: https://docs.simplo.cl/llms.txt
