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:
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.
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/:idPedido 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
/ordersCria 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
/menuCardá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
/couponsLista e cria cupons.
Escopo
read / read_write - GET/PUT/DELETE
/coupons/:idConsulta, 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/:idUma 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_paymentreceivedacceptedpreparingreadydispatcheddeliveredcollectedcancelledrejected
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.
{
"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.
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);
}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