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

> ## Agent Instructions
> Documentação das APIs da DeliveryVip, em português. Regras que mais quebram integrações: (1) Merchant API: faça polling em GET /merchant/v3/events:polling no máximo a cada 30 s por token; confirme todo evento recebido com POST /merchant/v3/events/acknowledgment e corpo [{"id": "<eventId>"}] (o campo lido é id, não eventId), inclusive eventos repetidos ou que o sistema não trata; deduplique por eventId; o evento é só um aviso, busque o pedido na orderURL. (2) Tokens client_credentials valem 24 h e não têm refresh_token: peça outro ao receber 401. (3) Webhooks: valide a assinatura HMAC sobre o corpo bruto e responda 2xx rápido; o polling é a reconciliação. (4) Open Delivery: host od.deliveryvip.com.br, um client_secret por loja, datas em UTC. (5) Fidelidade: o operador implementa 5 rotas assinadas com HMAC e chama o config push; o estorno precisa ser idempotente. (6) Partner API: scope dv.partner. Não invente endpoints: use a referência gerada das specs OpenAPI.

# Reescrever o catálogo (force)

> Envie o catálogo completo em uma chamada e remova da DeliveryVip tudo o que não estiver nele.

`POST /merchant/v3/{merchantId}/merchantForce` recebe a loja inteira, no mesmo formato do [GET da loja](/docs/guides/merchant/catalog-and-services/details.md), e deixa o catálogo da DeliveryVip igual ao enviado. Cada lista enviada cria e altera os objetos dela e **remove os que não vieram**. Use na carga inicial ou quando o seu sistema for a fonte da verdade do catálogo inteiro.

> [!CAUTION]
>
> **Lista vazia apaga tudo daquele tipo.** `"items": []` tira todos os produtos do cardápio, e uma lista com um produto só deixa a loja com um produto só. Antes de chamar o force, confirme que cada lista enviada está completa.

## O que acontece com cada lista

