# Cambiar una cotización

`POST https://api.fiscalisto.com/v1/quotes/{id}`

Solo lo que mande cambia. Un borrador cambia ahí mismo; una que ya se envió se vuelve una versión nueva en borrador (mismo número, version + 1) que el cliente ve al mandarla; mientras, su liga muestra la anterior. Una aceptada, rechazada o facturada ya no cambia.

## Parámetros

| Nombre | Dónde | Obligatorio | Descripción |
| --- | --- | --- | --- |
| `id` | ruta | sí | El id del objeto. |
| `Idempotency-Key` | encabezado |  | Opcional (los SDK la mandan solos). Si la respuesta se pierde, repita la solicitud con el mismo valor durante 24 horas: contesta lo mismo, con idempotent-replayed: true, y no lo hace dos veces (ni crea, ni manda correos, ni cobra). |

## Cuerpo

| Campo | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- |
| `customer` | string (cus_…) o objeto |  | Un cliente de su catálogo (cus_…), uno con sus datos fiscales (como en POST /v1/invoices: se agrega a sus clientes) o solo name y email si aún no los tiene. |
| `customer.tax_id` | string | sí | RFC (Rfc), 12 caracteres una persona moral y 13 una física. |
| `customer.legal_name` | string | sí | Nombre o razón social tal como está en la constancia de situación fiscal, sin el régimen de capital (sin «S.A. de C.V.»). (hasta 300 caracteres) |
| `customer.tax_system` | string | sí | Régimen fiscal (RegimenFiscal), clave de c_RegimenFiscal: 601, 612, 626… |
| `customer.zip` | string | sí | Código postal del domicilio fiscal del cliente (DomicilioFiscalReceptor), 5 dígitos. |
| `customer.email` | string |  | Su correo (hasta 5, separados por comas). (hasta 500 caracteres) |
| `customer.foreign` | objeto |  | Si es extranjero: su país de residencia (ResidenciaFiscal, c_Pais) y su número de registro tributario (NumRegIdTrib), con el RFC genérico XEXX010101000. |
| `customer.foreign.country` | string | sí | País de residencia fiscal, clave de 3 letras de c_Pais (USA, CAN…). (3 caracteres) |
| `customer.foreign.tax_id` | string | sí | Número de registro de identidad fiscal en su país (NumRegIdTrib). (hasta 40 caracteres) |
| `customer.ieps_taxpayer` | boolean |  | true si el cliente es contribuyente de IEPS: el IEPS va desglosado en vez de sumado al precio. |
| `customer.name` | string | sí | A quién va dirigida. (hasta 200 caracteres) |
| `items` | arreglo de objeto |  | Los conceptos, como en POST /v1/invoices. (hasta 200) |
| `items[].product` | string (prd_…) |  | Un producto de su catálogo (prd_…): toma su clave, unidad, precio e impuestos. |
| `items[].description` | string |  | Descripción del concepto (Descripcion), hasta 1,000 caracteres. (hasta 1000 caracteres) |
| `items[].product_key` | string |  | Clave del producto o servicio (ClaveProdServ), 8 dígitos de c_ClaveProdServ. Búsquela con GET /v1/sat_catalogs/product_keys?q=… |
| `items[].unit_key` | string |  | Clave de unidad (ClaveUnidad) de c_ClaveUnidad: E48 unidad de servicio (por omisión), H87 pieza, ACT actividad… (hasta 5 caracteres) |
| `items[].unit_name` | string o null |  | Nombre de la unidad (Unidad), hasta 20 caracteres. |
| `items[].sku` | string o null |  | Número de identificación o SKU (NoIdentificacion). |
| `items[].quantity` | number |  | Cantidad (Cantidad). Por omisión 1. (de -∞ a 1000000000) |
| `items[].unit_price` | number |  | Precio unitario antes de impuestos (ValorUnitario). (de 0 a 1000000000000) |
| `items[].discount` | number |  | Descuento (Descuento). (de 0 a 1000000000000) |
| `items[].taxability` | `01`, `02`, `03`, `04`, `05`, `06`, `07`, `08` |  | Objeto de impuesto (ObjetoImp), c_ObjetoImp: 01 no objeto, 02 sí objeto (por omisión), 03 sin desglose, 04 no causa… |
| `items[].iva` | `0`, `0.16`, `0.08`, `exento` |  | Tasa de IVA trasladado: 0.16 (por omisión), 0.08 (región fronteriza), 0 o exento. |
| `items[].ieps` | number |  | IEPS trasladado: tasa (0.265…) o cuota en pesos por unidad, según ieps_factor. (de 0 a 72.1605) |
| `items[].ieps_factor` | `Tasa`, `Cuota` |  | Tasa o Cuota (TipoFactor del IEPS). |
| `items[].ieps_units` | number |  | Unidades de IEPS a cuota (litros, cigarros…), si no son la cantidad. (de -∞ a 1000000000) |
| `items[].iva_retention` | number |  | Tasa de IVA retenido (por ejemplo 0.106667, dos terceras partes del 16%). (de 0 a 0.16) |
| `items[].isr_retention` | number |  | Tasa de ISR retenido (por ejemplo 0.10 honorarios, 0.0125 RESICO). (de 0 a 0.35) |
| `items[].predial` | arreglo de string |  | Números de cuenta predial (CuentaPredial) en arrendamiento. (hasta 10) |
| `items[].pedimentos` | arreglo de string |  | Números de pedimento (InformacionAduanera) de mercancía importada. (hasta 50) |
| `items[].third_party` | objeto |  | A cuenta de terceros (ACuentaTerceros): RFC, nombre, régimen y código postal. |
| `items[].third_party.tax_id` | string | sí | RFC de a cuenta de quién (RfcACuentaTerceros). (hasta 13 caracteres) |
| `items[].third_party.name` | string | sí | Nombre (NombreACuentaTerceros). (hasta 300 caracteres) |
| `items[].third_party.tax_system` | string | sí | Régimen fiscal (RegimenFiscalACuentaTerceros), c_RegimenFiscal. |
| `items[].third_party.zip` | string | sí | Código postal de su domicilio fiscal (DomicilioFiscalACuentaTerceros). |
| `items[].iedu` | objeto |  | Complemento de instituciones educativas privadas (IEDU): alumno, CURP, nivel y RVOE. |
| `items[].iedu.student_name` | string | sí | Nombre del alumno (nombreAlumno). (hasta 300 caracteres) |
| `items[].iedu.curp` | string | sí | CURP, 18 caracteres. (18 caracteres) |
| `items[].iedu.level` | `Preescolar`, `Primaria`, `Secundaria`, `Profesional técnico`, `Bachillerato o su equivalente` | sí | Nivel educativo (nivelEducativo). |
| `items[].iedu.rvoe` | string | sí | Reconocimiento de validez oficial de estudios (autRVOE). (hasta 30 caracteres) |
| `items[].iedu.payer_tax_id` | string o null |  | RFC de quien paga, si no es el receptor (rfcPago). |
| `items[].used_vehicle` | objeto |  | Complemento de vehículo usado. |
| `items[].used_vehicle.purchase_amount` | number | sí | Monto de adquisición (montoAdquisicion). (de -∞ a 1000000000000) |
| `items[].used_vehicle.sale_amount` | number | sí | Monto de enajenación (montoEnajenacion). (de -∞ a 1000000000000) |
| `items[].used_vehicle.vehicle_key` | string | sí | Clave vehicular (claveVehicular). (hasta 7 caracteres) |
| `items[].used_vehicle.make` | string | sí | Marca (marca). (hasta 50 caracteres) |
| `items[].used_vehicle.type` | string | sí | Tipo o versión (tipo). (hasta 50 caracteres) |
| `items[].used_vehicle.model` | string | sí | Año del modelo (modelo), 4 dígitos. |
| `items[].used_vehicle.engine_number` | string |  | Número de motor (numeroMotor). (hasta 17 caracteres) |
| `items[].used_vehicle.serial_number` | string |  | Número de serie (numeroSerie). (hasta 17 caracteres) |
| `items[].used_vehicle.niv` | string |  | Número de identificación vehicular (NIV). (hasta 17 caracteres) |
| `items[].used_vehicle.guide_value` | number | sí | Valor según la guía EBC o Libro Azul (valor). (de -∞ a 1000000000000) |
| `items[].used_vehicle.customs` | arreglo de objeto |  | Información aduanera de la importación del vehículo (InformacionAduanera). (hasta 10) |
| `items[].used_vehicle.customs[].number` | string | sí | Número del documento de importación (numero). (hasta 100 caracteres) |
| `items[].used_vehicle.customs[].date` | string | sí | Fecha del documento (fecha), AAAA-MM-DD. |
| `items[].used_vehicle.customs[].office` | string |  | Aduana (aduana). (hasta 100 caracteres) |
| `items[].addenda` | objeto |  | Addenda del receptor (Walmart, Soriana…), con sus propios campos. |
| `currency` | string |  | Moneda, clave ISO 4217 de c_Moneda (MXN, USD, EUR…). Por omisión MXN. (3 caracteres) |
| `exchange_rate` | number |  | Tipo de cambio a pesos (TipoCambio). Obligatorio si la moneda no es MXN; use el del DOF del día anterior. (de -∞ a 1000000) |
| `payment_form` | string |  | Forma de pago (FormaPago), clave de c_FormaPago: 01 efectivo, 03 transferencia, 04 tarjeta de crédito, 28 débito, 99 por definir… Obligatoria con PUE; con PPD es 99. |
| `payment_method` | `PUE`, `PPD` |  | Método de pago (MetodoPago): PUE (una sola exhibición, por omisión) o PPD (en parcialidades o diferido, se cobra con complementos de pago). |
| `use` | string |  | Uso del CFDI (UsoCFDI), clave de c_UsoCFDI. Por omisión G03, o S01 con régimen 616. |
| `notes` | string |  | Observaciones que aparecen en el PDF (no van en el XML). (hasta 1000 caracteres) |
| `valid_until` | string |  | Hasta cuándo es válida (AAAA-MM-DD, hasta un año). Por omisión, en 15 días. |
| `terms` | string |  | Condiciones: tiempo de entrega, anticipo, garantía… (hasta 2000 caracteres) |

