# Pedidos

> Registre lo que su cliente pidió, entréguelo con su remisión, facture lo entregado en una o varias partes y sepa cuándo se cobró.

Un **pedido** (`sor_…`) es lo que su cliente le compra: los conceptos, su orden de compra y cuándo lo espera. Lo **entrega** en una o varias partes, cada una con su remisión (`REM-1`, `REM-2`…), y lo **factura** en una o varias facturas. Su estado sigue solo lo que pasa: `draft` → `confirmed` → `partially_delivered` → `delivered` → `invoiced` → `paid` (o `closed`, `canceled`). Un pedido no es un CFDI; cada factura que sale de él sí lo es.

## Crear uno

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/sales_orders \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": "cus_OufpKqnrvx9p42",
    "customer_po": "OC-778",
    "payment_form": "99",
    "payment_method": "PPD",
    "items": [
      { "description": "Silla de oficina ergonómica", "product_key": "56101504", "quantity": 100, "unit_price": 1850 }
    ],
    "expected_on": "2026-11-20",
    "payment_days": 30,
    "confirm": true
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const salesOrder = await fiscalisto.salesOrders.create({
  customer: "cus_OufpKqnrvx9p42",
  customer_po: "OC-778",
  payment_form: "99",
  payment_method: "PPD",
  items: [
    {
      description: "Silla de oficina ergonómica",
      product_key: "56101504",
      quantity: 100,
      unit_price: 1850,
    },
  ],
  expected_on: "2026-11-20",
  payment_days: 30,
  confirm: true,
});
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

