Pular para o conteúdo

Desenvolvedores · API v1

API pública e webhooks

Para ERP, CRM, logística, BI ou o sistema do próprio restaurante. Consulte pedidos, cardápio, clientes e notas, crie pedidos de canais externos e receba cada mudança por webhook assinado.

https://api.restfood.com.br/v1

Visão geral

Base
https://api.restfood.com.br/v1
Isolamento
Cada token pertence a uma loja e só enxerga dados dessa loja, com o mesmo isolamento no banco que o painel usa.
Dinheiro
Sempre em centavos inteiros, em campos terminados em Cents.
Datas
ISO 8601 com offset, por exemplo 2026-10-28T20:14:03-03:00.
Paginação
?page=1&perPage=50 (máximo 100). Resposta { items, page, perPage, total }.
Erros
{ code, message, fields?, requestId }. Envie o requestId ao suporte quando precisar de ajuda.

Autenticação

Envie o token em toda requisição, no cabeçalho:

Cabeçalho
Authorization: Bearer rf_live_<40 caracteres>

O dono da loja gera o token em Configurações → Integrações. O token aparece uma única vez e fica guardado apenas como hash SHA-256: se perder, gere outro.

  • readConsultas.
  • read_writeConsultas e também cria pedido, muda status, mexe em cupom e emite nota.
Exemplo
curl https://api.restfood.com.br/v1/orders?status=received \
  -H "Authorization: Bearer $RESTFOOD_TOKEN"

Limites

120 requisições por minuto por token. Ao exceder, a API responde 429 com o cabeçalho Retry-After em segundos.

Pedidos

POST /orders exige o cabeçalho Idempotency-Key. Reenviar a mesma chave devolve o mesmo resultado, sem pedido duplicado.

  • GET/orders?status=&date=YYYY-MM-DD&updatedSince=&externalCode=&page=

    Lista os pedidos da loja.

    Escopo read

  • GET/orders/:id

    Pedido completo: itens com preço da época, complementos, frações, cliente, endereço, pagamentos, linha do tempo, descontos, totais e avaliação.

    Escopo read

  • POST/orders

    Cria pedido vindo de canal externo (channel: "integration") com externalCode único por loja. O preço é recalculado no servidor; total divergente devolve 409 price_changed.

    Escopo read_write

  • PUT/orders/:id/status

    { status, reason?, trackingUrl? }. Segue a mesma máquina de estados do painel.

    Escopo read_write

Cadastro e operação

  • GET/menu

    Cardápio publicado.

    Escopo read

  • GET/customers?q=&page=

    Clientes da loja, com saldo de cashback e fiado.

    Escopo read

  • GET/delivery-areas

    Áreas de entrega com taxa, pedido mínimo e prazo.

    Escopo read

  • GET/ratings?from=&to=&page=

    Avaliações dos pedidos.

    Escopo read

  • GET/POST/coupons

    Lista e cria cupons.

    Escopo read / read_write

  • GET/PUT/DELETE/coupons/:id

    Consulta, altera e remove um cupom.

    Escopo read / read_write

  • GET/financial/accounts?type=payable|receivable&status=&from=&to=

    Contas a pagar e a receber.

    Escopo read

Fiscal

  • GET/fiscal/documents?orderId=&status=

    Notas fiscais (NFC-e, NF-e, NFS-e).

    Escopo read

  • GET/fiscal/documents/:id

    Uma nota: status, chave, protocolo e links de XML e DANFE.

    Escopo read

  • POST/fiscal/nfce

    { orderId, customerDocument? }. Coloca a emissão na fila e responde 202 com o documento em processing.

    Escopo read_write

Status do pedido

Valores possíveis em status, na ordem em que um pedido costuma passar por eles:

  • pending_payment
  • received
  • accepted
  • preparing
  • ready
  • dispatched
  • delivered
  • collected
  • cancelled
  • rejected

Webhooks

Eventos

  • order.createdPedido entrou na loja.
  • order.updatedItens, valores ou dados do pedido mudaram.
  • order.status_changedO pedido mudou de etapa.
  • order.ratedO cliente avaliou o pedido.
  • fiscal.document_authorizedA nota foi autorizada.
  • fiscal.document_rejectedA nota foi rejeitada.
Corpo de exemplo
{
  "id": "evt_0193...",
  "event": "order.status_changed",
  "createdAt": "2026-10-28T20:14:03-03:00",
  "storeId": "0193...",
  "data": {
    "orderId": "0193...",
    "dailyNumber": 42,
    "status": "preparing",
    "previousStatus": "accepted"
  }
}

Cabeçalhos

  • X-RestFood-Signaturet=<unix>,v1=<hex>, onde v1 = HMAC_SHA256(segredo_do_endpoint, "<t>.<corpo>").
  • X-RestFood-EventNome do evento, igual ao campo event do corpo.
  • X-RestFood-DeliveryId da entrega. Use para descartar reenvios que você já processou.

Entrega e novas tentativas

  • Cadastre URLs HTTPS em Configurações → Integrações e escolha os eventos de cada uma.
  • Rejeite a mensagem se o t da assinatura tiver mais de 5 minutos.
  • Responda 2xx em até 10 segundos. Processe o trabalho pesado depois, numa fila sua.
  • Falhou: 6 novas tentativas com espera crescente (30 s, 2 min, 10 min, 30 min, 2 h e 6 h). Depois disso a entrega fica como falha no painel, com botão de reenvio.
  • O painel mostra as últimas entregas de cada endpoint com status HTTP e tempo de resposta, e tem o botão Enviar teste.

Verificar assinatura em Node.js

Calcule o HMAC SHA-256 de <t>.<corpo> com o segredo do endpoint e compare em tempo constante com timingSafeEqual. Use o corpo bruto: reserializar o JSON muda os bytes e invalida a assinatura.

verify.js
import { createHmac, timingSafeEqual } from 'node:crypto';

const TOLERANCE_SECONDS = 5 * 60;

/**
 * Confere o cabeçalho X-RestFood-Signature.
 * rawBody precisa ser o corpo exatamente como chegou, antes de JSON.parse.
 */
export function verifyRestFoodSignature(rawBody, header, secret) {
  const parts = Object.fromEntries(
    String(header ?? '')
      .split(',')
      .map((part) => part.trim().split('=')),
  );
  const timestamp = Number(parts.t);
  if (!Number.isInteger(timestamp) || typeof parts.v1 !== 'string') return false;

  const age = Math.abs(Math.floor(Date.now() / 1000) - timestamp);
  if (age > TOLERANCE_SECONDS) return false;

  const expected = createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest();
  const received = Buffer.from(parts.v1, 'hex');

  return received.length === expected.length && timingSafeEqual(received, expected);
}
server.js · Express
import express from 'express';
import { verifyRestFoodSignature } from './verify.js';

const app = express();
const seen = new Set(); // em produção, use o seu banco ou Redis

app.post('/webhooks/restfood', express.raw({ type: 'application/json' }), (req, res) => {
  const ok = verifyRestFoodSignature(
    req.body.toString('utf8'),
    req.get('X-RestFood-Signature'),
    process.env.RESTFOOD_WEBHOOK_SECRET,
  );
  if (!ok) return res.status(401).end();

  const delivery = req.get('X-RestFood-Delivery');
  if (seen.has(delivery)) return res.status(200).end();
  seen.add(delivery);

  const event = JSON.parse(req.body.toString('utf8'));
  // Coloque event numa fila e responda logo: o limite é de 10 segundos.
  res.status(200).end();
});

Vai integrar um sistema maior?

Conte o que precisa e a equipe ajuda a desenhar a integração.

Falar com a equipe