Ejemplo:

```json
{
  "valid_until": "2026-11-30"
}
```

## Con el SDK de TypeScript

```ts
import { Fiscalisto } from "fiscalisto";

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

const quote = await fiscalisto.quotes.update("quo_OufpKqnrvx9p3Kd8wQm2XyT5uBcW8sKdLx", { valid_until: "2026-11-30" }, { idempotencyKey: "pedido-A-1042" });
```

## Con el SDK de Python

```python
from fiscalisto import Fiscalisto

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

quote = fiscalisto.quotes.update("quo_OufpKqnrvx9p3Kd8wQm2XyT5uBcW8sKdLx", {"valid_until": "2026-11-30"}, idempotency_key="pedido-A-1042")
```

## Con el SDK de PHP

```php
<?php

use Fiscalisto\Fiscalisto;

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

$quote = $fiscalisto->quotes->update('quo_OufpKqnrvx9p3Kd8wQm2XyT5uBcW8sKdLx', ['valid_until' => '2026-11-30'], ['idempotency_key' => 'pedido-A-1042']);
```

## Con el SDK de .NET

```csharp
using Fiscalisto;

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

var quote = await fiscalisto.Quotes.UpdateAsync("quo_OufpKqnrvx9p3Kd8wQm2XyT5uBcW8sKdLx", new UpdateQuoteParams { ValidUntil = "2026-11-30" }, new RequestOptions { IdempotencyKey = "pedido-A-1042" });
```

