> ## Documentation Index
> Fetch the complete documentation index at: https://developers.zouti.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Versionamento e compatibilidade

> O que pode mudar dentro da v1 e como escrever uma integração que não quebra.

A versão da API está no caminho: `https://api.zouti.com.br/v1`. Dentro da `v1`, a API só recebe
mudanças **aditivas**: o que já existe continua funcionando do mesmo jeito.

## O que pode mudar na v1

* **Campos novos** no objeto, inclusive dentro de objetos aninhados como `payment` ou `customer`.
* **Valores novos** em listas de valores: `status`, `payment.status`, `payment.method`,
  `payment.card.brand` e as demais.
* **Parâmetros opcionais novos** nas rotas existentes.
* **Recursos novos**, com rotas novas.

## O que não muda na v1

Campo, parâmetro ou valor existente não muda de significado nem é removido dentro da `v1`.

Uma mudança incompatível (remover um campo, mudar o significado de um valor, tornar um parâmetro
obrigatório) só entra numa versão nova, num caminho novo (`/v2`). As mudanças da API ficam
registradas no [Changelog](/changelog).

## Como se proteger

Para não quebrar com as mudanças aditivas, a sua integração deve:

* **Ignorar campos que não conhece.** Leia só os campos que usa. Não valide a resposta com um
  schema que recuse propriedades extras.
* **Aceitar valores desconhecidos de enum.** Um `status` novo não pode derrubar a integração:
  trate-o num caso padrão (por exemplo, registre e siga) em vez de lançar erro.
* **Não depender da ordem dos campos** no JSON.
* **Não depender do texto de `error.message`.** Trate os erros pelo `code`; a mensagem pode mudar.

O código ao lado lê só os campos que usa e mapeia o `status` com um caso padrão.

<RequestExample>
  ```bash cURL theme={null}
  # Requer jq. Lê só os campos usados; um status desconhecido cai em "outro".
  curl -sS "https://api.zouti.com.br/v1/orders?limit=10" \
    -H "Authorization: Bearer $ZOUTI_API_KEY" \
    | jq -r '.data[] | [.id, .status, (
        {PAID: "pago", AWAITING_PAYMENT: "aguardando", REFUNDED: "reembolsado"}[.status] // "outro"
      )] | @tsv'
  ```

  ```javascript Node.js theme={null}
  // Node.js 18+ (fetch nativo). Lê só os campos usados e aceita status desconhecido.
  const API_KEY = process.env.ZOUTI_API_KEY;
  const BASE_URL = 'https://api.zouti.com.br';

  const STATUS_LABELS = {
    AWAITING_PAYMENT: 'aguardando pagamento',
    UNPAID: 'não pago',
    PAID: 'pago',
    CANCELED: 'cancelado',
    SHIPPED: 'enviado',
    DELIVERED: 'entregue',
    REFUNDED: 'reembolsado',
    DISPUTED: 'em disputa',
    TRIAL: 'em teste',
  };

  function statusLabel(status) {
    // Valor novo na v1 não derruba a integração: cai no caso padrão.
    return STATUS_LABELS[status] ?? `outro (${status})`;
  }

  const response = await fetch(`${BASE_URL}/v1/orders?limit=10`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  const body = await response.json();
  if (!response.ok) {
    console.error(`${body.error.code} (${body.error.request_id})`);
    process.exit(1);
  }

  for (const order of body.data) {
    // Só os campos usados: campos novos no JSON são ignorados.
    const { id, status, amount_total: amountTotal } = order;
    console.log(`${id} · ${statusLabel(status)} · ${amountTotal} centavos`);
  }
  ```

  ```python Python theme={null}
  # Python 3 com requests. Lê só os campos usados e aceita status desconhecido.
  import os

  import requests

  API_KEY = os.environ["ZOUTI_API_KEY"]
  BASE_URL = "https://api.zouti.com.br"

  STATUS_LABELS = {
      "AWAITING_PAYMENT": "aguardando pagamento",
      "UNPAID": "não pago",
      "PAID": "pago",
      "CANCELED": "cancelado",
      "SHIPPED": "enviado",
      "DELIVERED": "entregue",
      "REFUNDED": "reembolsado",
      "DISPUTED": "em disputa",
      "TRIAL": "em teste",
  }


  def status_label(status):
      # Valor novo na v1 não derruba a integração: cai no caso padrão.
      return STATUS_LABELS.get(status, f"outro ({status})")


  response = requests.get(
      f"{BASE_URL}/v1/orders",
      params={"limit": 10},
      headers={"Authorization": f"Bearer {API_KEY}"},
      timeout=30,
  )
  body = response.json()
  if not response.ok:
      raise SystemExit(f"{body['error']['code']} ({body['error']['request_id']})")

  for order in body["data"]:
      # Só os campos usados: campos novos no JSON são ignorados.
      print(f"{order['id']} · {status_label(order['status'])} · {order['amount_total']} centavos")
  ```

  ```php PHP theme={null}
  <?php
  // PHP 7.4+ com a extensão curl. Lê só os campos usados e aceita status desconhecido.
  const BASE_URL = 'https://api.zouti.com.br';
  const STATUS_LABELS = [
      'AWAITING_PAYMENT' => 'aguardando pagamento',
      'UNPAID' => 'não pago',
      'PAID' => 'pago',
      'CANCELED' => 'cancelado',
      'SHIPPED' => 'enviado',
      'DELIVERED' => 'entregue',
      'REFUNDED' => 'reembolsado',
      'DISPUTED' => 'em disputa',
      'TRIAL' => 'em teste',
  ];

  function status_label(string $status): string
  {
      // Valor novo na v1 não derruba a integração: cai no caso padrão.
      return STATUS_LABELS[$status] ?? "outro ({$status})";
  }

  $ch = curl_init(BASE_URL . '/v1/orders?limit=10');
  curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_TIMEOUT => 30,
      CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('ZOUTI_API_KEY')],
  ]);
  $raw = curl_exec($ch);
  if ($raw === false) {
      fwrite(STDERR, curl_error($ch) . PHP_EOL);
      exit(1);
  }
  $body = json_decode($raw, true);
  if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) !== 200) {
      fwrite(STDERR, "{$body['error']['code']} ({$body['error']['request_id']})\n");
      exit(1);
  }

  foreach ($body['data'] as $order) {
      // Só os campos usados: campos novos no JSON são ignorados.
      printf("%s · %s · %d centavos\n", $order['id'], status_label($order['status']), $order['amount_total']);
  }
  ```
