Em 2026, a perceção do WordPress mudou. Já não é visto apenas como um motor de blogues. Amadureceu para um motor de API. Uma abordagem API-first significa que o núcleo da implementação é a estrutura dos dados e a sua acessibilidade, não o tema visual. O núcleo que usamos em produção é WordPress 7.1 (a 7.0 saiu a 20 de maio de 2026) sobre PHP 8.4. O frontend, quando existe à parte, é Astro 7, não um tema PHP a pintar HTML em cada pedido.
Para empresas, o WordPress funciona como o hub de conteúdos que alimenta o sítio público, a aplicação móvel e várias ferramentas internas. Para ter sucesso neste ecossistema, os programadores têm de ir além de wp_head() e wp_footer() e dominar a orquestração de dados headless. Em Portugal essa orquestração inclui um segundo contrato que o catálogo não cobre: quem emite a fatura, quem assina o callback da SIBS / IfthenPay / Eupago, e onde se guardam os tokens sob o RGPD e o critério da CNPD.
Neste guia de mais de 2500 palavras, cobrimos as estratégias e tecnologias do WordPress API-first em 2026. Filas, idempotência e reconciliação com o ERP estão no guia de arquitetura de integração WooCommerce ERP 2026. Aqui entra o corte das APIs numa migração de loja: mapa de URLs, cutover de webhooks e janela de escrita dupla.
Conheça os serviços headless WordPress e a integração WooCommerce ERP.
1. O que é o WordPress API-First?
O desenvolvimento tradicional começa pelo design. Um ficheiro do Figma chega à agência, o tema cresce à volta dele, e a API aparece no fim, se aparecer. No API-first o trabalho começa pelos custom post types e endpoints. Este corte tem consequências para a arquitetura, a escala e a manutenção. A loja portuguesa que só desenha o tema e deixa a faturação para “um plugin no fim” descobre o corte na primeira inspeção da AT, não no kick-off.
O contrato de dados
Define exatamente como os dados (artigos, produtos, utilizadores) vão ser estruturados e expostos. Esse contrato é a base sobre a qual o resto se constrói. Num projeto português o contrato também declara que campos o WordPress não emite: número de fatura, ATCUD, código de validação da série, QR do documento. Esses valores voltam do software certificado e guardam-se como metadado imutável da encomenda.
Exemplo de contrato de leitura (catálogo, não documento fiscal):
{
"endpoint": "/wp-json/v1/products",
"method": "GET",
"response": {
"id": "integer",
"sku": "string",
"name": "string (max: 200)",
"price": "float (2 decimals)",
"currency": "string (ISO 4217)",
"categories": "array<string>",
"availability": "enum: in_stock|out_of_stock|preorder",
"metadata": {
"seo_title": "string (max: 60)",
"seo_description": "string (max: 160)"
}
}
}
O contrato de escrita é outro objeto. Stock, preço e título não viajam no mesmo POST. Um bot de armazém que acerta qty não pode pisar tax_class. Um editor que publica um artigo não pode assinar um callback MB WAY.
Independência do backend
Quando a API está pronta, a equipa de Astro 7 e a equipa móvel trabalham em paralelo sobre a mesma fonte. O atraso deixa de ser “o tema ainda não tem o bloco”. Passa a ser “o endpoint ainda não devolve o campo”. Isso é visível, mensurável, e negociável.
Na prática, um projeto API-first em 2026 tem três artefactos no repositório antes da primeira linha de CSS:
- O esquema do CPT e das taxonomias, com os campos que o editor realmente preenche.
- A coleção OpenAPI ou o schema GraphQL, com tipos, erros e códigos HTTP.
- A lista do que a loja não gera, incluindo série ATCUD, número de documento e qualquer identificador que a AT já tenha atribuído ao software certificado.
Sem o terceiro ponto, o contrato mente. O frontend pede um invoice_number ao WooCommerce, o plugin inventa uma sequência, e o Primavera emite outra. O cliente recebe dois números. A contabilidade fecha zero.
A independência também corta o hábito de meter lógica comercial no functions.php do tema. Um endpoint de stock, um consumidor de fila e um validador de NIF vivem num plugin com histórico de versões. O tema descreve apresentação. Quando o redesign chega, a API continua.
SAF-T (PT), séries ATCUD e software certificado de faturação
Em Portugal a regra do emissor certificado inverte a direção da integração antes de se escrever a primeira linha de REST. O software que emite faturas tem de estar certificado pela Autoridade Tributária e Aduaneira. O número de certificação sai no documento. Isto não é uma preferência de arquitetura. É condição de legalidade do documento.
A loja WooCommerce, na instalação normal, não é software certificado. Por isso a loja não emite a fatura. A loja regista a encomenda. O software certificado (PHC, Primavera, Sage) emite o documento fiscal e devolve o ATCUD. O POST a /wp-json/wc/v3/orders cria o pedido, o estado, o NIF, a morada e as linhas. Não cunha a série. Não incrementa o contador fiscal. Não desenha o QR da AT.
A regra do emissor certificado inverte a direção da API
A intuição de um programador REST é: a loja é a origem, o ERP consome. Em Portugal, para o documento fiscal, a origem é o software certificado. A loja é um cliente que pede a emissão e espera um retorno. Se inverter esta seta, o WooCommerce passa a comportar-se como sistema informático de faturação. Herda a obrigação de certificação que não cumpre.
O fluxo que fecha com a AT é curto:
- A loja cria a encomenda (REST WooCommerce ou checkout clássico).
- O pagamento confirma-se (callback MB WAY ou Multibanco).
- A integração pede a emissão ao PHC, ao Primavera ou ao Sage, com uma chave de idempotência.
- O software certificado comunica a série, emite o documento, devolve ATCUD, número e QR.
- A loja grava esses campos como metadado. O PDF que o cliente vê é o do emissor, ou um reflexo fiel dele.
O guia de arquitetura WooCommerce ERP 2026 cobre filas, bloqueios e reconciliação. Este artigo cobre o corte da API: que rotas existem, o que cada uma pode escrever, e o que é falha de desenho mandar a loja inventar.
A loja regista a encomenda, o certificado devolve o ATCUD
O ATCUD (código único do documento) nasce da série documental comunicada à AT, que devolve um código de validação. A série é um recurso registado no software certificado. Não é um AUTO_INCREMENT na tabela de encomendas. Uma integração que atribui numeração no lado do WordPress produz documentos que não fecham com a contabilidade e obriga a anulações.
O SAF-T (PT) fecha o ciclo mensal. É o ficheiro que a empresa entrega à AT, gerado a partir da contabilidade, não a partir da loja. Para o ficheiro fechar, cada encomenda tem de trazer de volta o identificador do documento fiscal. Se a sincronização for só da loja para o ERP, o fecho mensal vira trabalho manual no gabinete de Aveiro, no contabilista do Porto, ou no parceiro Sage que herda o caos.
Um caso que vemos com regularidade: loja B2B em WooCommerce, armazém no continente, expedição CTT e Chronopost para ilhas, NIF validado no checkout. A equipa pede “o plugin de faturas do WordPress porque é mais simples”. A simplificação transfere para a loja um requisito de certificação que ela não cumpre. Perder essa discussão no levantamento sai mais barato do que na primeira inspeção.
Moloni, InvoiceXpress e Vendus aparecem em PMEs como emissor certificado mais leve. PHC CS, Primavera e Sage aparecem quando já existe contabilidade de empresa. A API-first não escolhe a marca. Escolhe a seta: a loja pede, o certificado responde.
O WooCommerce REST não cunha o número de fatura
POST /wp-json/wc/v3/orders aceita meta_data. Isso não é licença para gravar invoice_number gerado em PHP. O campo fiscal entra depois do retorno do PHC, do Primavera ou do Sage, e entra imutável. Um segundo POST que tente “corrigir” o ATCUD é um incidente, não uma sincronização.
Rotas estreitas ajudam. Uma rota pt-erp/v1/fiscal-return recebe order_id, atcud, document_number, series_validation_code, event_id. O permission_callback está ligado a uma chave WooCommerce de escrita, não a um editor humano. Se o mesmo event_id regressar, a rota responde o resultado já gravado e não pede segunda emissão.
O PDF, o QR e a menção ao número de certificação do software saem do emissor. Recalcular o QR na loja é a forma mais rápida de divergir do que a AT espera ler.
MB WAY, Multibanco e a chave de idempotência partilhada
Os callbacks da IfthenPay, da Eupago ou da SIBS não são “mais um webhook de marketing”. São uma segunda via de escrita sobre a mesma encomenda. MB WAY e referência Multibanco podem notificar duas vezes. Podem notificar fora de ordem. Podem notificar o servidor antigo durante um cutover.
A chave de idempotência tem de ser a mesma no callback de pagamento e no retorno fiscal. Se o TPV diz “pago” duas vezes e o PHC recebe dois pedidos de emissão, saem dois documentos ou nenhum. Se o Multibanco confirma depois do MB WAY sobre o mesmo pedido, a fila vê um único event_id e o certificado emite uma vez.
Três regras de corte que cabem no contrato de API:
- A URL de notificação servidor a servidor é a única via que passa a encomenda a “em processamento”. A página de retorno do browser só pinta o recibo.
- A verificação da antiphishing key / HMAC corre em tempo constante (
hash_equals). Sem assinatura válida, não há mudança de estado. - O pedido de emissão fiscal só arranca depois do pagamento confirmado, com o mesmo
event_idque o callback já gravou.
Durante uma migração (PrestaShop, Magento ou um WooCommerce velho para um novo), o trabalho de API reduz-se a três peças. Não é um guia Shopify. É o mapa de contratos: cada URL de callback tem destino; os emissores pausam, a fila drena, as URLs novas registam-se; origem e destino aceitam eventos durante um intervalo curto com a mesma chave. Depois congela-se a origem. O PHC, o Primavera ou o Sage só veem um event_id por operação.
CNPD e o armazenamento de tokens
Abrir o WordPress por API em Portugal é um tratamento de dados. A CNPD não distingue “é só uma API key” de um segredo que abre encomendas, moradas e NIFs. O artigo 32.º do RGPD aplica-se ao cofre desses tokens. O artigo 33.º obriga a notificar a autoridade de controlo em 72 horas se a violação afetar dados pessoais. Um dump de chaves REST com acesso a encomendas é uma violação.
As Application Passwords vivem no utilizador WordPress, com hash em usermeta. As chaves ck_ / cs_ do WooCommerce vivem em woocommerce_api_keys. A antiphishing key da IfthenPay e o segredo da Eupago não saem da origem. Nenhum destes valores se copia para wp_options em claro, nem para um repositório, nem para o binário de uma app Flutter.
Rotação por evento de saída de pessoas, não “quando alguém se lembrar”. IPs em logs que saem do EEE vão com hash. O frontend headless leva um token de leitura. O ERP de stock leva uma chave de escrita de catálogo. O callback de pagamento não usa a mesma credencial que o editor.
2. Dominar endpoints REST API personalizados
A REST API por omissão do WordPress cobre leituras de conteúdo. Projetos empresariais exigem lógica própria que reduza idas à base e proteja dados sensíveis. A REST API do WooCommerce em /wp-json/wc/v3/ cobre produtos, encomendas e cupões. O stock que chega de um ERP não deve passar por um PUT genérico ao produto: um campo a mais (preço, título, tax class) pisa-se em silêncio.
Isolamento da lógica de negócio
Em vez de dez pedidos para montar o histórico de compras de um utilizador, construímos um único endpoint wp-json/v1/user-commerce que devolve um objeto JSON já cortado para o ecrã.
add_action('rest_api_init', function () {
register_rest_route('v1', '/user-commerce/(?P<id>\\d+)', [
'methods' => 'GET',
'callback' => 'get_user_commerce_data',
'permission_callback' => 'verify_api_token',
'args' => [
'id' => [
'validate_callback' => static function ($param) {
return is_numeric($param);
},
],
],
]);
});
function get_user_commerce_data($request) {
$user_id = (int) $request['id'];
return [
'orders' => get_user_orders($user_id),
'subscriptions' => get_user_subscriptions($user_id),
'loyalty_points' => get_user_loyalty($user_id),
'recommendations' => get_user_recommendations($user_id),
];
}
Este agregado lê. Não escreve fatura. Não mexe em stock. Não confirma Multibanco. Cada uma dessas escritas tem rota própria, chave própria e event_id próprio.
Rotas REST próprias para stock
O ERP é a fonte de verdade das existências. O WooCommerce só aplica o delta. Uma rota estreita (sku, qty, warehouse, event_id) com permission_callback ligado a uma chave WooCommerce de escrita, não a um administrador humano, evita que um token editorial mova inventário.
add_action('rest_api_init', function () {
register_rest_route('wc-erp/v1', '/stock', [
'methods' => 'POST',
'callback' => 'wpp_apply_stock_delta',
'permission_callback' => 'wpp_verify_wc_write_key',
'args' => [
'sku' => ['required' => true, 'type' => 'string'],
'qty' => ['required' => true, 'type' => 'integer'],
'event_id' => ['required' => true, 'type' => 'string'],
],
]);
});
event_id é a chave de idempotência. Se o Primavera reenviar o mesmo ajuste, a rota responde o resultado já conhecido e não volta a subtrair. O padrão de filas e bloqueios está no guia de arquitetura WooCommerce ERP. Aqui basta não abrir /wc/v3/products/<id> a um robot de armazém em Gaia.
A mesma disciplina aplica-se ao retorno fiscal. Stock e ATCUD não partilham payload. Partilham a ideia: rota estreita, chave de escrita, idempotência, resposta cacheada do primeiro sucesso.
Application Passwords frente a chaves API do WooCommerce
O WordPress e o WooCommerce autenticam dois mundos. Não os misture. As Application Passwords vivem no utilizador WordPress, vão com hash para usermeta e herdam as suas capacidades: um editor, uma app móvel ou um script contra /wp-json/wp/v2/. As chaves REST do WooCommerce (ck_ / cs_) vivem em woocommerce_api_keys, com permissão read, write ou read_write, e autenticam /wp-json/wc/v3/.
Um ERP de stock usa uma chave write de catálogo. Um front Astro 7 usa read. Nunca uma Application Password de administrador no binário da app. Rodar uma chave WooCommerce não desliga a equipa de conteúdos. Rodar um Application Password não corta a sincronização do armazém.
Na app Flutter o checkout autenticado passa pela origem PHP. A app não leva ck_ de escrita. Essa chave reembolsa e mexe em stock. Um binário descompilado com uma chave de escrita é um incidente CNPD à espera de data.
Validação e sanitização
Usamos as funções nativas de register_rest_route para forçar validação de entrada, de modo a que a API resista a injeções.
Camadas de validação:
- Tipo de dados: cada parâmetro confronta o tipo esperado.
- Intervalo: valores numéricos têm mínimo e máximo.
- Formato: strings confrontam padrões (SKU, NIF,
event_id). - Sanitização: toda a entrada passa por sanitização antes de ir à base.
- Autorização: cada pedido verifica as permissões do token, não só a sua existência.
O NIF no checkout B2B valida-se contra o serviço público antes da encomenda avançar. Um NIF inválido não chega ao PHC. Um payload que meta HTML no billing.address_1 não chega à fatura.
3. WordPress como um content mesh
Em 2026, as organizações grandes tratam o WordPress como um nó numa malha de serviços, não como o sítio onde “está o site”. O conteúdo sai para o Astro 7, para a app, para o CRM, para o catálogo. O stock e o documento fiscal entram de outros nós. A malha só funciona se cada aresta tiver contrato, idempotência e um dono.
Sincronização com sistemas externos
O WordPress não se limita a guardar conteúdo. Sincroniza nos dois sentidos. Uma atualização de produto no SAP, no PHC ou no Primavera pode disparar uma atualização na API WordPress, que depois atualiza a loja e a app.
Fluxo de leitura de catálogo:
[ERP certificado] → webhook → [WordPress API] → webhook → [Frontend Astro 7]
→ webhook → [App móvel Flutter]
→ webhook → [CRM HubSpot]
O fluxo fiscal, como a secção anterior deixou claro, corre ao contrário no último quilómetro: a loja pede a emissão, o certificado responde. Misturar as duas setas no mesmo consumidor de fila é a forma clássica de duplicar documentos numa campanha de Black Friday.
Quando o corte é uma migração de loja, o trabalho de API reduz-se a três peças:
- Mapa de URLs: cada rota REST e cada URL de callback (IfthenPay, Eupago, SIBS) da origem tem destino. Sem mapa, o TPV continua a notificar o servidor antigo e as encomendas ficam em “pendente de pagamento”.
- Cutover de webhooks: pausam-se os emissores, drena-se a fila, registam-se as URLs novas. Um webhook órfão durante o corte duplica encomendas ou perde stock.
- Janela de escrita dupla: origem e destino aceitam eventos durante um intervalo curto, com a mesma chave de idempotência. Depois congela-se a origem.
Webhooks e eventos
Usamos ganchos para notificar serviços externos quando um artigo é publicado ou um utilizador se regista. O mesmo mecanismo serve o Slack editorial. Não serve, sozinho, o callback MB WAY.
add_action('transition_post_status', function ($new, $old, $post) {
if ($new === 'publish' && $old !== 'publish') {
$payload = [
'event' => 'content_published',
'post_id' => $post->ID,
'title' => $post->post_title,
'url' => get_permalink($post->ID),
'timestamp' => current_time('c'),
];
$subscribers = get_webhook_subscribers('content_published');
foreach ($subscribers as $subscriber) {
wp_remote_post($subscriber['url'], [
'body' => wp_json_encode($payload),
'headers' => ['Content-Type' => 'application/json'],
'timeout' => 5,
]);
}
}
}, 10, 3);
Este disparo é melhor esforço. Um timeout de 5 segundos e um foreach síncrono no pedido HTTP do editor não é a fila do pagamento. Publicar um artigo pode falhar a notificação ao Slack. Confirmar um Multibanco não pode.
Arquitetura orientada a eventos
Em 2026, a arquitetura baseada em eventos substituiu as ligações ponto a ponto para o tráfego que não pode perder-se:
- Fila de mensagens: Redis Streams ou RabbitMQ como broker.
- Processamento assíncrono: os eventos correm em segundo plano, fora do TTFB do checkout.
- Retry com recuo: falhas transitórias repetem-se com jitter.
- Dead letter queue: o que falha de forma repetida sai da linha quente e fica para investigação.
Os callbacks MB WAY e Multibanco não se tratam como mais um webhook de marketing. São uma segunda via de escrita sobre a mesma encomenda. Se o broker e o TPV não partilharem a chave de idempotência, o ERP emite duas faturas ou nenhuma. O wp-cron.php não é o consumidor desta fila. Um daemon WP-CLI ou um worker PHP 8.4 à parte é.
4. Performance da camada API
Uma das queixas históricas sobre a API WordPress era a velocidade. Em 2026 resolvemos isto com cache em camadas, e com a disciplina de não cachear o que não pode devolver um 200 velho.
Cache de objetos (Redis)
Guardamos respostas da API em memória para não repetir SQL caro. Cada endpoint tem a sua estratégia, consoante a volatilidade. Os endpoints de notificação de pagamento e de regresso fiscal não têm cache de resposta: um 200 antigo com um HMAC já verificado não se deve reaplicar.
| Endpoint | TTL Redis | Invalidação |
|---|---|---|
| /posts | 5 minutos | Ao publicar ou atualizar o artigo |
| /products | 2 minutos | Ao mudar preço ou stock |
| /menu | 1 hora | Ao editar o menu |
| /settings | 24 horas | Ao mudar opções |
| /user-data | 0 (sem cache) | Dados em tempo real |
| /ifthenpay-callback, /wc-erp/v1/stock, /pt-erp/v1/fiscal-return | 0 (sem cache) | Só idempotência por event_id |
Vinte milissegundos no edge para uma listagem de produtos é um objetivo razoável. Vinte milissegundos para um callback Multibanco é um incidente com fatura a mais.
Cache no edge
Com Cloudflare (ou equivalente), o JSON de catálogo serve-se a partir de um PoP perto do leitor, não a partir do PHP de origem. As rotas autenticadas, o stock ao vivo e os callbacks do TPV saem do edge e vão à origem.
function add_api_cache_headers($response) {
if (is_wp_error($response)) {
return $response;
}
$response->header('Cache-Control', 'public, max-age=300, stale-while-revalidate=60');
$response->header('CDN-Cache-Control', 'max-age=600');
$response->header('Surrogate-Control', 'max-age=3600');
return $response;
}
add_filter('rest_post_dispatch', 'add_api_cache_headers');
Este filtro não se aplica a wc-erp/v1, a pt-erp/v1 nem à URL de notificação da IfthenPay ou da Eupago. Um Cache-Control: public num callback de pagamento não é uma otimização.
A listagem de produtos pode, e deve, viver no edge. O availability agressivo no edge durante uma campanha é outra conversa: aí o TTL cai para segundos, ou o campo de stock sai do payload público e a app pergunta à origem.
GraphQL como alternativa de leitura
Para ecrãs complexos, GraphQL via WPGraphQL corta o over-fetching. Uma query pede o produto, as categorias e três relacionados. Várias idas REST desaparecem.
query ProductPage {
product(id: "123") {
title
price
description
categories {
name
slug
}
relatedProducts(first: 3) {
title
thumbnail
}
}
}
GraphQL não substitui as rotas de escrita de stock nem o webhook do TPV. Essas mutações continuam em REST estreito. Um mutation que emita fatura no WordPress é o mesmo erro de direção, com schema mais bonito.
Rate limiting na origem (por exemplo 60 pedidos por minuto por IP) vive no Redis do cluster, não em transients. As IPs de notificação da IfthenPay, da Eupago e da SIBS saem do limite: um 429 ao TPV deixa o pagamento feito no banco e a encomenda pendente no WooCommerce. CORS apertado, HTTPS obrigatório, logs de acesso com IP com hash se saírem do EEE, e rotação de tokens por saída de pessoas completam a superfície. Nada disto é decoração. É o mínimo para a malha não ser uma porta aberta com NIF à vista.
5. Porque a WPPoland é o seu parceiro API-first
Na WPPoland o trabalho API-first não começa no tema. Começa no contrato.
- Endpoints à medida: desenhamos APIs para a aplicação móvel ou web, com rotas estreitas para stock, catálogo e regresso fiscal. O preço do projeto é individual. Fecha-se depois do âmbito.
- Integração de sistemas: ligamos o WordPress a ERP (SAP, PHC, Primavera, Sage) e a CRM (HubSpot, Salesforce). A seta fiscal em Portugal fica explícita no desenho: a loja regista, o certificado emite.
- Consultoria headless: ajudamos a decidir se a abordagem API-first é a certa para o negócio, e se o frontend deve ser Astro 7, uma app, ou os dois. Os serviços headless WordPress e a integração WooCommerce ERP são as portas de entrada.
Não vendemos um plugin que “resolve a faturação portuguesa” a partir do WooCommerce. Essa frase é o sinal de que o corte da API ainda não foi feito.
6. Conclusão: O hub da web moderna
O WordPress é o backend mais flexível que a maior parte das equipas editoriais consegue realmente usar. Ao adotar uma filosofia API-first, sai-se do molde de sítio padrão. O CMS passa a ser o hub que alimenta o Astro 7, a app e as ferramentas internas, com um contrato que diz o que a loja gera e o que só o software certificado pode devolver.
Em Portugal esse contrato tem uma frase que não é opcional. A loja regista a encomenda. O PHC, o Primavera ou o Sage emitem o documento e devolvem o ATCUD. O WooCommerce REST não cunha o número de fatura. MB WAY e Multibanco partilham a chave de idempotência com esse retorno. A CNPD aplica-se ao sítio onde os tokens dormem.
Se os dados ainda estão presos num tema tradicional, ou se a loja ainda inventa séries fiscais, fale connosco. O contacto chega ao mesmo sítio que os serviços de desenvolvimento WordPress.