## Con el SDK de Go

```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()

	quote, err := client.Quotes.Update(ctx, "quo_OufpKqnrvx9p3Kd8wQm2XyT5uBcW8sKdLx", &fiscalisto.UpdateQuoteParams{
		ValidUntil: fiscalisto.String("2026-11-30"),
	}, fiscalisto.WithIdempotencyKey("pedido-A-1042"))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(quote.ID)
}
```

## Con el SDK de Java

```java
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.RequestOptions;
import com.fiscalisto.model.UpdateQuoteParams;

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

var quote = fiscalisto.quotes().update("quo_OufpKqnrvx9p3Kd8wQm2XyT5uBcW8sKdLx", new UpdateQuoteParams().setValidUntil("2026-11-30"), RequestOptions.idempotencyKey("pedido-A-1042"));
System.out.println(quote.getId());
```

## Respuesta 200

Correcto.

Un objeto `Quote`:

| Campo | Tipo | Siempre viene | Descripción |
| --- | --- | --- | --- |
| `id` | string | sí | Identificador del objeto, con su prefijo (iss_, inv_, ret_, cus_, prd_, emp_, bat_, brn_, whs_, stm_, adj_, evt_, whe_). |
| `livemode` | boolean | sí | true en producción (llaves fk_live_), false en pruebas (fk_test_). Lo de pruebas no vale ante el SAT. |
| `object` | `"quote"` | sí | Qué tipo de objeto es («invoice», «customer»…). |
| `issuer` | string | sí | El emisor (iss_…). |
| `number` | string | sí | Su serie y folio, como lo ve el cliente (COT-12). |
| `version` | integer | sí | Cambiar una ya enviada hace una versión nueva con el mismo número; el id contesta siempre la última. (de -9007199254740991 a 9007199254740991) |
| `status` | `draft`, `sent`, `viewed`, `accepted`, `rejected`, `expired`, `invoiced` | sí | draft, sent, viewed (el cliente abrió la liga), accepted, rejected, expired (pasó valid_until) o invoiced. |
| `url` | string o null | sí | La liga donde el cliente la ve, descarga su PDF, la acepta, pide cambios o la rechaza; null mientras sea borrador. |
| `customer` | objeto | sí | A quién va: tax_id null si aún no tiene sus datos fiscales; catalog_id es su cliente (cus_…) en su catálogo, o null. |
| `customer.tax_id` | string o null | sí | RFC (Rfc), 12 caracteres una persona moral y 13 una física. |
| `customer.name` | string o null | sí | Nombre. |
| `customer.email` | string o null | sí | Correo a donde se envía (varios separados por comas). Solo se usa si se pide enviarlo. |
| `customer.catalog_id` | string o null | sí | El cliente (cus_…) en su catálogo, o null si no está en él. |
| `currency` | string | sí | La moneda. |
| `items` | arreglo de objeto | sí | Los conceptos, como los de una factura. |
| `items[].description` | string | sí | Descripción del concepto (Descripcion), hasta 1,000 caracteres. |
| `items[].product_key` | string | sí | Clave del producto o servicio (ClaveProdServ), 8 dígitos de c_ClaveProdServ. Búsquela con GET /v1/sat_catalogs/product_keys?q=… |
| `items[].quantity` | number |  | Cantidad (Cantidad). Por omisión 1. |
| `items[].unit_key` | string |  | Clave de unidad (ClaveUnidad) de c_ClaveUnidad: E48 unidad de servicio (por omisión), H87 pieza, ACT actividad… |
| `items[].unit_price` | number | sí | Precio unitario antes de impuestos (ValorUnitario). |
| `total` | number o null | sí | El total con impuestos. |
| `valid_until` | string | sí | Su último día de validez (AAAA-MM-DD). |
| `terms` | string o null | sí | Las condiciones impresas: entrega, anticipo, garantía… |
| `notes` | string o null | sí | Las notas, como las de una factura. |
| `auto_invoice` | boolean | sí | Si al aceptarla se timbra la factura sola. |
| `customer_comment` | string o null | sí | Lo que escribió el cliente al pedir cambios o al rechazarla, o null. |
| `sent_at` | string (date-time) o null | sí | Cuándo se envió. |
| `viewed_at` | string (date-time) o null | sí | Cuándo el cliente abrió la liga por primera vez. |
| `decided_at` | string (date-time) o null | sí | Cuándo se aceptó o rechazó. |
| `decided_by` | `customer`, `user` o null | sí | customer (en su liga) o user (usted, con POST /v1/quotes/{id}/accept o desde la app). |
| `invoice` | string o null | sí | La factura (inv_…) que se timbró de ella, o null. |
| `created_at` | string (date-time) o null | sí | Cuándo se creó. |