![Se a chave não veio, o tipo fica como está; com objetos, cria e altera os enviados e remove os demais; vazia, remove todos daquele tipo](https://mintcdn.com/deliveryvip-a4256422/ELxpcniK2_BP8zxT/images/catalogo-force-listas.png?fit=max\&auto=format\&n=ELxpcniK2_BP8zxT\&q=85\&s=64d4d1f2d851030cb6f357ea0d6f30b1)

O que o force faz com cada lista do corpo

| Lista | Objetos que não vieram |
| - | - |
| `options`, `optionGroups`, `categories`, `items` | Saem do catálogo. Se forem enviados de novo com o mesmo `id`, em um force ou upsert, voltam. |
| `paymentMethods` | São **apagados** de vez. |
| `services` | Nada é removido: só os serviços enviados são alterados. |

As listas são gravadas nesta ordem: `services`, `options`, `optionGroups`, `categories`, `items` e `paymentMethods`. Por isso um produto pode apontar para uma categoria criada na mesma chamada, e um grupo para opções criadas na mesma chamada. Tudo roda numa única transação: se qualquer objeto falhar, nada é gravado.

> [!WARNING]
>
> O `status` é obrigatório e sempre aplicado: `AVAILABLE` abre a loja e `UNAVAILABLE` fecha. Envie o estado que a loja deve ter depois da chamada.

## Corpo da requisição

**id** `uuid` *required*

ID da loja. Use o mesmo `merchantId` da URL.

**lastUpdate** `datetime` *required*

Data e hora da versão do catálogo no seu sistema. Obrigatório, mas hoje não é usado.

**ttl** `integer` *required*

Obrigatório para manter o formato do GET, mas hoje não é usado. Envie `3600`.

**status** `string` *required*

`AVAILABLE` abre a loja, `UNAVAILABLE` fecha.

**basicInfo** `object`

Aceito para manter o formato do GET, mas **não altera** os dados cadastrais da loja. Se enviado, precisa de `name`, `document` e `corporateName`, e o `address`, se vier, de `state`, `city`, `district`, `street`, `number` e `postalCode`. Pode ser omitido.

**services** `object[]`

Serviços de entrega e retirada, com os campos de [`SERVICE`](/docs/guides/merchant/catalog-and-services/actions/upsert#service).

**options** `object[]`

Opções, com os campos de [`OPTION`](/docs/guides/merchant/catalog-and-services/actions/upsert#option).

**optionGroups** `object[]`

Grupos de opções, com os campos de [`OPTION_GROUP`](/docs/guides/merchant/catalog-and-services/actions/upsert#option_group).

**categories** `object[]`

Categorias, com os campos de [`CATEGORY`](/docs/guides/merchant/catalog-and-services/actions/upsert#category).

**items** `object[]`

Produtos com modificadores, com os campos de [`ITEM`](/docs/guides/merchant/catalog-and-services/actions/upsert#item).

**paymentMethods** `object[]`

Formas de pagamento, com os campos de [`PAYMENT_METHOD`](/docs/guides/merchant/catalog-and-services/actions/upsert#payment_method).

Os objetos de cada lista seguem as mesmas regras do [upsert](/docs/guides/merchant/catalog-and-services/actions/upsert.md), inclusive os campos obrigatórios. As regras de formato, imagens e erros estão em [Ações](/docs/guides/merchant/catalog-and-services/actions.md).

## Requisição

Reescrever só as categorias, sem tocar em produtos, opções e formas de pagamento:

```bash cURL theme={null}
curl --request POST 'https://api.deliveryvip.com.br/merchant/v3/{merchantId}/merchantForce' \
  --header 'Authorization: Bearer {token}' \
  --header 'Content-Type: application/json' \
  --data '{
    "id": "{merchantId}",
    "lastUpdate": "2023-09-26T18:29:16-03:00",
    "ttl": 3600,
    "status": "AVAILABLE",
    "categories": [
      { "id": "41678b1b-1902-4f34-b7b0-e2271e93283c", "index": 1, "name": "Pizzas", "status": "AVAILABLE" },
      { "id": "d37d1183-d544-4d15-a067-0f0ad38f7680", "index": 2, "name": "Bebidas", "status": "AVAILABLE" }
    ]
  }'
```

```js Node.js theme={null}
const response = await fetch(
  `https://api.deliveryvip.com.br/merchant/v3/${merchantId}/merchantForce`,
  {
    method: 'POST',
    headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      id: merchantId,
      lastUpdate: new Date().toISOString(),
      ttl: 3600,
      status: 'AVAILABLE',
      categories: [
        { id: '41678b1b-1902-4f34-b7b0-e2271e93283c', index: 1, name: 'Pizzas', status: 'AVAILABLE' },
        { id: 'd37d1183-d544-4d15-a067-0f0ad38f7680', index: 2, name: 'Bebidas', status: 'AVAILABLE' },
      ],
    }),
  },
)
if (response.status !== 204) console.error(await response.json())
```

```python Python theme={null}
from datetime import datetime, timezone

response = requests.post(
    f"https://api.deliveryvip.com.br/merchant/v3/{merchant_id}/merchantForce",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "id": merchant_id,
        "lastUpdate": datetime.now(timezone.utc).isoformat(),
        "ttl": 3600,
        "status": "AVAILABLE",
        "categories": [
            {"id": "41678b1b-1902-4f34-b7b0-e2271e93283c", "index": 1, "name": "Pizzas", "status": "AVAILABLE"},
            {"id": "d37d1183-d544-4d15-a067-0f0ad38f7680", "index": 2, "name": "Bebidas", "status": "AVAILABLE"},
        ],
    },
)
if response.status_code != 204:
    print(response.json())
```

Depois dessa chamada, a loja tem só essas duas categorias. As demais saem do cardápio. A resposta de sucesso é `204 No Content`, sem corpo.

> [accordion] Exemplo de catálogo completo
>
> ```json theme={null}
> {
>   "id": "7b32f751-5088-4398-bd7b-36c4dc9de062",
>   "lastUpdate": "2023-09-26T18:29:16-03:00",
>   "ttl": 3600,
>   "status": "AVAILABLE",
>   "services": [
>     { "status": "AVAILABLE", "serviceType": "DELIVERY", "serviceTime": 15 },
>     { "status": "AVAILABLE", "serviceType": "TAKEOUT", "serviceTime": 15 }
>   ],
>   "paymentMethods": [
>     {
>       "id": "41678b1b-1902-4f34-b7b0-e2271e93283c",
>       "index": 1,
>       "name": "Visa - Crédito",
>       "mode": "CREDIT",
>       "externalCode": "13",
>       "status": "AVAILABLE"
>     }
>   ],
>   "options": [
>     {
>       "id": "a493064b-f4dd-4780-85da-fc3ecc6b1cb6",
>       "name": "Calabresa",
>       "description": "Molho de tomate, mussarela e calabresa",
>       "externalCode": "152",
>       "status": "AVAILABLE",
>       "image": {
>         "url": "https://exemplo.com/calabresa.jpg",
>         "checksum": "9fOMBLAAaCVVpx03oiViRQ=="
>       }
>     }
>   ],
>   "optionGroups": [
>     {
>       "id": "0f0e34d5-386e-4574-bb14-3615fbe090b1",
>       "name": "Sabores tradicionais",
>       "externalCode": "2",
>       "status": "AVAILABLE",
>       "optionIds": ["a493064b-f4dd-4780-85da-fc3ecc6b1cb6"]
>     }
>   ],
>   "categories": [
>     {
>       "id": "d37d1183-d544-4d15-a067-0f0ad38f7680",
>       "index": 1,
>       "name": "Pizzas",
>       "status": "AVAILABLE"
>     }
>   ],
>   "items": [
>     {
>       "id": "fdbd50f9-63a7-4259-82e6-24ac5b7dc3c2",
>       "index": 1,
>       "name": "Pizza Grande",
>       "description": "Até 2 sabores",
>       "externalCode": "104",
>       "status": "AVAILABLE",
>       "categoryId": "d37d1183-d544-4d15-a067-0f0ad38f7680",
>       "menu": ["DELIVERY", "TAKEOUT", "INDOOR"],
>       "price": { "value": 50.0, "originalValue": 50.0, "currency": "BRL" },
>       "image": {
>         "url": "https://exemplo.com/pizza.jpg",
>         "checksum": "9fOMBLAAaCVVpx03oiViRQ=="
>       },
>       "modifiers": [
>         {
>           "id": "79d89952-67cd-43e9-98a4-67b5e3357be9",
>           "index": 1,
>           "name": "Escolha os sabores",
>           "externalCode": "123",
>           "status": "AVAILABLE",
>           "rule": "APPORTIONMENT",
>           "minPermitted": 1,
>           "maxPermitted": 2,
>           "optionGroups": [
>             {
>               "optionGroupId": "0f0e34d5-386e-4574-bb14-3615fbe090b1",
>               "index": 1,
>               "options": [
>                 {
>                   "optionId": "a493064b-f4dd-4780-85da-fc3ecc6b1cb6",
>                   "index": 1,
>                   "status": "AVAILABLE",
>                   "price": { "value": 0.0, "originalValue": 0.0, "currency": "BRL" }
>                 }
>               ]
>             }
>           ]
>         }
>       ]
>     }
>   ]
> }
> ```

## Boas práticas

> [!TIP]
>
> * Gere o corpo a partir do catálogo completo do seu sistema, nunca de uma lista parcial ou filtrada.
> * Omita as chaves dos tipos que você não quer reescrever. Uma chave ausente não remove nada; uma lista vazia remove tudo.
> * Para mudanças do dia a dia, prefira o [update](/docs/guides/merchant/catalog-and-services/actions/update.md) ou o [upsert](/docs/guides/merchant/catalog-and-services/actions/upsert.md): são menores e não arriscam remover objetos.
> * Depois de um force, confira o resultado com o [GET da loja](/docs/guides/merchant/catalog-and-services/details.md).


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