- Visao Geral
- Autenticacao
- Fluxo de Integracao de Pedidos
- Endpoints Detalhados
- searchCriteria — Guia Completo
- Fluxo de Status do Pedido
- Boas Praticas
- Exemplos de Payloads Completos
- Tratamento de Erros
- Configuracao do Postman
Este guia documenta a integracao entre um ERP e o Magento 2.4.8 via REST API para sincronizacao de pedidos. O foco e o cenario onde:
- O Magento e o canal de vendas (e-commerce)
- O ERP e o sistema de gestao (processa pedidos, estoque, faturamento, logistica)
┌──────────┐ ┌──────────────┐
│ │ 1. Obter Token │ │
│ │ ───────────────────────────>│ │
│ │ 2. Token Bearer │ │
│ │ <───────────────────────────│ Magento 2.4 │
│ │ │ REST API │
│ │ 3. GET /orders │ │
│ │ ───────────────────────────>│ │
│ │ 4. Lista de Pedidos │ │
│ │ <───────────────────────────│ │
│ │ │ │
│ ERP │ 5. GET /orders/{id} │ │
│ │ ───────────────────────────>│ │
│ │ 6. Recebe detalhe do pedido│ │
│ │ <───────────────────────────│ │
│ │ │ │
│ │ 7. POST /order/{id}/invoice│ │
│ │ ───────────────────────────>│ │
│ │ 8. Invoice criada │ │
│ │ <───────────────────────────│ │
│ │ │ │
│ │ 9. POST /order/{id}/ship │ │
│ │ ───────────────────────────>│ │
│ │ 10. Shipment criado │ │
│ │ <───────────────────────────│ │
└──────────┘ └──────────────┘
- Base URL:
http://seu-magento.com/rest/V1 - Content-Type:
application/json - Autenticacao: Bearer Token
- Paginacao: via
searchCriteria
POST /rest/V1/integration/admin/token
Content-Type: application/json
{
"username": "admin",
"password": "sua_senha_admin"
}Response (string pura, nao JSON):
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxfQ..."
Inclua o token no header de todas as requests:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json- Nao hardcode o token — Ele expira. Obtenha um novo a cada sessao ou configure um Integration Token permanente no admin do Magento
- Integration Token (recomendado para ERP): No admin do Magento, va em System > Extensions > Integrations e crie uma integracao com as permissoes necessarias. O token gerado nao expira
- Armazene com seguranca — Use variaveis de ambiente ou cofre de credenciais
┌─────────────┐
│ Pedido │
│ Criado │
│ (pending) │
└──────┬──────┘
│
┌──────▼──────┐
│ ERP obtem │
│ pedido via │
│ GET /orders│
└──────┬──────┘
│
┌──────▼──────┐
│ ERP valida │
│ pagamento │
│ e estoque │
└──────┬──────┘
│
┌────────┴────────┐
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ Aprovado │ │ Rejeitado │
└──────┬──────┘ └──────┬──────┘
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ POST │ │ POST │
│ /order/id/ │ │ /order/id/ │
│ invoice │ │ cancel │
│ (faturar) │ │ (cancelar) │
└──────┬──────┘ └─────────────┘
│
┌────────▼────────┐
│ ERP separa │
│ estoque e │
│ despacha │
└────────┬────────┘
│
┌──────▼──────┐
│ POST │
│ /order/id/ │
│ ship │
│ (enviar com │
│ tracking) │
└──────┬──────┘
│
┌──────▼──────┐
│ Pedido │
│ Complete │
│ (complete) │
└─────────────┘
-
Polling de pedidos (a cada 5 min ou via webhook)
GET /rest/V1/orders?searchCriteria[filter_groups][0][filters][0][field]=status &searchCriteria[filter_groups][0][filters][0][value]=pending &searchCriteria[filter_groups][0][filters][0][condition_type]=eq &searchCriteria[sortOrders][0][field]=created_at &searchCriteria[sortOrders][0][direction]=ASC &searchCriteria[pageSize]=100 -
Para cada pedido pendente:
- Obter detalhes completos:
GET /rest/V1/orders/{order_id} - Validar pagamento e dados no ERP
- Adicionar comentario:
POST /rest/V1/orders/{order_id}/comments
- Obter detalhes completos:
-
Faturar (apos confirmar pagamento):
POST /rest/V1/order/{order_id}/invoice -
Enviar (apos despachar):
POST /rest/V1/order/{order_id}/ship -
Tratar excecoes:
- Cancelamento:
POST /rest/V1/orders/{order_id}/cancel - Devolucao:
POST /rest/V1/order/{order_id}/refund - Hold:
POST /rest/V1/orders/{order_id}/hold
- Cancelamento:
GET /rest/V1/orders?searchCriteria[pageSize]=20&searchCriteria[currentPage]=1
Authorization: Bearer {token}Response:
{
"items": [
{
"entity_id": 1,
"increment_id": "000000001",
"status": "pending",
"state": "new",
"customer_email": "cliente@email.com",
"customer_firstname": "Joao",
"customer_lastname": "Silva",
"grand_total": 159.90,
"base_grand_total": 159.90,
"order_currency_code": "BRL",
"subtotal": 149.90,
"shipping_amount": 10.00,
"tax_amount": 0.00,
"discount_amount": 0.00,
"total_qty_ordered": 2,
"created_at": "2026-03-28 10:30:00",
"updated_at": "2026-03-28 10:30:00",
"store_id": 1,
"items": [
{
"item_id": 1,
"sku": "produto-sku-001",
"name": "Nome do Produto",
"qty_ordered": 2,
"price": 74.95,
"row_total": 149.90,
"product_type": "simple"
}
],
"billing_address": {
"firstname": "Joao",
"lastname": "Silva",
"street": ["Rua Exemplo, 123"],
"city": "Sao Paulo",
"region": "Sao Paulo",
"postcode": "01000-000",
"country_id": "BR",
"telephone": "(11) 99999-9999",
"vat_id": "12.345.678/0001-90"
},
"extension_attributes": {
"shipping_assignments": [
{
"shipping": {
"address": {
"firstname": "Joao",
"lastname": "Silva",
"street": ["Rua Exemplo, 123"],
"city": "Sao Paulo",
"region": "Sao Paulo",
"postcode": "01000-000",
"country_id": "BR"
},
"method": "flatrate_flatrate",
"total": {
"base_shipping_amount": 10.00,
"shipping_amount": 10.00
}
}
}
]
},
"payment": {
"method": "checkmo",
"additional_information": []
},
"status_histories": []
}
],
"total_count": 1,
"search_criteria": {
"page_size": 20,
"current_page": 1
}
}GET /rest/V1/orders/{order_id}
Authorization: Bearer {token}Retorna o mesmo objeto do item na lista, mas completo com todas as informacoes.
POST /rest/V1/order/{order_id}/invoice
Authorization: Bearer {token}
Content-Type: application/json
{
"capture": true,
"notify": true,
"appendComment": true,
"comment": {
"comment": "NF-e 123456 emitida",
"is_visible_on_front": 1
},
"items": []
}Invoice completo (todos os itens): Use items: [] (array vazio)
Invoice parcial: Especifique itens:
{
"capture": true,
"items": [
{"order_item_id": 1, "qty": 1},
{"order_item_id": 3, "qty": 2}
]
}Response:
{
"entity_id": 1,
"increment_id": "000000001",
"order_id": 1,
"state": 2,
"grand_total": 159.90,
"items": [...]
}POST /rest/V1/order/{order_id}/ship
Authorization: Bearer {token}
Content-Type: application/json
{
"items": [],
"notify": true,
"appendComment": true,
"comment": {
"comment": "Pedido despachado",
"is_visible_on_front": 1
},
"tracks": [
{
"track_number": "BR123456789XX",
"carrier_code": "custom",
"title": "Correios SEDEX"
}
]
}Campos do tracking:
| Campo | Descricao | Exemplo |
|---|---|---|
track_number |
Codigo de rastreio | BR123456789XX |
carrier_code |
Codigo da transportadora | correios, custom, jadlog |
title |
Nome exibido | Correios SEDEX, Jadlog |
POST /rest/V1/orders/{order_id}/comments
Authorization: Bearer {token}
Content-Type: application/json
{
"statusHistory": {
"comment": "Pedido importado no ERP - Protocolo #12345",
"is_customer_notified": 0,
"is_visible_on_front": 0,
"status": "processing"
}
}Nota: Se o campo status for omitido, apenas o comentario e adicionado sem alterar o status.
POST /rest/V1/orders/{order_id}/cancel
Authorization: Bearer {token}
Content-Type: application/json
{}Response: true (booleano)
POST /rest/V1/order/{order_id}/refund
Authorization: Bearer {token}
Content-Type: application/json
{
"notify": true,
"comment": {
"comment": "Devolucao autorizada",
"is_visible_on_front": 1
},
"items": [],
"arguments": {
"shipping_amount": 0,
"adjustment_positive": 0,
"adjustment_negative": 0
}
}POST /rest/V1/orders/{order_id}/hold
POST /rest/V1/orders/{order_id}/unhold
Authorization: Bearer {token}
Content-Type: application/json
{}O searchCriteria e o sistema de filtragem e paginacao do Magento. Funciona tanto como query params (GET) quanto no body (POST).
searchCriteria[filter_groups][{group_index}][filters][{filter_index}][field]={campo}
searchCriteria[filter_groups][{group_index}][filters][{filter_index}][value]={valor}
searchCriteria[filter_groups][{group_index}][filters][{filter_index}][condition_type]={condicao}
| Condicao | Significado | Exemplo |
|---|---|---|
eq |
Igual a | status eq pending |
neq |
Diferente de | status neq canceled |
gt |
Maior que | entity_id gt 100 |
gteq |
Maior ou igual | updated_at gteq 2026-01-01 |
lt |
Menor que | grand_total lt 500 |
lteq |
Menor ou igual | entity_id lteq 1000 |
like |
LIKE SQL | customer_email like %@gmail.com |
nlike |
NOT LIKE | status nlike %cancel% |
in |
Em um conjunto | status in pending,processing |
nin |
Nao em um conjunto | status nin canceled,closed |
null |
E nulo | customer_id null |
notnull |
Nao e nulo | customer_id notnull |
finset |
FIND_IN_SET | category_ids finset 3,5 |
searchCriteria[pageSize]=50 # Itens por pagina (max 500)
searchCriteria[currentPage]=1 # Pagina atual (comeca em 1)
searchCriteria[sortOrders][0][field]=created_at # Campo de ordenacao
searchCriteria[sortOrders][0][direction]=DESC # ASC ou DESC
GET /rest/V1/orders?
searchCriteria[filter_groups][0][filters][0][field]=status
&searchCriteria[filter_groups][0][filters][0][value]=pending
&searchCriteria[filter_groups][0][filters][0][condition_type]=eq
&searchCriteria[pageSize]=100
&searchCriteria[currentPage]=1
&searchCriteria[sortOrders][0][field]=created_at
&searchCriteria[sortOrders][0][direction]=ASC
GET /rest/V1/orders?
searchCriteria[filter_groups][0][filters][0][field]=updated_at
&searchCriteria[filter_groups][0][filters][0][value]=2026-03-28 00:00:00
&searchCriteria[filter_groups][0][filters][0][condition_type]=gteq
&searchCriteria[pageSize]=200
GET /rest/V1/orders?
searchCriteria[filter_groups][0][filters][0][field]=customer_email
&searchCriteria[filter_groups][0][filters][0][value]=cliente@email.com
&searchCriteria[filter_groups][0][filters][0][condition_type]=eq
GET /rest/V1/orders?
searchCriteria[filter_groups][0][filters][0][field]=status
&searchCriteria[filter_groups][0][filters][0][value]=pending
&searchCriteria[filter_groups][0][filters][0][condition_type]=eq
&searchCriteria[filter_groups][0][filters][1][field]=status
&searchCriteria[filter_groups][0][filters][1][value]=processing
&searchCriteria[filter_groups][0][filters][1][condition_type]=eq
Nota: Filters dentro do mesmo
filter_groupusam condicao OR. Filter groups diferentes usam condicao AND.
No Magento, state e status sao conceitos diferentes:
- State: Estado interno do pedido (valor tecnico, controla o fluxo)
- Status: Label visivel (pode ser customizado, mas geralmente reflete o state)
| State | Status Padrao | Descricao |
|---|---|---|
new |
pending |
Pedido recem-criado, aguardando pagamento |
pending_payment |
pending_payment |
Aguardando confirmacao de pagamento (gateways) |
processing |
processing |
Pagamento confirmado, pedido em separacao |
complete |
complete |
Pedido faturado e enviado |
closed |
closed |
Pedido com devolucao total |
canceled |
canceled |
Pedido cancelado |
holded |
on_hold |
Pedido em espera |
payment_review |
payment_review |
Pagamento em revisao |
new/pending
│
├──[pagamento confirmado]──> processing
│ │
│ ┌───────────┤
│ │ │
│ [criar invoice] [criar shipment]
│ │ │
│ ▼ │
│ processing │
│ (faturado) │
│ │ │
│ └───┬───────┘
│ │
│ [ambos criados]
│ │
│ ▼
│ complete
│
├──[pagamento rejeitado]──> canceled
│
├──[hold]──> holded
│ │
│ [unhold]──> retorna ao state anterior
│
└──[fraude]──> payment_review
│
[cancelar]──> canceled
| Acao | Status Antes | Status Depois |
|---|---|---|
| Criar Invoice | pending |
processing |
| Criar Invoice + Ship | pending |
complete |
| Criar Shipment | processing |
complete (se ja faturado) |
| Cancelar | pending |
canceled |
| Hold | Qualquer (exceto complete/closed) | holded |
| Credit Memo Total | complete |
closed |
| Credit Memo Parcial | complete |
complete |
Polling (recomendado para inicio):
- Facil de implementar
- Use
updated_at+gteqpara buscar incrementos - Intervalo recomendado: 5 minutos
- Sempre ordene por
created_at ASCpara processar na ordem
Webhooks (avancado):
- O Magento 2.4 suporta Async API e webhooks via modulos de terceiros
- Menos latencia, mas mais complexidade
- Considere usar o modulo Amasty Webhooks ou implementar observers customizados
// Sempre use paginacao
pageSize = 100 // Max recomendado por request
currentPage = 1 // Comeca em 1
// Calcule o total de paginas:
total_pages = ceil(total_count / pageSize)- Verifique se o pedido ja foi processado antes de criar invoice/shipment
- Use o
status_historiespara rastrear comentarios ja adicionados - Armazene o
entity_iddo Magento no ERP para evitar duplicidade
// Estrategia de retry
max_retries = 3
retry_delay = [5s, 30s, 120s] // Backoff exponencial
// Codigos de erro trataveis:
// 401 → Renovar token e tentar novamente
// 404 → Pedido nao encontrado, pular
// 500 → Retry com backoff
// 400 → Erro de validacao, logar e nao tentar novamente
- Nunca exponha credenciais da API no codigo-fonte
- Use HTTPS em producao
- Limite as permissoes do token de integracao ao minimo necessario
- Regenere tokens periodicamente
- Logue todas as chamadas de API para auditoria
- Evite
pageSize > 200— pode causar timeout - Use campos especificos nos filtros ao inves de buscar tudo
- Para pedidos com muitos itens, considere processar em lotes
- Cache o token de autenticacao ate que expire
- Considere usar a API Async para operacoes em massa (
/rest/async/V1/...)
Este Magento possui multi-store (unimarka e unisul). Para integracao com ERP:
- Filtre por
store_idpara separar pedidos de cada loja - Use o endpoint
GET /rest/V1/store/storeConfigspara listar as stores disponiveis - O
store_idesta disponivel em cada pedido retornado pela API
# Pseudocodigo - Sincronizacao de pedidos do Magento para o ERP
import requests
from datetime import datetime
BASE_URL = "http://seu-magento.com/rest/V1"
USERNAME = "erp_user"
PASSWORD = "erp_password"
# 1. Autenticar
response = requests.post(f"{BASE_URL}/integration/admin/token", json={
"username": USERNAME,
"password": PASSWORD
})
token = response.json()
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
# 2. Buscar pedidos atualizados desde a ultima sincronizacao
last_sync = "2026-03-28 00:00:00" # Armazenar no ERP a data da ultima sinc
response = requests.get(
f"{BASE_URL}/orders",
headers=headers,
params={
"searchCriteria[filter_groups][0][filters][0][field]": "updated_at",
"searchCriteria[filter_groups][0][filters][0][value]": last_sync,
"searchCriteria[filter_groups][0][filters][0][condition_type]": "gteq",
"searchCriteria[sortOrders][0][field]": "updated_at",
"searchCriteria[sortOrders][0][direction]": "ASC",
"searchCriteria[pageSize]": "100"
}
)
orders = response.json()["items"]
# 3. Processar cada pedido
for order in orders:
order_id = order["entity_id"]
status = order["status"]
if status == "pending":
# Importar pedido no ERP
erp_import_order(order)
# Adicionar comentario de confirmacao
requests.post(
f"{BASE_URL}/orders/{order_id}/comments",
headers=headers,
json={
"statusHistory": {
"comment": "Pedido importado no ERP com sucesso",
"is_customer_notified": 0,
"is_visible_on_front": 0,
"status": "processing"
}
}
)
elif status == "processing":
# Verificar se ja foi faturado no ERP
if erp_is_invoiced(order["increment_id"]):
# Verificar se precisa criar invoice no Magento
invoices = requests.get(
f"{BASE_URL}/invoices",
headers=headers,
params={
"searchCriteria[filter_groups][0][filters][0][field]": "order_id",
"searchCriteria[filter_groups][0][filters][0][value]": order_id,
"searchCriteria[filter_groups][0][filters][0][condition_type]": "eq"
}
).json()
if invoices["total_count"] == 0:
# Criar invoice
requests.post(
f"{BASE_URL}/order/{order_id}/invoice",
headers=headers,
json={"capture": True, "notify": True, "items": []}
)
# Verificar se ja foi despachado
if erp_is_shipped(order["increment_id"]):
tracking = erp_get_tracking(order["increment_id"])
requests.post(
f"{BASE_URL}/order/{order_id}/ship",
headers=headers,
json={
"items": [],
"notify": True,
"tracks": [{
"track_number": tracking["code"],
"carrier_code": tracking["carrier"],
"title": tracking["carrier_name"]
}]
}
)GET /rest/V1/orders?
searchCriteria[filter_groups][0][filters][0][field]=increment_id
&searchCriteria[filter_groups][0][filters][0][value]=000000123
&searchCriteria[filter_groups][0][filters][0][condition_type]=eq
Authorization: Bearer {token}{
"capture": true,
"notify": true,
"appendComment": true,
"comment": {
"extension_attributes": {},
"comment": "NF-e autorizada: Numero 123456, Serie 1, Chave: 35260312345678000195550010000123461123456789",
"is_visible_on_front": 1
},
"items": []
}{
"items": [],
"notify": true,
"tracks": [
{
"track_number": "BR111111111XX",
"carrier_code": "correios",
"title": "Correios PAC"
},
{
"track_number": "JAD123456789",
"carrier_code": "jadlog",
"title": "Jadlog Expresso"
}
]
}| Codigo | Significado | Acao |
|---|---|---|
200 |
Sucesso | Processar response |
400 |
Bad Request | Verificar payload, nao tentar novamente |
401 |
Unauthorized | Renovar token e tentar novamente |
403 |
Forbidden | Verificar permissoes do token |
404 |
Not Found | Recurso nao existe, pular |
500 |
Internal Server Error | Retry com backoff |
503 |
Service Unavailable | Retry com backoff |
{
"message": "The consumer isn't authorized to access %resources.",
"parameters": {
"resources": "Magento_Sales::sales"
}
}| Erro | Causa | Solucao |
|---|---|---|
"Order is not invoiceable" |
Pedido ja faturado ou status nao permite | Verificar status antes de faturar |
"You can't create a shipment without products" |
items vazio e pedido sem itens |
Verificar items do pedido |
"The order already has an invoice" |
Invoice ja existe | Verificar invoices existentes |
"You can't cancel the order" |
Pedido nao pode ser cancelado | Verificar se tem invoice/shipment |
"The consumer isn't authorized" |
Token invalido/expirado | Renovar token |
"No such entity with %fieldName = %fieldValue" |
ID nao encontrado | Verificar o ID passado |
- Abra o Postman
- Clique em Import (botao no canto superior esquerdo)
- Selecione o arquivo
magento-erp-orders.postman_collection.json - A collection aparecera no sidebar esquerdo
- Clique na collection Magento 2.4 ERP - Pedidos
- Va na aba Variables
- Configure:
base_url: URL do seu Magento (ex:http://localhost:8001)admin_token: (sera preenchido automaticamente pela request de auth)order_id: ID de um pedido existente para testesincrement_id: Numero visivel de um pedido para testes
- Primeiro: Execute "Obter Admin Token" — o token sera salvo automaticamente
- Segundo: Execute "Listar Pedidos Recentes" — copie um
entity_idparaorder_id - Terceiro: Execute "Detalhes do Pedido por ID" para ver todos os dados
- Quarto: Execute "Criar Invoice" para faturar o pedido
- Quinto: Execute "Criar Shipment com Tracking" para enviar
Para evitar renovar o token a cada sessao:
- No admin do Magento: System > Extensions > Integrations
- Clique em Add New Integration
- Preencha nome e email
- Na aba Available API, selecione:
Sales > Orders(todas as operacoes)Sales > Invoices(todas as operacoes)Sales > Shipments(todas as operacoes)Sales > Credit Memos(todas as operacoes)
- Salve e clique em Activate
- Copie o Access Token gerado
- No Postman, cole na variavel
admin_token