```json
{
  "id": "quo_OufpKqnrvx9p3Kd8wQm2XyT5uBcW8sKdLx",
  "object": "quote",
  "livemode": false,
  "issuer": "iss_OufpKqnrvx9p",
  "number": "COT-12",
  "version": 1,
  "status": "sent",
  "url": "https://fiscalisto.com/cotizacion/7Hq2mZr1XyT5uBcW8sKdLx0VeNOufpKq",
  "customer": {
    "tax_id": "ICV060329BY0",
    "name": "INMOBILIARIA CVA",
    "email": "compras@cva.example",
    "catalog_id": "cus_OufpKqnrvx9p42"
  },
  "currency": "MXN",
  "items": [
    {
      "description": "Desarrollo del sitio web",
      "product_key": "81112103",
      "quantity": 1,
      "unit_key": "E48",
      "unit_price": 45000
    }
  ],
  "total": 52200,
  "valid_until": "2026-11-09",
  "terms": "50% de anticipo, entrega en 4 semanas.",
  "notes": null,
  "auto_invoice": true,
  "customer_comment": null,
  "sent_at": "2026-10-25T10:12:00-06:00",
  "viewed_at": null,
  "decided_at": null,
  "decided_by": null,
  "invoice": null,
  "created_at": "2026-10-25T10:05:00-06:00"
}
```

## Errores

Puede responder 400, 401, 403, 404, 429, 500 con el cuerpo de error de siempre; cada código está en https://fiscalisto.com/docs/api/errores.md.
