Autenticação
OAuth client credentials, escopos, expiração de 3600 s, credencial pausada ou revogada e limites do endpoint de token.
A API usa OAuth 2.0 com o fluxo client credentials: o seu sistema troca client_id e client_secret por um token de acesso e envia esse token em todas as chamadas. Não há login de usuário, redirecionamento nem refresh token.
- Requisição do seu sistema, sempre por HTTPS
- Resposta 2xx
- 401 invalid_token: token expirado ou credencial pausada/revogada
- Uma credencial atende uma loja; N lojas são N credenciais e N tokens
- Seu sistema chama
POST /oauth/tokencom a credencial. - A API responde com um JWT válido por 3600 segundos e os escopos concedidos.
- Seu sistema envia o token em
Authorization: Bearerem cada chamada. - Antes de o token expirar, seu sistema pede outro.
Obtendo o token
POST https://api.meupedido.io/open-delivery/oauth/tokenO caminho POST /v1/oauth/token é um alias e responde igual.
A credencial pode ser enviada de três formas. O formulário é a forma canônica do OAuth 2.0 e a que a maioria das bibliotecas usa por padrão.
Content-Type: application/x-www-form-urlencoded, com os três campos no corpo.
curl -X POST https://api.meupedido.io/open-delivery/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=mp_7f3a9c1e5b2d4a6f8e0c1b3d" \
-d "client_secret=$CLIENT_SECRET"Qualquer outro Content-Type responde 415.
Resposta
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjaGFudF9pZCI6IjZkMmY0YzhhLTFiM2UtNGY1YS05YzdkLTJlOGIwYTFmM2M1ZCIsImNsaWVudF9pZCI6Im1wXzdmM2E5YzFlNWIyZDRhNmY4ZTBjMWIzZCIsInNjb3BlIjoib3JkZXJzOnJlYWQgb3JkZXJzOndyaXRlIG1lcmNoYW50OnJlYWQgY2F0YWxvZzpyZWFkIn0.Q1w7Xy0Yt3cJ5w8NnZK2p9Vb4Ls6Hd1Ff0Rr8Mm3Aa0",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjaGFudF9pZCI6IjZkMmY0YzhhLTFiM2UtNGY1YS05YzdkLTJlOGIwYTFmM2M1ZCIsImNsaWVudF9pZCI6Im1wXzdmM2E5YzFlNWIyZDRhNmY4ZTBjMWIzZCIsInNjb3BlIjoib3JkZXJzOnJlYWQgb3JkZXJzOndyaXRlIG1lcmNoYW50OnJlYWQgY2F0YWxvZzpyZWFkIn0.Q1w7Xy0Yt3cJ5w8NnZK2p9Vb4Ls6Hd1Ff0Rr8Mm3Aa0",
"token_type": "bearer",
"tokenType": "bearer",
"expires_in": 3600,
"expiresIn": 3600,
"scope": "orders:read orders:write merchant:read catalog:read"
}Cada campo vem em snake_case (como o RFC 6749 define) e em camelCase (como a especificação Open Delivery escreve). Os valores são idênticos; leia o que a sua biblioteca esperar.
| Campo | Significado |
|---|---|
access_token | O JWT a enviar em Authorization: Bearer |
token_type | Sempre bearer |
expires_in | Validade em segundos, sempre 3600 |
scope | Os escopos da credencial, separados por espaço |
O token é um JWT assinado com HS256 pelo MeuPedido. Ele carrega as claims merchant_id (a loja), client_id e scope. Trate-o como opaco: não dependa do formato interno, e nunca tente validá-lo localmente, porque a chave de assinatura não é pública.
Em código
curl -X POST https://api.meupedido.io/open-delivery/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET"Usando o token
Envie o token no header Authorization de todas as chamadas à API.
curl "https://api.meupedido.io/open-delivery/v1/events:polling" \
-H "Authorization: Bearer $TOKEN"Sem o header, a resposta é 401 com corpo vazio e o header WWW-Authenticate.
Expiração e renovação
O token vale por 3600 segundos a partir da emissão. Não existe refresh token: renovar é chamar POST /oauth/token de novo.
A estratégia recomendada:
- Guarde o token junto com o instante de expiração calculado a partir de
expires_in. - Renove antes de expirar, com uma margem de alguns minutos, em vez de esperar o
401. - Se ainda assim uma chamada responder
401, peça um token novo uma vez e repita a chamada. Se o endpoint de token também responder401 invalid_client, a credencial foi pausada ou revogada: pare e avise o operador. - Um token por credencial, compartilhado entre as threads ou workers do seu processo. Pedir um token a cada requisição esgota o limite do endpoint.
Escopos
Os escopos são definidos pelo lojista ao criar a credencial e não podem ser alterados depois. O token carrega exatamente os escopos da credencial.
| Escopo | Libera |
|---|---|
orders:read | GET /v1/events:polling, POST /v1/events/acknowledgment, GET /v1/orders/{orderId} |
orders:write | POST /v1/orders/{orderId}/confirm e as demais ações |
merchant:read | GET /v1/merchant/{merchantId} |
catalog:read | GET /v1/merchant/{merchantId}/menus |
Uma chamada a um endpoint cujo escopo a credencial não tem responde:
{
"error": "insufficient_scope",
"message": "A credencial não possui o escopo orders:write."
}Credencial pausada ou revogada
O lojista pode pausar, retomar ou revogar a credencial a qualquer momento no painel. O efeito é imediato e vale para tokens já emitidos, mesmo dentro do prazo de validade:
{
"error": "invalid_token",
"message": "A credencial foi pausada ou revogada pelo lojista."
}Com a credencial pausada, os eventos continuam sendo acumulados no feed e ficam disponíveis assim que ela for retomada. Revogação é permanente: para voltar, o lojista cria outra credencial.
Erros do endpoint de token
O endpoint de token responde no formato do RFC 6749: error com um código estável e error_description com o texto em pt-BR. É o formato que toda biblioteca OAuth 2.0 já sabe ler, e por isso é diferente do error e message das demais rotas.
| Status | error | Quando |
|---|---|---|
400 | unsupported_grant_type | grant_type diferente de client_credentials |
400 | invalid_request | Falta client_id, client_secret ou grant_type, ou o corpo está malformado |
401 | invalid_client | Credencial inexistente, segredo errado, pausada ou revogada |
413 | invalid_request | Corpo acima de 4 KB. Um pedido de token tem só três campos |
415 | invalid_request | Content-Type diferente de formulário ou JSON |
429 | rate_limit_exceeded | Limite do endpoint atingido; espere o Retry-After |
{
"error": "invalid_request",
"error_description": "Informe client_id e client_secret."
}O 401 vem só com o código, de propósito. Credencial inexistente e segredo errado recebem exatamente a mesma resposta, para o endpoint não revelar quais client_id existem:
{
"error": "invalid_client"
}Limites do endpoint de token
O endpoint de token tem dois limites independentes, ambos respondendo 429 com Retry-After: 60:
- 60 requisições por minuto por endereço IP. Um único processo bem comportado nunca chega perto disso. O
429vem comerroremessage. - 10 falhas por minuto por credencial. Se o seu sistema entrar em loop com um segredo errado, ele vai bater neste limite antes de qualquer outro, e o
429vem comerroreerror_description. O limite vale só para o segredo errado: o segredo correto continua emitindo token normalmente, então ninguém que conheça apenas o seuclient_idconsegue derrubar a sua integração.
Os demais endpoints têm o limite geral de 600 requisições por minuto por credencial, descrito em Boas práticas.
Segurança do segredo
- O
client_secreté mostrado uma única vez, ao criar a credencial. Guarde-o em um cofre de segredos ou em variável de ambiente. - Nunca o coloque em código, repositório, log, mensagem de erro, URL ou ticket de suporte. O suporte nunca pede o segredo.
- Use uma credencial por loja e por sistema. Se um segredo vazar, o lojista revoga só aquela credencial.
- Toda comunicação é HTTPS. Não há endpoint HTTP.
- CORS está liberado apenas para o playground deste portal. A integração é servidor a servidor: chamar a API a partir de um navegador expõe o segredo e é bloqueado.
Próximos passos
- Primeira integração em 10 minutos: use o token para receber o primeiro pedido.
- Polling: o loop de consulta de eventos.
- Boas práticas: limites, erros e backoff.