Toda loja Magento 2 / Adobe Commerce no Brasil cedo ou tarde esbarra no mesmo nó: o catálogo, o estoque e o financeiro vivem no ERP, mas o pedido nasce no e-commerce — e nada vira venda de verdade sem a NF-e modelo 55 (ou a NFC-e modelo 65, no varejo com retirada) autorizada pela SEFAZ. Quando essa ponte é mal feita, aparecem os sintomas clássicos: estoque vendido em duplicidade (overselling), pedidos travados sem nota, consumers de fila parados e o time de operação reconciliando planilha à mão às 23h da Black Friday.
Este guia foi reescrito para descer ao nível que um especialista realmente usa em produção: endpoints literais (POST /rest/V1/integration/admin/token, POST /V1/inventory/source-items), payloads JSON e queries GraphQL reais, blocos de env.php para rodar consumers, os web services SOAP nomeados da SEFAZ (NFeAutorizacao4, NFeRetAutorizacao4…), os rate limits reais dos ERPs brasileiros (Bling a ~3 req/s) e — o recorte que mais muda arquitetura no Brasil — o fato de que Webhooks e Adobe I/O Events só existem no Adobe Commerce, não no Magento Open Source, que é onde roda a maioria das lojas Bling/Tiny/Omie. Tudo ancorado na documentação oficial da Adobe, dos ERPs e do Portal Nacional da NF-e. Se a sua loja ainda roda no Magento 1, leia antes o guia de Migração de Magento 1 para Magento 2 — integrar sobre uma plataforma em fim de vida é construir sobre fundação sem manutenção.
As três APIs do Magento 2: REST, GraphQL e SOAP (com chamadas reais)
O Adobe Commerce / Magento 2 expõe três tipos de web API: REST, GraphQL e SOAP. REST e SOAP são o mesmo framework por baixo — ambos seguem o modelo CRUD + search e leem os mesmos endpoints declarados no webapi.xml de cada módulo. GraphQL é uma camada separada, pensada para o storefront. A regra que aplico em todo projeto é simples: GraphQL para o que o cliente vê, REST para o que o ERP escreve. Mas a justificativa não é estética — é de cobertura de API, e é aqui que a maioria dos guias para.
O trade-off que decide: GraphQL não cobre o back-office
GraphQL no Magento é storefront-only. Ele não expõe a maior parte das operações administrativas: não há mutations para criar produto com todo o conjunto de atributos administrativos, gerenciar source items de estoque, criar invoice/shipment ou rodar atualização de atributo em massa. Por isso o ERP fica em REST não por gosto, mas por necessidade: é a única API que cobre o catálogo administrativo, pedidos, estoque MSI e operações em lote. SOAP, na prática, quase nunca entra em projeto novo — compartilha o mesmo webapi.xml do REST, mas o WSDL é gerado por serviço (?wsdl&services=catalogProductRepositoryV1) e o XML verboso só compensa quando um sistema legado exige SOAP. Eu nunca escolho SOAP voluntariamente em 2026.
1) Obter o token admin (REST)
POST /rest/V1/integration/admin/token
Content-Type: application/json
{"username": "erp_integration", "password": "********"}
# resposta: uma string com o token, ex.:
# "vbnf3hj5lkm8..."
# uso nas próximas chamadas:
# Authorization: Bearer vbnf3hj5lkm8...2) Criar um produto simples (REST)
O store-view all grava o valor no escopo default (global), o que normalmente é o que o ERP quer:
POST /rest/all/V1/products
Authorization: Bearer <token>
Content-Type: application/json
{
"product": {
"sku": "SKU-1001",
"name": "Camiseta Preta P",
"price": 79.90,
"attribute_set_id": 4,
"type_id": "simple",
"status": 1,
"visibility": 4
}
}3) Ler produto no storefront (GraphQL)
POST /graphql
Content-Type: application/json
query {
products(filter: { sku: { eq: "SKU-1001" } }) {
items {
name
sku
price_range {
minimum_price { regular_price { value currency } }
}
}
}
}O gotcha de quem extrai dados: searchCriteria
Quando o ERP lê do Magento via REST (delta de pedidos, varredura de catálogo), a paginação e os filtros vão por searchCriteria. Filtros dentro do mesmo filter_group são OR; grupos diferentes são AND. Exemplo de "todos os pedidos criados depois de X, paginado":
GET /rest/V1/orders?
searchCriteria[filter_groups][0][filters][0][field]=created_at&
searchCriteria[filter_groups][0][filters][0][value]=2026-06-14 00:00:00&
searchCriteria[filter_groups][0][filters][0][condition_type]=gteq&
searchCriteria[pageSize]=100&
searchCriteria[currentPage]=1&
searchCriteria[sortOrders][0][field]=created_atcondition_type aceita eq, gteq, lteq, in, like etc. Se você omitir pageSize, o Magento retorna tudo — e em uma loja com 200 mil pedidos isso derruba o servidor. Sempre pagine.
| API | Cobertura | Melhor uso | Endpoint |
|---|---|---|---|
| REST | Catálogo admin, pedidos, MSI, lote — completa | Integração ERP, admin, batch | /rest/<store-view>/V1/... |
| GraphQL | Storefront apenas (sem admin) | Headless, PWA, mobile | /graphql (único) |
| SOAP | Igual ao REST, mas verboso | Legado que exige WSDL (raro) | /soap?wsdl&services=... |
Segundo a documentação para desenvolvedores da Adobe Commerce, o framework de web API é baseado no modelo CRUD e search — no texto original em inglês: "The framework is based on the CRUD (create, read, update, delete) & search model." A orientação de usar GraphQL para o storefront e REST para integrações administrativas é síntese minha da documentação, não uma frase única.
Fonte: Adobe Commerce Developer
Os endpoints GraphQL diferem por hospedagem: em PaaS (on-prem/Cloud), https://<server>/graphql; em SaaS (Adobe Commerce as a Cloud Service), https://<region>-<env>.api.commerce.adobe.com/<tenantId>/graphql. O controle fino de payload do GraphQL tem impacto direto na Performance e Core Web Vitals do front.
Autenticação: tokens, endpoints literais, OAuth 1.0a e ACL
Antes de qualquer chamada, o ERP precisa autenticar. O Magento 2 oferece três tipos de token, todos enviados no header Authorization: Bearer <token>, com comportamentos de expiração bem diferentes — e errar isso é a causa nº 1 de integrações que "param de funcionar do nada".
| Tipo | Endpoint / como obter | Validade padrão | Uso típico |
|---|---|---|---|
| Integration token | Criar e ativar uma Integration no Admin | Indefinida (até revogação) | Integração com ERP/middleware |
| Admin token | POST /rest/V1/integration/admin/token | 4 horas | Operações administrativas pontuais |
| Customer token | POST /rest/V1/integration/customer/token | 1 hora | Ações em nome do cliente |
Os corpos são idênticos em estrutura — {"username":"","password":""} — e a resposta é literalmente uma string com o token. A expiração de admin/customer é configurável em Stores > Configuration > Services > OAuth > Access Token Expiration (Admin Token Lifetime e Customer Token Lifetime, em horas).
Conforme a documentação para desenvolvedores da Adobe Commerce, por padrão "an admin token is valid for 4 hours, while a customer token is valid for 1 hour", e "A cron job that runs hourly removes all expired tokens." Os trechos entre aspas são literais da página; o restante é resumo meu.
Fonte: Adobe Commerce Developer
Esse cron horário é o job que limpa tokens admin/customer expirados — ele roda no cron group default. Se o cron estiver parado, tokens expirados acumulam na tabela oauth_token. Para integração com ERP eu sempre uso o Integration token: não expira, evita renovação automática. Ainda assim, atenção a um gotcha: apesar de "não expirar", o token de integração pode ser invalidado se o admin associado for desativado ou tiver a senha trocada em certas versões — quando isso acontece, a integração começa a tomar 401 sem aviso.
O gotcha clássico do OAuth 1.0a: o callback HTTPS público
Em PaaS/on-prem, integrações de terceiros podem usar OAuth 1.0a. Quando você clica em Activate, o Commerce faz um HTTPS POST com consumer key/secret, verifier e store URL para o Callback Link que você cadastrou. Se esse endpoint não for HTTPS, público e válido no momento da ativação, você recebe o famoso "Sorry, something went wrong" / Unable to activate — a causa nº 1 desse erro é tentar ativar contra um localhost ou um endpoint atrás de firewall que o Magento não alcança. A chave de assinatura concatena consumer_secret & token_secret.
SaaS é diferente: não existe Integration token
Em Adobe Commerce as a Cloud Service (ACCS) os métodos tradicionais de admin/integration token não são suportados — a autenticação é via Adobe IMS / OAuth 2.0 server-to-server, com client_id, client_secret e uma technical account configurada no Adobe Developer Console. Se você vai para SaaS, planeje a integração já nesse modelo desde o dia zero.
ACL: limite o blast radius
Crie a integração em System > Extensions > Integrations > Add New Integration e, em Basic Settings > API, defina o Resource Access. Esses recursos vêm do acl.xml de cada módulo e são referenciados pelo webapi.xml. A integração roda como um usuário admin-like: se você der "All", um token vazado vira controle total da loja. Nunca conceda "All" ao ERP — libere só catálogo, estoque (Magento_InventoryApi), pedidos e clientes que ele realmente usa. Menor privilégio limita o blast radius e é um dos pilares do guia de Segurança e Hardening do Magento 2.
Tratamento de erros HTTP: como o ERP deve reagir a cada código
O guia anterior cobria os status de bulk mas ignorava os HTTP status da REST síncrona — e é por aí que 90% dos bugs de integração entram. O Magento responde erro com um JSON padronizado: message (com placeholders), parameters (os valores) e, em modo developer, trace. Exemplo real de um 400:
HTTP/1.1 400 Bad Request
{
"message": "The product that was requested doesn't exist. Verify the product and try again.",
"parameters": [],
"trace": "#0 /app/code/..."
}O ERP precisa reagir diferente a cada classe de status — tratar tudo como "erro genérico" é o que gera retry cego e duplicação:
| Status | Significado | O ERP deve… |
|---|---|---|
| 400 | Payload/validação inválida | Corrigir o dado. Não repetir igual — vai falhar de novo |
| 401 | Token ausente/expirado/inválido | Renovar token e repetir uma vez |
| 403 | Sem permissão (ACL) | Ajustar Resource Access. Não repetir |
| 404 | Recurso inexistente | Decidir: criar (upsert) ou registrar e seguir |
| 429 | Rate limit (se houver WAF/nginx na frente) | Respeitar Retry-After, backoff |
| 500/503 | Erro/indisponibilidade do servidor | Retry com backoff exponencial + jitter |
Na prática: 4xx (exceto 401/429) é problema de dado seu — alarme e correção, nunca retry automático infinito; 5xx e 429 são transitórios — retry com backoff. Logue sempre o corpo completo do erro: o message do Magento é descritivo o suficiente para diagnosticar sem abrir o servidor. Cuidado com trace em produção: ele vaza caminhos internos e só aparece em developer mode — em produção deve estar desligado.
Async e Bulk APIs: alto volume e consumers em produção
Chamadas REST síncronas funcionam para baixo volume, mas quebram quando o ERP empurra milhares de SKUs ou pedidos de uma vez — timeouts, locks de banco, loja travada. A resposta do Magento são as Async APIs e Bulk APIs, que gravam o trabalho em fila e respondem na hora com um bulk_uuid.
Async e Bulk: endpoints reais
Async: adicione o prefixo /async ao endpoint síncrono (suporta POST/PUT/DELETE/PATCH, não GET). Bulk combina várias chamadas do mesmo tipo num array. Exemplo de Bulk criando dois produtos de uma vez:
POST /rest/all/async/bulk/V1/products
Authorization: Bearer <token>
Content-Type: application/json
[
{ "product": { "sku": "SKU-1", "name": "Produto 1", "price": 10, "attribute_set_id": 4, "type_id": "simple" } },
{ "product": { "sku": "SKU-2", "name": "Produto 2", "price": 20, "attribute_set_id": 4, "type_id": "simple" } }
]
# resposta imediata:
# { "bulk_uuid": "e6...", "request_items": [...], "errors": false }Acompanhamento de status
- Sumário:
GET /V1/bulk/:bulkUuid/status - Por status:
GET /V1/bulk/:bulkUuid/operation-status/:status - Detalhado:
GET /V1/bulk/:bulkUuid/detailed-status(comtopic_nameeserialized_data)
| Código | Status | Ação |
|---|---|---|
| 1 | Complete | Sucesso |
| 2 | Retriably failed | Reprocessar (falha temporária) |
| 3 | Not retriable | Corrigir dado antes de reenviar |
| 4 | Open | Aguardando processamento |
| 5 | Rejected | Rejeitada na entrada |
Rodar consumers em produção: o que ninguém te conta
O backlog só escoa se houver consumer vivo. bin/magento queue:consumers:start async.operations.all sobe um consumer manualmente, mas em produção há um conflito clássico: por padrão o cron do Magento também roda consumers (via consumers_runner), e se você subir consumers à mão por supervisord ao mesmo tempo, eles competem e você acaba com mensagens processadas em duplicidade. A decisão é no app/etc/env.php:
'cron_consumers_runner' => [
'cron_run' => false, // desligue se for usar supervisord/systemd
'max_messages' => 10000, // default; consumer reinicia após N msgs
'consumers' => [ // [] = todos; melhor listar os que importam
'async.operations.all',
'product_action_attribute.update',
'inventory.reservations.updateSalabilityStatus',
],
'multiple_processes' => [ // paralelismo por consumer
'async.operations.all' => 4,
],
],Minha prática: quando uso supervisord, coloco cron_run => false para o cron não duplicar consumers, e deixo o supervisord (ou systemd) garantir que cada processo reinicie ao morrer. Comando completo que uso no supervisord:
bin/magento queue:consumers:start async.operations.all \
--max-messages=1000 --single-thread --area-code=adminhtml--max-messages força o processo a morrer após N mensagens (o supervisord o ressuscita, evitando vazamento de memória do PHP em runs longos). async.operations.all processa todas as operações async — em loja grande convém dedicar consumers por tópico para que uma carga de catálogo não bloqueie a baixa de estoque. Consumers úteis para integração ERP: async.operations.all, product_action_attribute.update (preço/atributo em massa), inventory.source.items.cleanup e inventory.reservations.updateSalabilityStatus.
De acordo com a documentação da Adobe Commerce, os status de operação bulk distinguem uma falha retentável (código 2) de uma falha que não deve ser repetida sem correção (código 3). Paráfrase da tabela oficial, não citação literal.
Fonte: Adobe Commerce Developer
Message Queue Framework: RabbitMQ, dead-letter e operação real
Por trás das Async/Bulk APIs está o Message Queue Framework (MQF). Publishers publicam via PublisherInterface::publish($topic, $message); consumers processam por tópico. A configuração mora em quatro arquivos: communication.xml, queue_topology.xml, queue_publisher.xml e queue_consumer.xml. Trecho típico de um queue_consumer.xml:
<consumer name="async.operations.all"
queue="async.operations.all"
connection="amqp"
maxMessages="20000"
consumerInstance="Magento\Framework\MessageQueue\Consumer"/>Escolha do broker
- RabbitMQ (AMQP 0.9.1): o broker primário para produção (porta AMQP 5672). Para o Adobe Commerce 2.4.8, os requisitos atuais citam RabbitMQ 4.1.
- ActiveMQ Artemis (STOMP): alternativa suportada.
- Adapter MySQL: usa as tabelas
queue,queue_message,queue_message_status. Faz polling, não tem dead-letter exchange e não é recomendado para produção.
php bin/magento setup:config:set \
--amqp-host="rabbitmq.local" --amqp-port="5672" \
--amqp-user="magento" --amqp-password="***" --amqp-virtualhost="/"Segundo a documentação da Adobe Commerce, sempre que possível use um broker externo como RabbitMQ ou ActiveMQ Artemis em ambientes de produção — no original: "Use an external message broker like RabbitMQ or ActiveMQ Artemis for production environments whenever possible."
Fonte: Adobe Commerce Developer
Corrigindo um mito: o MQF NÃO garante dead-letter "pronto"
É comum ler que "o RabbitMQ guarda as mensagens não entregues, nada se perde". Isso é enganoso. O Dead-Letter Exchange (DLX) do RabbitMQ precisa ser configurado explicitamente — TTL, x-dead-letter-exchange, fila vinculada. O Magento ganhou suporte a argumentos de dead-letter/retry na criação de filas a partir da 2.4.2, mas esses argumentos só podem ser definidos na criação da fila (não dá para adicionar a uma fila existente), e o MQF não monta um DLX completo por padrão. Resultado real: mensagem que falha sem retry configurado pode ir para a tabela failed ou simplesmente ser descartada. Se você precisa de garantia de não-perda, configure o DLX você mesmo e monitore.
Comandos operacionais que uso de verdade
# listar todos os consumers definidos (db e amqp)
bin/magento queue:consumers:list
# inspecionar profundidade e mensagens não confirmadas
rabbitmqctl list_queues name messages messages_unacknowledged
# Management UI no navegador:
# http://<host>:15672 (user/pass do rabbitmq)Quando vejo messages_unacknowledged crescendo sem cair, é sinal de consumer travado processando uma mensagem venenosa — purgo/reprocesso pelo Management UI e investigo o topic_name no detailed-status. Fila parada = pedido sem baixa de estoque, então em produção eu trato consumer como serviço gerenciado (supervisord ou cron com lock), nunca como processo solto.
Webhooks e Adobe I/O Events: só Adobe Commerce (e o que sobra para Open Source)
Até aqui o ERP chama o Magento. Muitas integrações precisam do contrário — o Magento avisar sistemas externos quando algo acontece. E aqui vem o recorte que mais muda arquitetura no Brasil e que quase nenhum guia diz com clareza.
Atenção: Webhooks e Adobe I/O Events exigem Adobe Commerce (licença paga)
O módulo magento/commerce-webhooks e o Adobe I/O Events são recursos do Adobe Commerce (PaaS/SaaS) — não funcionam no Magento Open Source. Como a maioria das lojas que integram Bling/Tiny/Omie roda exatamente Open Source, isso é decisivo. Se você está em Open Source, esqueça webhooks nativos; o que sobra é:
- Observers / Plugins custom: um
observeremsales_order_place_after(ousales_order_save_after) que enfileira e posta o pedido para o ERP. É o padrão real em Open Source. - Eventos de fila (MQF): publicar no RabbitMQ no observer e ter um consumer que entrega ao ERP com retry — desacopla o checkout da disponibilidade do ERP.
A regra que dou: nunca chame o ERP de forma síncrona dentro do observer de checkout. Se o ERP estiver lento, o cliente fica travado no "finalizando pedido". Enfileire e entregue fora do request.
Webhooks (Adobe Commerce): síncronos, com assinatura HMAC
No Adobe Commerce, webhooks são síncronos — o Commerce faz uma chamada em tempo real e aguarda a resposta, podendo abortar a ação. Configuração via webhooks.xml:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_AdobeCommerceWebhooks:etc/webhooks.xsd">
<method name="observer.checkout_submit_all_after" type="after">
<hooks>
<hook name="validate_order" url="https://erp.example.com/hooks/order"
method="POST" timeout="5000" softTimeout="1000">
<fields><field name="data.order.increment_id"/></fields>
<rules>
<rule field="data.order.grand_total" operator="greaterThan" value="0"/>
</rules>
</hook>
</hooks>
</method>
</config>Gotcha de segurança crítico: valide a assinatura. Com a verificação ativa, o Commerce adiciona o header x-adobe-commerce-webhook-signature — um HMAC SHA256 (base64) do corpo, assinado pelo Commerce com a chave privada e que você confere com a chave pública configurada. Sem isso, qualquer um pode forjar um POST para o seu endpoint. E o gotcha operacional: como o webhook é síncrono, um endpoint lento bloqueia o checkout — por isso o timeout e o softTimeout existem. Use webhook só para validação que precisa ser em tempo real (crédito, antifraude, regra fiscal).
Conforme a documentação de extensibilidade da Adobe Commerce, um webhook dispara "a real-time call from Commerce to a URL endpoint", e se a resposta indicar indisponibilidade "the flow is interrupted and an exception is thrown". Trechos entre aspas literais; restante é resumo meu.
Fonte: Adobe Commerce Developer
Adobe I/O Events (assíncrono, via App Builder)
Quando assíncrono basta, use Adobe I/O Events: o Commerce envia eventos ao Adobe I/O, que roteia para apps do App Builder, eliminando polling. Registro:
# habilitar e apontar o provider (Adobe Developer Console)
bin/magento config:set adobe_io_events/integration/enabled 1
bin/magento config:set commerce_events/event_processing/enabled 1
# inscrever um evento
bin/magento events:subscribe observer.sales_order_save_after \
--fields=increment_id --fields=stateO journaling persiste eventos por até 7 dias, então o consumidor pode ficar offline e recuperar depois. Em integrações ERP, o padrão poderoso é manter o de-para e a validação em uma action do App Builder, fora do core — a loja segue atualizável e o TCO de upgrade cai.
Estoque, preço e catálogo com MSI: payloads reais e anti-overselling
A sincronização que mais gera problema é a de estoque — vender o que não existe destrói a confiança. O Magento 2.3 introduziu o Inventory Management (antes MSI — Multi Source Inventory). Quatro conceitos são pré-requisito:
- Sources: locais físicos — armazéns, lojas, CDs, drop shippers.
- Stocks: mapeiam o canal de venda/website para uma ou mais sources.
- Salable Quantity: a quantidade vendável virtual, agregada por stock (não por source), considerando reservations. Obtenha por service call — nunca leia como valor estático no produto.
- Reservations: deduções append-only da salable quantity, criadas no checkout e liberadas no shipment.
O payload real — e o status que todo mundo esquece
O ERP atualiza a quantidade da source assim:
POST /rest/V1/inventory/source-items
Authorization: Bearer <token>
Content-Type: application/json
{
"sourceItems": [
{ "sku": "SKU-1001", "source_code": "default", "quantity": 100, "status": 1 }
]
}O gotcha clássico: o campo status (1 = In Stock, 0 = Out of Stock) é praticamente obrigatório. Se o ERP manda só quantity sem status, ou manda status: 0 com quantity: 100, o produto fica fora de estoque mesmo com qty > 0. Já perdi horas debugando "produto não vende" que era exatamente isso. Para consultar a vendável: GET /V1/inventory/get-product-salable-quantity/:sku/:stockId. Em catálogo grande, use a versão bulk dessa atualização para não gerar uma chamada por SKU.
Atribuição source ↔ stock ↔ website
Um produto só vende se a source dele estiver vinculada a um stock que, por sua vez, esteja atribuído ao website da venda. Produto sem stock vinculado ao website não é vendável, por mais quantidade que tenha na source. Quando um produto "importado certinho" não aparece como disponível, eu checo primeiro a atribuição source→stock→website.
O remédio para overselling: reconciliar reservations
ERPs que sobrescrevem a quantidade direto "comem" reservations em andamento e geram overselling ou estoque fantasma. Quando as reservations dessincronizam, o MSI tem ferramentas CLI de reconciliação — uso essas duas em produção:
# lista inconsistências (formato cru ORDER:SKU:QTY:STOCK)
bin/magento inventory:reservation:list-inconsistencies
# cria reservas de compensação para corrigir
bin/magento inventory:reservation:list-inconsistencies -r \
| bin/magento inventory:reservation:create-compensationsSegundo a documentação da Adobe Commerce, quando ocorre um evento como pedido, cancelamento, reembolso ou shipment, o serviço de reserva cria uma reservation para cada SKU — no original: "Reservations are append-only entities."
Fonte: Adobe Commerce Developer
Ao desenvolver, use PlaceReservationsForSalesEventInterface e nunca AppendReservationsInterface direto na lógica de negócio. Modo Single Source / Legacy: quem desativa o MSI cai no estoque legado (cataloginventory_stock_item) e o source-items deixa de ser o caminho — nesse caso o ERP escreve stock_item via /V1/products/:sku/stockItems/:itemId. Saiba em qual modo você está antes de escolher o endpoint.
O que sincronizar e em que direção
| Entidade | Dono | Direção | API/recurso |
|---|---|---|---|
| Catálogo | ERP | ERP → Magento | Bulk /V1/products |
| Preços | ERP | ERP → Magento | special/tier price + product_action_attribute.update |
| Estoque | ERP | ERP → Magento | /V1/inventory/source-items |
| Pedidos | Magento | Magento → ERP | observer / webhook / fila |
| NF-e (chave/status) | ERP/SEFAZ | ERP → Magento | REST order (update status) |
Defina sempre um dono único por entidade. Estoque e preço pertencem ao ERP; pedidos nascem no Magento. Sincronização sem dono vira guerra de sobrescrita.
Delta sync, searchCriteria e reindex após carga em massa
Dois gargalos derrubam integrações de catálogo em produção e quase nunca são tratados: full sync desnecessário e reindex/cache depois da carga.
Delta sync: sincronização incremental
Reenviar o catálogo inteiro a cada ciclo é desperdício e estoura rate limit. A estratégia correta é delta sync: marcar a "última sincronização" e puxar só o que mudou, usando updated_at/created_at com searchCriteria. Para pegar pedidos novos desde a última varredura:
GET /rest/V1/orders?
searchCriteria[filter_groups][0][filters][0][field]=updated_at&
searchCriteria[filter_groups][0][filters][0][value]=2026-06-14 02:00:00&
searchCriteria[filter_groups][0][filters][0][condition_type]=gt&
searchCriteria[pageSize]=200&searchCriteria[currentPage]=1Guarde o maior updated_at retornado como marca-d'água para a próxima rodada. No sentido ERP→Magento, o ERP deve manter um flag de sincronização por registro e só enviar deltas. Full sync, reservo para o seeding inicial e para reconciliações periódicas (ex.: madrugada de domingo).
Reindex e cache: o gargalo pós-Bulk import
Depois de uma carga grande via Bulk, os indexers ficam invalidated e o produto pode não aparecer na busca/categoria até reindexar. Em produção eu mantenho os indexers em Update on Schedule (não "Update on Save"), para que a carga não dispare reindex síncrono a cada SKU:
# ver status; o que importa é não ficar "invalid" pendurado
bin/magento indexer:status
# colocar em modo agendado (mvp para volume)
bin/magento indexer:set-mode schedule
# reindex pontual após seeding inicial
bin/magento indexer:reindex catalog_product_price cataloginventory_stock
# limpar caches relevantes pós-carga
bin/magento cache:flush full_page block_htmlO gotcha: em Update on Save, importar 50 mil SKUs dispara dezenas de milhares de reindex parciais e derruba a performance. Em Update on Schedule, o mview registra as mudanças e o cron reindexa em lote — é o modo correto para quem recebe carga de ERP. Após preço/estoque mudarem, invalide o full_page cache das páginas afetadas; senão o cliente vê preço/disponibilidade antigos.
ERPs brasileiros: SAP, TOTVS, Bling, Tiny, Omie e rate limits reais
O fluxo típico é sempre o mesmo: o ERP gerencia produtos, estoque, preços e financeiro; o e-commerce envia o pedido; o ERP dá baixa de estoque, emite a NF-e via SEFAZ e devolve número, chave e status para o Magento atualizar o pedido. O que muda é o estilo de API, a autenticação e — o que derruba integração na prática — o rate limit.
ERPs cloud: REST/JSON + rate limits que você precisa respeitar
- Bling (API v3): REST com OAuth 2.0 (
Authorization: Bearer [access_token]). Rate limit real: 3 requisições/segundo e 120.000/dia; ao exceder, retorna HTTP 429. Há ainda bloqueio de IP por erro excessivo (ex.: muitas chamadas a/oauth/tokenem 60s). Esse limite de 3 req/s é exatamente o que derruba sincronização de catálogo grande feita ingênua — você precisa de throttle. - Omie: JSON via POST com
app_key,app_secret,calle objetoparam. Limite por IP + App Key + Método; requisições idênticas em janela curta de ~60s são bloqueadas (e a doc cita bloqueio temporário após repetições incorretas). Credenciais vêm de "Chave de Integração API" (só admin). - Tiny (Olist): a API v3 usa OAuth 2.0 (fluxo com
client_id/client_secretgerados no módulo de aplicativos/extensões) — Tiny foi adquirida pela Olist. A v2, ainda em uso, autentica por token simples. Ao integrar Tiny novo, vá de v3/OAuth2.
Segundo a documentação oficial do Bling, a API v3 é "Estruturada no padrão REST" e autentica "por meio de autenticação OAuth 2.0" com o header
Fontes: Bling — Referência da API e Bling — LimitesAuthorization: Bearer [access_token](trechos literais da página de referência da API). Já a página de limites impõe "3 requisições por segundo" e "120.000 requisições por dia", retornando HTTP 429 ao exceder (trechos literais da página de limites, linkada abaixo).
ERPs enterprise: SAP e TOTVS Protheus
Aqui o Magento quase nunca fala direto com o ERP — há middleware de mediação:
- SAP: os padrões reais são IDoc e BAPI/RFC para o ECC, e OData V2/V4 no S/4HANA, normalmente mediados pelo SAP Integration Suite (Cloud Platform Integration / CPI) ou pelo SAP PI/PO. Autenticação por OAuth 2.0 client credentials ou certificado. A integração e-commerce↔SAP costuma trafegar pedido como IDoc/OData e receber confirmação de fatura de volta.
- TOTVS Protheus: REST via módulo de integração / EAI, com webhooks de saída para receber pedidos do e-commerce; frequentemente passa pelo TOTVS iPaaS ou por conectores de marketplace. A autenticação varia por implantação (token/OAuth).
| ERP | API | Auth | Rate limit / nota |
|---|---|---|---|
| Bling | REST/JSON v3 | OAuth 2.0 | 3 req/s, 120k/dia, 429 |
| Omie | JSON (POST) | app_key/app_secret | Limite por IP+key+método; janela ~60s |
| Tiny (Olist) | REST/JSON v3 | OAuth 2.0 (v3) / token (v2) | Migrar para v3 |
| TOTVS Protheus | REST/EAI + webhooks | Token/OAuth | TOTVS iPaaS comum |
| SAP | IDoc/BAPI/OData | OAuth2 / certificado | SAP Integration Suite (CPI) |
Janela de batch vs tempo real
Decisão prática que tomo em todo projeto: catálogo e preço em batch noturno (mudam pouco, podem aguardar a janela e respeitar o rate limit), pedido e estoque em quase-tempo-real (pedido nasce e precisa ir já; estoque precisa de baixa rápida). O gotcha: estoque em batch enquanto o pedido é tempo real causa overselling na janela entre sincronizações — por isso estoque de itens críticos eu trato near-real-time, e reconcilio com o ERP de madrugada.
NF-e e NFC-e: web services da SEFAZ, fluxo assíncrono e contingência
A NF-e modelo 55 (B2B/B2C com transporte) e a NFC-e modelo 65 (varejo presencial / retirada em loja) são documentos fiscais transmitidos à SEFAZ autorizadora via web services SOAP, em dois ambientes: homologação e produção. A especificação está no Manual de Orientação do Contribuinte (MOC) e suas Notas Técnicas (NT) — é nas NTs que aparecem mudanças de leiaute que quebram integração se ignoradas.
Os web services SOAP nomeados
Um especialista fiscal trabalha com estes serviços por nome:
- NFeAutorizacao4: envio do lote de NF-e (método
nfeAutorizacaoLote). - NFeRetAutorizacao4: consulta do retorno do lote pelo recibo (
nfeRetAutorizacaoLote). - NFeStatusServico4: checa a disponibilidade da SEFAZ — uso isso para decidir entrar em contingência.
- NFeConsultaProtocolo4: consulta a situação de uma NF-e pela chave.
- RecepcaoEvento4: eventos — cancelamento, carta de correção (CC-e), manifestação.
- NFeInutilizacao4: inutilização de faixa de numeração.
O fluxo assíncrono real: lote → recibo → protocolo
O coração da emissão moderna é assíncrono, e ignorar isso é o erro de quem nunca emitiu em volume:
- Monta o lote e envia via NFeAutorizacao4.
- A SEFAZ responde com um recibo (nRec) — não com a autorização ainda.
- Você consulta o recibo em NFeRetAutorizacao4 até obter o cStat de cada nota (100 = autorizada).
Atenção ao campo tpAmb no XML: 1 = produção, 2 = homologação. Em homologação a SEFAZ exige frases legais distintas por campo: no xNome do destinatário a razão social deve ser "NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL" (caso contrário, Rejeição 598); e na xProd do primeiro item a descrição deve ser "NOTA FISCAL EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL" (caso contrário, Rejeição 373) — repare que a frase do produto começa com "NOTA FISCAL", não com "NF-E". Nunca rode QA fiscal contra produção, sob risco de gerar notas reais indevidas.
Contingência de verdade
Quando a SEFAZ autorizadora cai, você não pode parar de vender. Os modos reais: SVC-AN e SVC-RS (SEFAZ Virtual de Contingência, que assume a autorização) e o EPEC (Evento Prévio de Emissão em Contingência), além da contingência offline com posterior transmissão. O NFeStatusServico4 é o que me diz quando acionar.
De acordo com o Portal Nacional da NF-e, a nota é transmitida à SEFAZ por web services, com ambientes distintos de homologação e produção, e a especificação técnica é definida pelo Manual de Orientação do Contribuinte (MOC) e suas Notas Técnicas. Síntese minha do portal, não citação literal.
Fonte: Portal Nacional da NF-e
Por que não emitir NF-e direto do Magento
Decisão que defendo em todo projeto: não emita NF-e do Magento. Delegue ao ERP ou a um middleware/gateway fiscal certificado — eles assinam com certificado A1 (arquivo) ou A3 (token), tratam contingência e devolvem a chave de 44 dígitos, o DANFE e o XML autorizado. Concentrar certificado e dados sensíveis no gateway reduz a sua superfície de conformidade — alinhado ao guia de Segurança e Hardening do Magento 2.
Fechando o ciclo bidirecional
De posse do retorno, o ERP chama o Magento via REST para atualizar o status do pedido e anexar chave/número/DANFE/XML. Mas o ciclo não acaba na autorização: eventos fiscais pós-emissão também precisam refletir no Magento — cancelamento deve gerar credit memo/cancelar o pedido; CC-e atualiza dados; devolução (NF-e de entrada) reabre estoque. Mapeie cada evento da SEFAZ para uma transição de status do pedido, ou o financeiro e o estoque divergem do fiscal.
Impostos e listas de preço: o de-para fiscal que vem do ERP
Quem integra preço e fiscal precisa mapear dois mundos que o guia anterior ignorava: preços por contexto e atributos fiscais.
Listas de preço
O ERP costuma ter tabelas de preço por canal/cliente. No Magento isso vira:
- special_price: preço promocional com janela de datas — bom para campanha vinda do ERP.
- tier_price: preço por quantidade e por customer group — é o que casa com "tabela de preço por tipo de cliente" do ERP. Atualizado via
/V1/products/tier-prices(bulk) ouproduct_action_attribute.update. - catalog price rules: regras de desconto no carrinho/catálogo.
- B2B / Shared Catalog: em Adobe Commerce B2B, preço por company via shared catalog — mapeie a tabela de preço do ERP para o shared catalog correto.
Atributos fiscais como atributos de produto
NCM, CFOP, origem, CEST e GTIN/EAN não são nativos do Magento — você os cria como atributos de produto e sincroniza do ERP, porque o gateway fiscal precisa deles para montar o XML. Eu padronizo um conjunto e sincronizo junto do catálogo:
| Atributo | Origem | Para que serve |
|---|---|---|
ncm | ERP | Classificação fiscal da mercadoria |
cfop | ERP (por operação) | Natureza da operação na NF-e |
origem | ERP | Origem da mercadoria (0–8) |
cest | ERP | Substituição tributária quando aplicável |
gtin / EAN | ERP | Identificação e matching de SKU |
Gotcha: o CFOP varia por operação (venda dentro/fora do estado, devolução) — não é um valor fixo do produto. Quem mantém isso é o ERP/gateway no momento da emissão; o que o Magento carrega é o dado base (NCM, origem, CEST). NFC-e (modelo 65) tem regras próprias por operação de varejo, então confirme com o contador o conjunto exato antes de modelar.
Confiabilidade: idempotência, backoff com jitter, rate limit e DLQ
Integração e-commerce↔ERP é, na essência, um problema de sistemas distribuídos: redes falham, serviços reiniciam, mensagens chegam duas vezes. As seções de Async/Bulk e MQF já cobriram filas, status codes e dead-letter — aqui eu fico no que falta: como implementar de fato.
Idempotência: implementação, não conceito
O Magento não garante idempotência sozinho — quem garante é você. O padrão que uso no middleware é uma tabela de-para que serve de chave de dedupe, checada antes de qualquer escrita:
-- tabela no middleware
de_para_sync(
external_id VARCHAR, -- id do pedido no ERP
magento_entity VARCHAR, -- ex.: 'order:1000012345'
status VARCHAR, -- pending|sent|confirmed|failed
bulk_uuid VARCHAR,
correlation_id VARCHAR,
updated_at DATETIME,
UNIQUE(external_id, magento_entity)
)
-- antes de criar pedido no Magento:
-- 1) SELECT por external_id; se já 'confirmed', não recria
-- 2) ou consulta o Magento por increment_id antes do POST /V1/ordersPara produtos a chave natural é o SKU; para pedidos, o increment_id ou o id externo do ERP. Assim, retry nunca duplica pedido nem baixa estoque em dobro.
Backoff exponencial com jitter (a fórmula)
Retry cego martela o serviço já degradado. A fórmula que aplico:
delay = min(cap, base * 2^n) * random(0.5, 1.5)
# base=1s, cap=60s -> ~1s, 2s, 4s, 8s, 16s... com jitter
# o jitter (0.5–1.5) evita thundering herd de N clientes retryando juntosE respeite a semântica dos status: bulk 2 ou HTTP 5xx/429 → retry com backoff; bulk 3 ou HTTP 4xx de dado → corrigir antes, retry só repete o erro.
Rate limit do lado do ERP e circuit breaker
Como vimos, o Bling corta em 3 req/s e devolve 429. O middleware precisa de um token bucket respeitando esse teto e honrar o header Retry-After quando vier. Para a SEFAZ, que pode ficar fora do ar, uso circuit breaker: depois de N falhas consecutivas, paro de tentar por um tempo e aciono contingência — em vez de empilhar timeouts.
Correlação e DLQ de verdade
Propague um correlation-id ERP→middleware→Magento e case-o com o bulk_uuid retornado pelo Magento; com isso, quando o cliente diz "meu pedido não foi pro ERP", você rastreia a mensagem ponta a ponta. E uma DLQ de verdade não é "o RabbitMQ guarda": é uma fila separada + alarme + replay manual, configurada explicitamente (vide a ressalva sobre DLX na seção de MQF). Mensagem que esgota retries vai para a DLQ, dispara alerta, e um operador decide reprocessar ou descartar.
| Pilar | Implementação concreta |
|---|---|
| Idempotência | Tabela de_para_sync + check por increment_id/SKU |
| Retry | min(cap, base*2^n)*rand(0.5,1.5); status 2/5xx só |
| Rate limit ERP | Token bucket; honrar 429/Retry-After |
| Resiliência SEFAZ | Circuit breaker + contingência |
| Observabilidade | correlation-id casado com bulk_uuid |
| DLQ | Fila separada + alarme + replay manual |
Arquitetura e de-para: direta vs middleware, n8n e matching de SKU
A decisão mais estratégica é onde mora a lógica de integração. Há dois caminhos, e a escolha errada cobra caro na manutenção.
Integração direta (ponto-a-ponto)
O Magento fala direto com o ERP via REST. Mais simples e barato de começar, ideal para um único ERP cloud (Bling/Tiny/Omie) e regras simples. O custo: acopla os sistemas — mudou o ERP, quebrou o Magento — e adicionar um terceiro sistema multiplica conexões (N×N).
n8n não é iPaaS gerenciado — e isso importa
Aqui corrijo uma confusão comum: n8n é automação low-code self-hosted, não um iPaaS gerenciado com SLA/governança como MuleSoft, Boomi ou TOTVS iPaaS. n8n é excelente para PME — flexível, com muitos conectores — mas você opera, observa, escala e garante a persistência de estado. iPaaS gerenciado traz conectores certificados, governança, alta disponibilidade e SLA, ao custo de licença e menos flexibilidade. O trade-off é quem fica responsável quando dá ruim às 2h da manhã:
| Aspecto | Direta | n8n (self-hosted) | iPaaS gerenciado |
|---|---|---|---|
| Custo inicial | Menor | Baixo (licença) + sua infra | Maior |
| Quem opera/escala | Você (no código) | Você | Fornecedor (SLA) |
| De-para centralizado | Não | Sim | Sim |
| Governança/conectores certificados | — | Limitado | Sim |
| Melhor para | 1 ERP cloud, regras simples | PME, Bling/Tiny/Omie | SAP/TOTVS, multi-sistema |
De-para real: status e matching de SKU
O de-para é onde os projetos mais erram. Dois mapeamentos concretos que toda integração precisa. Primeiro, status do pedido:
| Status Magento | Situação no ERP (exemplo) |
|---|---|
pending | Pedido em aberto / aguardando pagamento |
processing | Pago / em separação |
complete | Faturado (NF-e autorizada) / enviado |
canceled | Cancelado (com cancelamento fiscal se houve NF-e) |
Segundo, e o que mais gera bug silencioso, o matching de SKU: o SKU do Magento, o código do produto no ERP e o EAN/GTIN raramente são iguais. Defina a estratégia explicitamente:
- Chave primária: casar por SKU quando ERP e Magento compartilham o mesmo código.
- Fallback por EAN/GTIN: quando os códigos divergem, casar pelo EAN (atributo sincronizado).
- Tabela de-para explícita: quando nada bate, manter
sku_magento ↔ codigo_erp ↔ eannuma tabela — nunca deixar o matching "adivinhar".
Trate o de-para com o mesmo rigor da definição de URLs e atributos do guia de SEO Técnico para Magento 2: dado bem modelado na origem evita retrabalho em toda a cadeia. E reforçando o recorte da seção de webhooks: se você está em Magento Open Source (a maioria das lojas Bling/Tiny/Omie), a saída do Magento para o ERP será por observer/plugin custom + fila, não por webhooks nativos.
Homologação, testes e segurança de rede da API
Fecho com o que separa integração que sobrevive a produção de protótipo: como testar e como proteger a API.
Ambiente de homologação end-to-end
Valide o caminho inteiro em sandbox antes de produção: SEFAZ em homologação (tpAmb=2, com as frases "SEM VALOR FISCAL" corretas por campo), sandbox de Bling/Omie/Tiny, dados de teste com NCM/CFOP reais. Eu sempre tenho um plano de rollback/replay: se a integração falha em produção, preciso conseguir reprocessar a partir da fila/DLQ (com idempotência garantindo que o replay não duplique) e, no pior caso, reverter para entrada manual temporária sem perder pedidos.
Segurança de rede da API
Expor /rest e /graphql abertos à internet é convite a abuso. O mínimo que configuro:
- HTTPS obrigatório: nunca token em HTTP — em OAuth 1.0a o próprio Magento avisa "Integration not secure" até HTTPS.
- IP allowlist: liberar
/restsó para os IPs do ERP/middleware no nginx ou WAF. - Rate limit no nginx: proteger os endpoints de integração de picos/abuso.
- WAF na frente: filtrar payloads maliciosos antes de chegar ao PHP.
# nginx: restringir /rest a IPs conhecidos + rate limit
limit_req_zone $binary_remote_addr zone=apizone:10m rate=10r/s;
location ~* ^/rest/ {
allow 203.0.113.10; # IP do middleware/ERP
allow 203.0.113.11;
deny all;
limit_req zone=apizone burst=20 nodelay;
# ... fastcgi_pass etc.
}O gotcha: o endpoint de token (/rest/V1/integration/admin/token) é alvo de força bruta — protegê-lo com rate limit e allowlist é tão importante quanto proteger o /admin. Isso conecta diretamente com o guia de Segurança e Hardening do Magento 2, que recomendo seguir em paralelo.
Perguntas frequentes
Preciso emitir a NF-e direto do Magento 2?
Não, e recomendo fortemente que não faça. Delegue ao ERP ou a um middleware/gateway fiscal certificado, que assina digitalmente (certificado A1 ou A3), monta o lote e transmite à SEFAZ pelos web services SOAP (NFeAutorizacao4) no fluxo assíncrono lote→recibo→protocolo, tratando contingência (SVC-AN/SVC-RS/EPEC). Depois ele retorna a chave de 44 dígitos, o número, o DANFE e o XML autorizado ao Magento via REST, atualizando o status do pedido. Lembre de refletir também os eventos pós-emissão (cancelamento, CC-e) no status/credit memo do pedido.
Como obtenho um token e qual usar para integrar o ERP?
Para operações pontuais, o token admin sai de POST /rest/V1/integration/admin/token com body {"username":"","password":""} e vale 4 horas; o customer token de POST /rest/V1/integration/customer/token vale 1 hora. Para integração contínua com ERP, use o Integration token (criado em System > Extensions > Integrations), que não expira até revogação — todos vão no header Authorization: Bearer <token>. Conceda ACL específica, nunca 'All'. Em Adobe Commerce as a Cloud Service (SaaS) esses tokens não existem: a autenticação é via Adobe IMS / OAuth 2.0 server-to-server.
Webhooks do Adobe Commerce funcionam no Magento Open Source?
Não. Tanto o módulo magento/commerce-webhooks quanto o Adobe I/O Events são recursos exclusivos do Adobe Commerce (licença paga) e não funcionam no Magento Open Source. Como a maioria das lojas que integram Bling, Tiny ou Omie roda Open Source, o caminho para o Magento notificar o ERP é um observer/plugin custom (por exemplo em sales_order_place_after) que enfileira e posta o pedido para o ERP, idealmente via fila com retry — nunca uma chamada síncrona dentro do checkout, que travaria o cliente se o ERP estiver lento.
Por que meu produto fica 'fora de estoque' mesmo com quantidade no ERP?
O erro mais comum é enviar /V1/inventory/source-items só com quantity, sem o campo status (1=In Stock, 0=Out of Stock) — sem status correto o produto fica indisponível mesmo com qty>0. O segundo motivo é atribuição: o produto só vende se a source estiver vinculada a um stock atribuído ao website da venda. E se as reservations dessincronizarem (overselling/estoque fantasma), reconcilie com bin/magento inventory:reservation:list-inconsistencies -r | bin/magento inventory:reservation:create-compensations.
Como importar muitos SKUs sem derrubar a loja e sem estourar rate limit?
Use Bulk APIs (POST /rest/all/async/bulk/V1/products com array) em vez de chamadas síncronas: a resposta é imediata com bulk_uuid e o processamento roda na fila. Em produção, mantenha consumers vivos pelo env.php cron_consumers_runner (cron_run=false se usar supervisord, para não duplicar) e use --max-messages. Faça delta sync (só o que mudou, por updated_at com searchCriteria) em vez de full sync, respeite o rate limit do ERP de origem (Bling 3 req/s, 429) com token bucket, e após a carga rode indexer:reindex e limpe o full_page cache.
Devo integrar Magento e ERP diretamente, usar n8n ou um iPaaS?
Para um único ERP cloud (Bling/Tiny/Omie) com regras simples, integração direta via REST é mais barata. n8n é uma ótima automação low-code, mas é self-hosted: você opera, observa e escala — não confunda com iPaaS gerenciado (MuleSoft, Boomi, TOTVS iPaaS), que traz governança, conectores certificados e SLA, indicado para SAP/TOTVS e múltiplos sistemas. Em qualquer caminho, mantenha um de-para explícito: status Magento↔ERP, matching de SKU (SKU→EAN/GTIN→tabela) e idempotência por increment_id para que reprocessamentos não dupliquem pedidos.
Referências oficiais
- Getting Started with Adobe Commerce Web APIs (REST, SOAP, GraphQL) — Adobe Commerce Developer
- Token-based authentication (admin/customer/integration tokens, cron de limpeza) — Adobe Commerce Developer
- OAuth-based authentication (fluxo OAuth 1.0a, callback HTTPS) — Adobe Commerce Developer
- Search using REST endpoints (searchCriteria, filter_groups, condition_type) — Adobe Commerce Developer
- Bulk operation status endpoints (status codes, bulk_uuid) — Adobe Commerce Developer
- Manage message queues (env.php cron_consumers_runner, multiple_processes) — Adobe Experience League
- Message Queue Framework (MQF, RabbitMQ, MySQL adapter) — Adobe Commerce Developer
- Adobe Commerce Webhooks — overview, configuração e assinatura HMAC — Adobe Commerce Developer
- Adobe Commerce Webhooks — signature verification (x-adobe-commerce-webhook-signature) — Adobe Commerce Developer
- Manage source items (/V1/inventory/source-items, campo status) — Adobe Commerce Developer
- Inventory Management — Reservations (append-only, salable quantity) — Adobe Commerce Developer
- Inventory Management CLI reference (list-inconsistencies, create-compensations) — Adobe Experience League
- System Requirements (Adobe Commerce 2.4.8 — RabbitMQ 4.1, PHP 8.4) — Adobe Experience League
- Bling API v3 — Limites (3 req/s, 120.000/dia, 429) — Bling (ERP)
- Bling API v3 — Referência da API (REST, OAuth 2.0, Bearer) — Bling (ERP)
- Limites de Consumo da API do Omie (IP + App Key + Método) — Omie
- Aplicativos API V3 (Olist/Tiny) — Configurações e Utilização (OAuth2) — Olist / Tiny
- Portal Nacional da Nota Fiscal Eletrônica (NF-e) — MOC e Notas Técnicas — Receita Federal / SEFAZ