</RequestExample>

<ResponseExample>
  ```json Pedido theme={null}
  {
    "object": "order",
    "id": "ord_8k2m4q6s1v3x5z7b9d0f2h",
    "role": "OWNER",
    "status": "PAID",
    "currency": "BRL",
    "amount_total": 27730,
    "amount_subtotal": 29700,
    "amount_in_brl": 27730,
    "created_at": "2026-10-14T13:05:22.418Z",
    "paid_at": "2026-10-14T13:05:24.902Z",
    "canceled_at": null,
    "updated_at": "2026-10-14T13:05:25.117Z",
    "customer": {
      "name": "Maria Oliveira",
      "email": "maria.oliveira@example.com",
      "phone": "+5511999998888",
      "document": "12345678909",
      "document_type": "CPF"
    },
    "shipping_address": {
      "line1": "Rua das Flores",
      "line2": "123",
      "line3": "Apto 45",
      "neighborhood": "Centro",
      "city": "São Paulo",
      "state": "SP",
      "country": "BR",
      "postal_code": "01001000",
      "full_name": "Maria Oliveira"
    },
    "payment": {
      "method": "CREDIT_CARD",
      "status": "PAID",
      "installments": 1,
      "amount": 27730,
      "interest_amount": 0,
      "discount_amount": 1970,
      "fee": 1386,
      "amount_refunded": 0,
      "refunded_at": null,
      "decline_code": null,
      "decline_message": null,
      "card": {
        "brand": "MASTERCARD",
        "last4": "4242"
      }
    },
    "items": [
      {
        "product_id": "prod_3n7p1r5t9w2y4a6c8e0g1j",
        "name": "Curso Completo de Fotografia",
        "quantity": 1,
        "unit_price": 19700,
        "sub_total": 19700,
        "currency": "BRL",
        "offer_id": "prod_offer_5d1f3h7k9m2p4r6t8v0x2z",
        "plan_id": null,
        "order_bump_id": null
      },
      {
        "product_id": "prod_6b8d0f2h4k6m8p0r2t4v6x",
        "name": "Pacote de Presets",
        "quantity": 1,
        "unit_price": 10000,
        "sub_total": 10000,
        "currency": "BRL",
        "offer_id": null,
        "plan_id": null,
        "order_bump_id": "ob_2c4e6g8j0l2n4q6s8u0w2y"
      }
    ],
    "offer": {
      "id": "prod_offer_5d1f3h7k9m2p4r6t8v0x2z",
      "name": "Oferta de lançamento"
    },
    "promocode": {
      "code": "BEMVINDO10",
      "description": "10% de desconto no curso",
      "amount": -1970
    },
    "utm": {
      "utm_source": "instagram",
      "utm_medium": "social",
      "utm_campaign": "lancamento-outubro",
      "utm_term": null,
      "utm_content": "stories"
    },
    "tracking": {
      "sck": "parceiro-123",
      "src": "bio"
    },
    "navigator": {
      "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Instagram 350.0.0",
      "referer": "https://www.instagram.com/",
      "device": "Mobile",
      "browser": "Instagram",
      "origin": "instagram.com"
    },
    "metadata": {}
  }
  ```
</ResponseExample>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.