sales_order = fiscalisto.sales_orders.create({
    "customer": "cus_OufpKqnrvx9p42",
    "customer_po": "OC-778",
    "payment_form": "99",
    "payment_method": "PPD",
    "items": [
        {
            "description": "Silla de oficina ergonómica",
            "product_key": "56101504",
            "quantity": 100,
            "unit_price": 1850,
        },
    ],
    "expected_on": "2026-11-20",
    "payment_days": 30,
    "confirm": True,
})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$salesOrder = $fiscalisto->salesOrders->create([
    'customer' => 'cus_OufpKqnrvx9p42',
    'customer_po' => 'OC-778',
    'payment_form' => '99',
    'payment_method' => 'PPD',
    'items' => [
        [
            'description' => 'Silla de oficina ergonómica',
            'product_key' => '56101504',
            'quantity' => 100,
            'unit_price' => 1850,
        ],
    ],
    'expected_on' => '2026-11-20',
    'payment_days' => 30,
    'confirm' => true,
]);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	salesOrder, err := client.SalesOrders.Create(ctx, &fiscalisto.CreateSalesOrderParams{
		Customer:      fiscalisto.IDOf[fiscalisto.CreateSalesOrderParamsCustomer]("cus_OufpKqnrvx9p42"),
		CustomerPo:    fiscalisto.String("OC-778"),
		PaymentForm:   fiscalisto.String("99"),
		PaymentMethod: fiscalisto.String("PPD"),
		Items: []fiscalisto.CreateSalesOrderParamsItem{
			{
				Description: fiscalisto.String("Silla de oficina ergonómica"),
				ProductKey:  fiscalisto.String("56101504"),
				Quantity:    fiscalisto.Float64(100),
				UnitPrice:   fiscalisto.Float64(1850),
			},
		},
		ExpectedOn:  fiscalisto.String("2026-11-20"),
		PaymentDays: fiscalisto.Int64(30),
		Confirm:     fiscalisto.Bool(true),
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(salesOrder.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.CreateSalesOrderParams;
import com.fiscalisto.model.CreateSalesOrderParamsItem;
import java.util.List;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var salesOrder = fiscalisto.salesOrders().create(new CreateSalesOrderParams()
        .setCustomer("cus_OufpKqnrvx9p42")
        .setCustomerPo("OC-778")
        .setPaymentForm("99")
        .setPaymentMethod("PPD")
        .setItems(List.of(
                new CreateSalesOrderParamsItem()
                        .setDescription("Silla de oficina ergonómica")
                        .setProductKey("56101504")
                        .setQuantity(100)
                        .setUnitPrice(1850)
        ))
        .setExpectedOn("2026-11-20")
        .setPaymentDays(30)
        .setConfirm(true));
System.out.println(salesOrder.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var salesOrder = await fiscalisto.SalesOrders.CreateAsync(new CreateSalesOrderParams
{
    Customer = "cus_OufpKqnrvx9p42",
    CustomerPo = "OC-778",
    PaymentForm = "99",
    PaymentMethod = "PPD",
    Items = new()
    {
        new()
        {
            Description = "Silla de oficina ergonómica",
            ProductKey = "56101504",
            Quantity = 100,
            UnitPrice = 1850,
        },
    },
    ExpectedOn = "2026-11-20",
    PaymentDays = 30,
    Confirm = true,
});
```

Los conceptos y las condiciones de pago son los de una [factura](https://fiscalisto.com/docs/api/facturas) y se revisan con las mismas reglas, así que cada factura que sale del pedido timbra. `customer` es un cliente de su catálogo (`cus_…`) o uno con sus datos fiscales (se agrega a sus clientes). Con `"quote": "quo_…"` el pedido sale de una [cotización](https://fiscalisto.com/docs/api/cotizaciones), con su cliente y sus conceptos, y la cotización queda aceptada.

Sin `confirm` queda en borrador (`draft`) y se cambia con `POST /v1/sales_orders/{id}`; confírmelo con `POST /v1/sales_orders/{id}/confirm`. Confirmado, con [inventario](https://fiscalisto.com/docs/api/inventario) se aparta lo pedido en el almacén y ya se puede entregar y facturar.

`invoice_policy` dice qué se factura: `delivered` (por omisión), lo ya entregado; `ordered`, todo lo pedido desde el inicio (por ejemplo con pago por adelantado). Los servicios no se entregan: se facturan desde la primera factura.

## Entregar

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/sales_orders/sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx/deliveries \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [{ "line": 31, "quantity": 60 }],
    "carrier": "Paquetexpress",
    "tracking": "PX-90122"
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const salesOrder = await fiscalisto.salesOrders.deliver("sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx", {
  items: [{ line: 31, quantity: 60 }],
  carrier: "Paquetexpress",
  tracking: "PX-90122",
});
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

sales_order = fiscalisto.sales_orders.deliver("sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx", {
    "items": [{"line": 31, "quantity": 60}],
    "carrier": "Paquetexpress",
    "tracking": "PX-90122",
})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$salesOrder = $fiscalisto->salesOrders->deliver('sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx', [
    'items' => [['line' => 31, 'quantity' => 60]],
    'carrier' => 'Paquetexpress',
    'tracking' => 'PX-90122',
]);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	salesOrder, err := client.SalesOrders.Deliver(ctx, "sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx", &fiscalisto.CreateSalesOrderDeliveryParams{
		Items: []fiscalisto.CreateSalesOrderDeliveryParamsItem{
			{Line: 31, Quantity: 60},
		},
		Carrier:  fiscalisto.String("Paquetexpress"),
		Tracking: fiscalisto.String("PX-90122"),
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(salesOrder.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.CreateSalesOrderDeliveryParams;
import com.fiscalisto.model.CreateSalesOrderDeliveryParamsItem;
import java.util.List;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var salesOrder = fiscalisto.salesOrders().deliver("sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx", new CreateSalesOrderDeliveryParams()
        .setItems(List.of(
                new CreateSalesOrderDeliveryParamsItem()
                        .setLine(31)
                        .setQuantity(60)
        ))
        .setCarrier("Paquetexpress")
        .setTracking("PX-90122"));
System.out.println(salesOrder.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var salesOrder = await fiscalisto.SalesOrders.DeliverAsync("sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx", new CreateSalesOrderDeliveryParams
{
    Items = new() { new() { Line = 31, Quantity = 60 } },
    Carrier = "Paquetexpress",
    Tracking = "PX-90122",
});
```

`line` es el `id` de cada concepto en `items` del pedido. Sin `items`, sale todo lo que falta. La mercancía sale del almacén con la entrega, no con la factura. Si el emisor no vende sin existencias, no sale más de lo que hay (`400 sales_order_invalid`). Cada entrega trae su remisión en el PDF del pedido y su cliente la firma en su liga; si ya sabe quién recibió, mándelo en `received_by`.

`POST /v1/sales_orders/{id}/deliveries/{dlv_…}/cancel` regresa la mercancía al almacén. `POST /v1/sales_orders/{id}/cancel_remaining` deja el pedido con lo ya entregado.

## Facturar

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/sales_orders/sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx/invoice \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: PED-12-factura-1" \
  -d '{}'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const invoice = await fiscalisto.salesOrders.invoice("sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx", { idempotencyKey: "PED-12-factura-1" });
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

invoice = fiscalisto.sales_orders.invoice("sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx", idempotency_key="PED-12-factura-1")
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$invoice = $fiscalisto->salesOrders->invoice('sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx', [], ['idempotency_key' => 'PED-12-factura-1']);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	invoice, err := client.SalesOrders.Invoice(ctx, "sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx", nil, fiscalisto.WithIdempotencyKey("PED-12-factura-1"))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(invoice.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.RequestOptions;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var invoice = fiscalisto.salesOrders().invoice("sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx", null, RequestOptions.idempotencyKey("PED-12-factura-1"));
System.out.println(invoice.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var invoice = await fiscalisto.SalesOrders.InvoiceAsync("sor_OufpKqnrvx9p5Rt2mZr1XyT5uBcW8sKdLx", options: new RequestOptions { IdempotencyKey = "PED-12-factura-1" });
```

Timbra una factura con lo entregado y no facturado (o lo que diga `items`), con los datos fiscales que el cliente tenga hoy en su catálogo y la nota «Pedido PED-12 · Su orden de compra OC-778». Contesta la factura, como `POST /v1/invoices`. Cada llamada con una [Idempotency-Key](https://fiscalisto.com/docs/api/idempotencia) nueva timbra la siguiente parte; repetirla con la misma contesta la misma factura. Si no queda nada por facturar, `400 sales_order_invalid`.

Con `include_undelivered: true` también factura lo que aún no se entrega. Con `deliver: true`, al timbrar se registra la entrega de lo que lleva (venta de mostrador).

El pedido queda `paid` cuando sus facturas se pagan: una PUE al timbrarse, una PPD con sus [complementos de pago](https://fiscalisto.com/docs/api/pagos-y-notas-de-credito) o al conciliar el depósito. `invoices` trae cada factura con lo que falta pagar (`balance`), y `paid_total` la suma pagada. Si cancela una factura, lo que llevaba se puede volver a facturar.

## Mandarlo a su cliente

`POST /v1/sales_orders/{id}/send` lo manda por correo con su PDF y la liga (`url`) donde su cliente lo confirma, firma cada entrega con «Ya lo recibí», descarga sus remisiones y abre sus facturas. Con `"send_email": false` solo contesta `url`. `GET /v1/sales_orders/{id}/pdf` da el PDF.

## Eventos

| Evento | Cuándo |
| --- | --- |
| `sales_order.confirmed` | Se confirmó (por la API o desde la app). |
| `sales_order.customer_confirmed` | Su cliente lo confirmó en su liga (`customer_confirmed_at`). |
| `sales_order.delivered` | Ya salió todo lo pedido (`delivered_at`). |
| `sales_order.paid` | Sus facturas quedaron pagadas (`paid_at`). |
| `sales_order.canceled` | Se canceló (`cancel_reason`). |

## Cerrar, cancelar o reabrir

| Ruta | Para qué |
| --- | --- |
| `POST /v1/sales_orders/{id}/close` | Lo da por terminado aunque quede algo pendiente, y libera lo apartado. |
| `POST /v1/sales_orders/{id}/cancel` | Solo sin entregas ni facturas timbradas. Borra sus facturas en borrador y libera lo apartado. |
| `POST /v1/sales_orders/{id}/reopen` | Uno cerrado o cancelado vuelve a estar abierto. |
| `DELETE /v1/sales_orders/{id}` | Borra un borrador. |

`close` y `cancel` aceptan `reason`, que queda en su historial.
