Primeiro prazo DPP da UE (Baterias): 130 dias Garanta a conformidade agora
Idioma
EN DE FR IT ES NL PL BG CS DA EL ET FI HR HU LT LV MT PT RO SK SL SV
Produto
Funcionalidades Pós-venda Como funciona Demonstração Enterprise Preços
Setores
Todos os setores Têxteis Eletrónica Baterias
Recursos
Blogue Comparar software de DPP Requisitos por país Avaliação de preparação Verificador de alegações ecológicas Transferências gratuitas Glossário
Empresa
Parceiros Contacto
Iniciar sessão Começar grátis
Programadores / REST API

Referência da API

Tudo na MyProductPassport está disponível através de uma API REST autenticada por chave: crie produtos, gere e publique Passaportes Digitais de Produto, envie dados de baterias em tempo real e verifique a conformidade, diretamente do seu ERP, PIM ou pipeline de build.

v1 https://myproductpassport.eu/api/v1 Começar grátis Especificação OpenAPI ↓

01 / Primeiros passosAutenticação

Cada pedido é autenticado com uma chave de API enviada como token Bearer. As chaves são criadas na aplicação em Chaves de API, mostradas uma vez e guardadas com hash; cada chave tem o seu conjunto de permissões, uma lista opcional de IPs permitidos e uma data de expiração opcional. As chaves podem ser rodadas sem tempo de inatividade.

Cabeçalho do pedido
Authorization: Bearer pk_your_api_key
Em todos os planos. As chaves API podem ser criadas e usadas em todos os planos, incluindo o gratuito. O plano define quantos pedidos por minuto uma chave pode fazer (abaixo) e quantos produtos e passaportes o espaço de trabalho pode ter.
Modo de teste. Uma chave de teste (pk_test_...) executa cada chamada exatamente como uma chave de produção, com a mesma validação, os mesmos IDs e as mesmas respostas, e depois anula-a: nada é guardado, nenhum email ou webhook é enviado e nenhum ficheiro é mantido. As respostas incluem "test_mode": true e um cabeçalho X-MPP-Mode: test. Crie e teste uma integração com os seus dados reais e, depois, passe a usar uma chave de produção.

As permissões são concedidas por chave, para que uma integração só obtenha o que precisa:

PermissãoAutorizações
products:readLer produtos
products:writeCriar, atualizar e eliminar produtos
passports:readLer passaportes
passports:writeGerar passaportes
passports:publishPublicar e arquivar passaportes
webhooks:manageCriar, testar e remover endpoints de webhook
items:readRead individual items and their history
items:writeAdd, update and flag individual items
aftersales:readRead owner registrations and service requests
aftersales:writeUpdate service requests and reply to customers

02 / Primeiros passosLimites de pedidos

Os limites são por chave, por minuto, e definidos pelo plano:

PlanoPedidos / minuto
Grátis30
Micro60
Rótulo eletrónico60
Starter120
Professional300
Business600
Battery600

Cada resposta inclui os cabeçalhos X-RateLimit-Limit e X-RateLimit-Remaining. Exceder o limite devolve 429:

429 Too Many Requests
{ "error": "Rate limit exceeded.", "limit": 300, "retry_after": 60 }

03 / Primeiros passosErros

Os erros são JSON com um código de estado convencional. Os mais comuns:

EstadoSignificadoCorpo de exemplo
401Chave em falta, inválida, revogada ou expirada{"error": "Invalid or revoked API key."}
403Falta uma permissão à chave, o IP não está na lista permitida ou foi atingido o limite do plano{"message": "API key does not have 'products:write' permission."}
404O recurso não existe no seu espaço de trabalho{"message": "Not found."}
422A validação falhou{"message": "…", "errors": {"gtin": ["…"]}}
429Limite de pedidos excedido{"error": "Rate limit exceeded."}

04 / Primeiros passosPaginação

Os endpoints de listagem devolvem 25 itens por página com os objetos links e meta padrão. Passe ?page=2 para percorrer a coleção.

05 / Primeiros passosConector de assistente de IA (MCP)

Ligue o Claude, o Cursor ou qualquer assistente que fale o Model Context Protocol e peça-lhe, por palavras simples, que crie produtos, preencha passaportes com o que lhe disser e verifique o que ainda falta. Usa uma chave API com as permissões e o limite de pedidos dessa chave. Pode criar rascunhos e preencher campos; nunca publica, arquiva ou elimina nada: isso continua consigo na aplicação.

Endereço do servidor (Streamable HTTP)
https://myproductpassport.eu/api/mcp
Claude Code
claude mcp add --transport http myproductpassport https://myproductpassport.eu/api/mcp \
  --header "Authorization: Bearer pk_live_your_key"
Cursor (mcp.json)
{
  "mcpServers": {
    "myproductpassport": {
      "url": "https://myproductpassport.eu/api/mcp",
      "headers": { "Authorization": "Bearer pk_live_your_key" }
    }
  }
}
Claude Desktop e outros clientes que iniciam um servidor local
{
  "mcpServers": {
    "myproductpassport": {
      "command": "npx",
      "args": ["mcp-remote", "https://myproductpassport.eu/api/mcp", "--header", "Authorization: Bearer pk_live_your_key"]
    }
  }
}

As ferramentas disponíveis:

FerramentaO que faz
list_productsOs produtos do espaço de trabalho, do mais recente, 25 por página, com o setor e o último passaporte.
get_productUm produto com os detalhes, setor, secções regulamentares e último passaporte.
list_sectorsOs modelos de setor que um produto pode usar (têxteis, eletrónica, baterias, vinho e outros), com os respetivos IDs. O setor de um produto decide que campos do passaporte são obrigatórios.
create_productAdiciona um produto ao espaço de trabalho. Use um sector_id de list_sectors. compliance_sections acrescenta secções regulamentares ao passaporte: gpsr, epr, france, chemicals, eudr.
list_passportsOs passaportes do espaço de trabalho, do mais recente, 25 por página, com estado (draft, published, archived), percentagem de conformidade e endereço público.
get_passportUm passaporte: estado, versão, percentagem de conformidade, endereço público e ligações ao código QR.
create_passportCria um passaporte em rascunho para um produto. Não é publicado: é uma pessoa que o publica na aplicação.
get_passport_fieldsO que um passaporte pede: as chaves dos campos obrigatórios e opcionais, o significado de cada um (rótulo, descrição, exemplo), os valores existentes e que campos obrigatórios faltam.
update_passport_fieldsEscreve valores de campos num passaporte em rascunho ou publicado (um publicado é atualizado no local: mesmo endereço, mesmo código QR). Chaves de get_passport_fields; um texto vazio remove um valor. Escreva apenas factos indicados pelo utilizador ou pelos seus documentos.
get_complianceA completude de um passaporte: percentagem, estado e os campos obrigatórios ainda em falta.
Experimente com uma chave de teste. Com uma chave de teste (pk_test_...) as alterações do assistente são verificadas e depois anuladas, para ver o que faria antes de lhe dar uma chave real.

06 / EndpointsConta

GET /me

Devolve a conta autenticada, o seu nível de subscrição e quanto do limite de produtos está usado. Útil como verificação de ligação.

Pedido
curl https://myproductpassport.eu/api/v1/me \
  -H "Authorization: Bearer pk_your_key"
Resposta
{
  "data": {
    "id": 42,
    "name": "Jane Doe",
    "email": "[email protected]",
    "company_name": "Acme Ltd",
    "subscription_tier": "professional",
    "product_count": 128,
    "product_limit": 500,
    "passport_count": 96,
    "organization": {"id": 7, "name": "Acme Ltd"},
    "api_key": {"name": "ERP sync", "permissions": ["*"], "rate_limit_per_minute": 1000, "expires_at": null},
    "webhooks_available": true
  }
}

07 / EndpointsProdutos

GET /products requer products:read

Lista os produtos do seu espaço de trabalho, do mais recente para o mais antigo, 25 por página. Cada produto inclui o seu setor e um resumo do passaporte mais recente.

ParâmetroTipoDescrição
pageintegerNúmero da página.
Pedido
curl "https://myproductpassport.eu/api/v1/products?page=1" \
  -H "Authorization: Bearer pk_your_key"
Resposta
{
  "data": [
    {
      "id": 512,
      "name": "Alpine Merino Crew Sweater",
      "sku": "AM-CREW-01",
      "gtin": "05012345678900",
      "brand": "Northloom",
      "category": "textiles",
      "status": "active",
      "country_of_origin": "PT",
      "weight": 0.4,
      "weight_unit": "kg",
      "materials": [
        { "name": "Merino wool (RWS)", "percentage": 78 },
        { "name": "Recycled nylon (GRS)", "percentage": 20 },
        { "name": "Elastane", "percentage": 2 }
      ],
      "sector": { "id": 3, "name": "Textiles" },
      "latest_passport": {
        "id": 96, "version": 1,
        "status": "published", "compliance_percentage": 100
      },
      "created_at": "2026-08-14T09:21:00+00:00",
      "updated_at": "2026-09-01T16:02:11+00:00"
    }
  ],
  "links": { "next": null },
  "meta": { "current_page": 1, "per_page": 25, "total": 1 }
}
POST /products requer products:write

Cria um produto. Devolve 403 se o limite de produtos do plano estiver esgotado.

ParâmetroTipoDescrição
namestringobrigatórioNome do produto, até 255 caracteres.
skustringO seu SKU interno, até 100 caracteres.
gtinstringGTIN-8, 12, 13 ou 14 (apenas dígitos).
brandstringMarca apresentada no passaporte público.
descriptionstringAté 2000 caracteres.
categorystringCategoria em texto livre. Por predefinição "general".
sector_idintegerUm ID de setor, que seleciona o modelo de campos do passaporte.
country_of_originstringCódigo do país, p. ex. "PT".
weightnumberPeso líquido.
weight_unitstringUm de kg, g, lb, oz. Por predefinição, kg.
materialsarrayObjetos {name, percentage 0-100}.
has_packagingbooleanAdiciona ao passaporte os campos do modelo de embalagem (chaves que começam por pkg_), sob o mesmo código QR.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/products \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Alpine Merino Crew Sweater",
    "sku": "AM-CREW-01",
    "gtin": "05012345678900",
    "sector_id": 3,
    "materials": [
      {"name": "Merino wool (RWS)", "percentage": 78},
      {"name": "Recycled nylon (GRS)", "percentage": 22}
    ]
  }'
Resposta
{
  "data": {
    "id": 513,
    "name": "Alpine Merino Crew Sweater",
    "sku": "AM-CREW-01",
    "status": "active",
    "sector": { "id": 3, "name": "Textiles" },
    "created_at": "2026-09-07T18:40:00+00:00"
  }
}
POST /products/bulk requer products:write

Cria até 100 produtos numa chamada. O lote inteiro é recusado com 403 se exceder o limite de produtos restante. Para catálogos com milhares de produtos, chame este endpoint em ciclo ou use a importação CSV na aplicação.

ParâmetroTipoDescrição
productsarrayobrigatório1 a 100 objetos de produto com os mesmos campos de «Criar um produto» (sem materiais).
Pedido
curl -X POST https://myproductpassport.eu/api/v1/products/bulk \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "products": [
      {"name": "PSL-BT-122000", "sku": "PSL-BT-122000", "sector_id": 5},
      {"name": "PSL-BT-123000", "sku": "PSL-BT-123000", "sector_id": 5}
    ]
  }'
Resposta
{
  "message": "2 product(s) created.",
  "products": [
    { "id": 514, "name": "PSL-BT-122000", "status": "active" },
    { "id": 515, "name": "PSL-BT-123000", "status": "active" }
  ]
}
GET /products/{id} requer products:read

Devolve um produto com o seu setor e o resumo do passaporte mais recente. 404 se o id não estiver no seu espaço de trabalho.

Pedido
curl https://myproductpassport.eu/api/v1/products/512 \
  -H "Authorization: Bearer pk_your_key"
PUT /products/{id} requer products:write

Atualiza parcialmente um produto. Envie apenas os campos que pretende alterar; a lista de campos é igual à de Criar um produto.

Pedido
curl -X PUT https://myproductpassport.eu/api/v1/products/512 \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"brand": "Northloom"}'
DELETE /products/{id} requer products:write

Elimina um produto de forma recuperável. Os passaportes publicados do produto continuam a funcionar, para que os códigos QR impressos nunca fiquem sem página.

Pedido
curl -X DELETE https://myproductpassport.eu/api/v1/products/512 \
  -H "Authorization: Bearer pk_your_key"
Resposta
{ "message": "Product deleted." }

08 / EndpointsPassaportes

GET /passports requer passports:read

Lista os passaportes, do mais recente para o mais antigo, 25 por página, com resumo do produto e todos os campos do passaporte.

ParâmetroTipoDescrição
pageintegerNúmero da página.
Pedido
curl https://myproductpassport.eu/api/v1/passports \
  -H "Authorization: Bearer pk_your_key"
Resposta
{
  "data": [
    {
      "id": 96,
      "uuid": "36ff3776-d517-4228-8cde-9208136ea84a",
      "version": 1,
      "status": "published",
      "compliance_status": "compliant",
      "compliance_percentage": 100,
      "public_url": "https://myproductpassport.co.uk/p/36ff3776-…",
      "gs1_url": "https://myproductpassport.co.uk/01/05012345678900",
      "product": { "id": 512, "name": "Alpine Merino Crew Sweater", "sku": "AM-CREW-01" },
      "fields": [
        { "key": "material_composition", "value": "…", "verification_status": "verified" }
      ],
      "published_at": "2026-08-16T10:00:00+00:00"
    }
  ],
  "meta": { "current_page": 1, "per_page": 25, "total": 1 }
}
POST /products/{productId}/passports requer passports:write

Gera um rascunho de passaporte para um produto, pré-preenchendo campos a partir dos dados do produto e do modelo do setor. Devolve o rascunho com a sua pontuação de conformidade. Um produto que já tem um passaporte ativo devolve 409 com esse passaporte: corrija-o com PUT /passports/{id}/fields, que mantém o seu endereço e código QR.

Pedido
curl -X POST https://myproductpassport.eu/api/v1/products/512/passports \
  -H "Authorization: Bearer pk_your_key"
GET /passports/{id} requer passports:read

Devolve um passaporte com produto, campos, URL público e GS1 Digital Link.

Pedido
curl https://myproductpassport.eu/api/v1/passports/96 \
  -H "Authorization: Bearer pk_your_key"
POST /passports/{id}/publish requer passports:publish

Publica um rascunho de passaporte, ativando a sua página pública e código QR. Só podem ser publicados rascunhos; tudo o resto devolve 404.

Pedido
curl -X POST https://myproductpassport.eu/api/v1/passports/96/publish \
  -H "Authorization: Bearer pk_your_key"
POST /passports/{id}/archive requer passports:publish

Arquiva um passaporte e retira a sua página pública de circulação.

Pedido
curl -X POST https://myproductpassport.eu/api/v1/passports/96/archive \
  -H "Authorization: Bearer pk_your_key"
POST /passports/bulk-publish requer passports:publish

Publica até 50 rascunhos de passaporte numa chamada e indica o resultado de cada um, para que uma falha nunca interrompa o lote.

ParâmetroTipoDescrição
passport_idsarrayobrigatório1 a 50 IDs de passaporte.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/passports/bulk-publish \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"passport_ids": [96, 97, 98]}'
Resposta
{
  "published": 2,
  "failed": 1,
  "published_ids": [96, 97],
  "errors": [
    { "id": 98, "error": "Compliance below the publishing threshold." }
  ]
}
POST /passports/{id}/successor requer passports:write

Para um produto preparado para reutilização, reaproveitado ou remanufaturado, o Regulamento relativo às baterias (artigo 77.º, n.º 7) exige um novo passaporte ligado ao original. Isto cria um novo registo de produto e um rascunho de passaporte pré-preenchido a partir do publicado, com ligação a ele. O original mantém-se ativo e ambos os passaportes mostram a ligação. Publique o novo com POST /passports/{id}/publish.

ParâmetroTipoDescrição
stagestringobrigatórioprepared_for_reuse, repurposed ou remanufactured.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/passports/96/successor \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "stage": "repurposed" }'
Resposta
{
  "data": {
    "id": 131, "status": "draft", "version": 1,
    "lineage": {
      "stage": "repurposed",
      "original": { "id": 96, "url": "https://myproductpassport.co.uk/p/..." },
      "originals": [{ "passport_id": 96, "product_id": 40, "stage": "repurposed", "status": "published", "url": "https://myproductpassport.co.uk/p/..." }],
      "successors": []
    }
  }
}
GET /passports/{id}/fields requer passports:read

Devolve as chaves de campo que o modelo do setor do passaporte pede (obrigatórias e opcionais), os valores atuais e as chaves obrigatórias ainda em falta. Use-o para construir o corpo de PUT /passports/{id}/fields.

Pedido
curl https://myproductpassport.eu/api/v1/passports/96/fields \
  -H "Authorization: Bearer pk_your_key"
Resposta
{
  "passport_id": 96,
  "sector": "batteries",
  "compliance_percentage": 84,
  "required": ["battery_category", "carbon_footprint", "..."],
  "optional": ["energy_round_trip_efficiency", "..."],
  "missing_required": ["carbon_footprint_class", "recycled_content"],
  "values": { "battery_category": "Industrial", "...": "..." }
}
PUT /passports/{id}/fields requer passports:write

Escreve qualquer conjunto de valores de campos num passaporte em rascunho ou publicado: o conjunto completo do anexo XIII para uma bateria, os campos de um modelo setorial ou as suas próprias chaves. Envie apenas as chaves que pretende alterar; um valor null ou vazio remove esse campo. Um passaporte publicado é atualizado no local, o seu endereço e código QR não mudam e as traduções automáticas são regeneradas. A conformidade é novamente pontuada. Um rascunho não é publicado por esta chamada; use POST /passports/{id}/publish.

ParâmetroTipoDescrição
fieldsobjectobrigatórioMapa de chave de campo para valor. As chaves são letras minúsculas, dígitos e sublinhados; valores até 5000 caracteres. Até 200 chaves por chamada.
Pedido
curl -X PUT https://myproductpassport.eu/api/v1/passports/96/fields \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "carbon_footprint": "61.2 kg CO2e/kWh",
      "carbon_footprint_class": "C",
      "recycled_content": "Cobalt 16%, lithium 6%, nickel 6%, lead 0%"
    }
  }'
Resposta
{
  "message": "3 field(s) changed, 0 removed.",
  "changed": ["carbon_footprint", "carbon_footprint_class", "recycled_content"],
  "removed": [],
  "passport": { "id": 96, "status": "published", "compliance_percentage": 92 }
}
POST /passports/{id}/state-of-health requer passports:write

Envia os dados próprios desta bateria (ponto 4 do Anexo XIII do Regulamento (UE) 2023/1542) para um passaporte publicado, para sistemas BMS e de frotas. Envie qualquer subconjunto dos campos abaixo; a conformidade é reavaliada após a atualização. Estes valores só são mostrados a visitantes aprovados pelo titular do passaporte (artigo 77.º, n.º 2), nunca na página pública. capacity_fade, power_capability e internal_resistance são guardados como leituras atuais desta bateria (current_*), separados dos valores originais do modelo.

ParâmetroTipoDescrição
state_of_healthstringp. ex. "97% aos 412 ciclos".
state_of_certified_energystringEnergia certificada restante (baterias de VE).
battery_statusstringoriginal, repurposed, re-used, remanufactured ou waste.
capacity_fadestringPerda de capacidade até à data. Guardada como current_capacity_fade.
power_capabilitystringCapacidade de potência atual. Guardada como current_power_capability.
internal_resistancestringResistência interna medida. Guardada como current_internal_resistance.
use_datastringCiclos, eventos negativos, temperatura e estado de carga, até 5000 caracteres.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/passports/96/state-of-health \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "state_of_health": "97% at 412 cycles",
    "capacity_fade": "3% from initial rated capacity"
  }'
Resposta
{
  "message": "2 field(s) updated.",
  "updated_fields": ["state_of_health", "current_capacity_fade"],
  "passport": { "id": 96, "status": "published", "compliance_percentage": 100 }
}
POST /passports/{id}/units requer passports:write

Cada bateria precisa do seu próprio passaporte (Regulamento (UE) 2023/1542, artigo 77.º, n.º 1). Registe até 10 000 baterias de um modelo numa chamada, cada uma com o seu número de série (até 20 letras, dígitos, pontos, hífenes ou sublinhados) e, opcionalmente, manufacturing_date, battery_status e os seus dados do ponto 4 do Anexo XIII. Os números de série existentes são atualizados; os valores que omitir são mantidos. Com um GTIN no produto, o endereço de cada bateria é o seu GS1 Digital Link, /01/{gtin}/21/{serial}. Os dados do ponto 4 só são mostrados a visitantes aprovados pelo titular.

ParâmetroTipoDescrição
units[].serialstringobrigatórioO número de série da bateria.
units[].manufacturing_datestringMês e ano, p. ex. "2026-09".
units[].battery_statusstringoriginal ou waste. Uma mudança de estado exige os valores medidos nesse momento (anexo XIII, ponto 4, alínea a)); waste exige também responsible_party_type (producer, pro ou waste_operator), responsible_party_name e responsible_party_contact (artigo 77.º, n.º 7). recycled, com recycled_at e recycler_name, põe termo ao passaporte (artigo 77.º, n.º 8). Uma bateria reconvertida, reutilizada ou remanufaturada recebe um novo passaporte: POST /passports/{id}/units/{serial}/successor.
units[].state_of_healthstringTambém state_of_certified_energy, current_capacity_fade, current_power_capability, current_internal_resistance, remaining_capacity_ah, power_fade, internal_resistance_increase, round_trip_efficiency, round_trip_efficiency_fade, expected_lifetime_cycles_remaining, self_discharge_rate, ohmic_resistance e use_data.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/passports/96/units \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"units": [{"serial": "KES-00001", "manufacturing_date": "2026-09", "state_of_health": "100%"}]}'
Resposta
{ "created": 1, "updated": 0, "skipped": 0, "errors": [] }
PATCH /passports/{id}/units/{serial} requer passports:write

Para um sistema de gestão de baterias que envia os dados de uma bateria: qualquer um de battery_status, state_of_health, state_of_certified_energy, current_capacity_fade, current_power_capability, current_internal_resistance e use_data. Use GET no mesmo caminho para os ler, ou GET /passports/{id}/units para a lista (per_page até 500).

Pedido
curl -X PATCH https://myproductpassport.eu/api/v1/passports/96/units/KES-00001 \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"state_of_health": "96% at 412 cycles"}'
Resposta
{
  "data": { "serial": "KES-00001", "public_url": "https://myproductpassport.co.uk/01/05012345678900/21/KES-00001", "battery_status": "original", "data": { "state_of_health": "96% at 412 cycles" } }
}
GET /passports/{id}/units/{serial}/snapshots requer passports:read

O anexo XIII, ponto 4, alínea a), exige os valores de desempenho e durabilidade quando a bateria é colocada no mercado e quando o seu estado muda. Essas leituras são mantidas tal como estavam, independentemente do que for enviado depois; envie record_snapshot: true com um PATCH para guardar também uma leitura periódica.

Pedido
curl https://myproductpassport.eu/api/v1/passports/96/units/KES-00001/snapshots \
  -H "Authorization: Bearer pk_your_key"
Resposta
{
  "data": [
    { "event": "placed_on_market", "status": "original", "values": { "state_of_health": "100%" }, "measured_at": "2026-09-26T09:00:00+00:00", "source": "api" },
    { "event": "status_change", "status": "waste", "values": { "remaining_capacity_ah": "71 Ah", "power_fade": "14%", "internal_resistance_increase": "22%", "expected_lifetime_cycles_remaining": "0" }, "measured_at": "2029-03-02T10:00:00+00:00", "source": "bms" }
  ]
}
POST /passports/{id}/units/{serial}/successor requer passports:write

Artigo 77.º, n.º 7: uma bateria que tenha sido preparada para reutilização, reconvertida ou remanufaturada tem um novo passaporte ligado ao original. Esta ação regista novamente a bateria, com um novo número de série e identificador, num modelo de bateria de segunda vida do seu espaço de trabalho (criado a partir deste modelo, se ainda não existir), liga os dois e mantém os valores medidos na mudança. A bateria original mantém o seu passaporte. Complete e publique o modelo de segunda vida com POST /passports/{id}/publish.

ParâmetroTipoDescrição
stagestringobrigatórioprepared_for_reuse, repurposed ou remanufactured.
valuesobjectobrigatórioOs valores medidos na mudança: pelo menos um de remaining_capacity_ah ou current_capacity_fade, de current_power_capability ou power_fade, de current_internal_resistance ou internal_resistance_increase, e expected_lifetime_cycles_remaining (anexo IV, parte A).
serialstringO novo número de série. Por predefinição, o número de série original seguido de -RU, -RP ou -RM.
measured_atstringQuando os valores foram medidos.
member_statestringCódigo de duas letras do Estado-Membro onde o estado de saúde foi testado (artigo 73.º, n.º 1, alínea a)).
target_passport_idintegerUm modelo de segunda vida existente deste modelo de bateria, no qual a registar.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/passports/96/units/KES-00001/successor \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"stage": "repurposed", "values": {"remaining_capacity_ah": "82 Ah", "power_fade": "9%", "internal_resistance_increase": "15%", "expected_lifetime_cycles_remaining": "2000"}}'
Resposta
{
  "data": {
    "serial": "KES-00001-RP", "battery_status": "repurposed", "passport_id": 131,
    "lineage": { "originals": [{ "serial": "KES-00001", "passport_id": 96, "stage": "repurposed" }], "successors": [] }
  }
}
POST /passports/{id}/registry requer passports:write

Guarda no passaporte a submissão ao Registo DPP da UE e o respetivo resultado: estado, ID de correlação, o identificador de registo devolvido pelo Registo e uma ligação opcional para uma cópia de segurança alojada por um prestador de serviços DPP. O registo em si é feito no Registo da Comissão (formulário web ou carregamento de ficheiro); isto mantém o resultado junto do passaporte. GET /passports/{id} devolve o mesmo bloco em registry.

ParâmetroTipoDescrição
statusstringnot_submitted, submitted, registered ou failed.
product_groupstringGrupo de produtos do registo, por exemplo batteries.
granularitystringmodelo, lote ou artigo.
upistringIdentificador único do produto como URL https. Por predefinição, o URL do passaporte público.
correlation_idstringID de correlação atribuído pelo registo na submissão.
uristringIdentificador de registo devolvido pelo registo.
backup_urlstringLigação https para a cópia de segurança alojada por um prestador de serviços DPP.
submitted_atdateData de submissão.
registered_atdateData de registo.
errorstringDescrição do erro de uma submissão falhada.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/passports/96/registry \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "registered",
    "correlation_id": "7f3a2c1e-0b4d-4f8e-9a6b-2d1c3e4f5a6b",
    "uri": "urn:eu:dpp:reg:00000001",
    "registered_at": "2027-02-18"
  }'
Resposta
{
  "message": "Registry details updated.",
  "passport": {
    "id": 96,
    "registry": {
      "status": "registered",
      "upi": "https://myproductpassport.co.uk/p/552fbb4e-5d9a-41da-9050-cc9005d8b66b",
      "correlation_id": "7f3a2c1e-0b4d-4f8e-9a6b-2d1c3e4f5a6b",
      "uri": "urn:eu:dpp:reg:00000001",
      "registered_at": "2027-02-18T00:00:00+00:00"
    }
  }
}
GET /passports/{id}/qr requer passports:read

O código QR do passaporte como ficheiro: svg (predefinição), png (com a marca, pronto a imprimir) ou pdf (folha de etiquetas).

ParâmetroTipoDescrição
formatstringsvg | png | pdf
Pedido
curl "https://myproductpassport.eu/api/v1/passports/96/qr?format=png" \
  -H "Authorization: Bearer pk_your_key" -o passport-96.png

09 / EndpointsConformidade

GET /passports/{passportId}/compliance requer passports:read

Executa uma verificação de conformidade em tempo real de um passaporte face aos campos obrigatórios do seu setor e indica exatamente o que falta.

Pedido
curl https://myproductpassport.eu/api/v1/passports/96/compliance \
  -H "Authorization: Bearer pk_your_key"
Resposta
{
  "data": {
    "passport_id": 96,
    "product_name": "Alpine Merino Crew Sweater",
    "status": "compliant",
    "percentage": 100,
    "completed_fields": 12,
    "total_fields": 12,
    "missing_fields": []
  }
}

10 / EndpointsSetores

GET /sectors

Os setores em que um produto pode ser classificado: os setores de sistema da plataforma mais os definidos pelo seu espaço de trabalho. Use o id ao criar produtos e as chaves de campo ao escrever campos do passaporte.

Pedido
curl https://myproductpassport.eu/api/v1/sectors \
  -H "Authorization: Bearer pk_your_key"
Resposta
{
  "data": [
    {
      "id": 4,
      "slug": "batteries",
      "name": "Batteries",
      "system": true,
      "regulations_finalised": true,
      "deadline": "2027-02-18",
      "deadline_label": "18 Feb 2027",
      "required_fields": ["battery_category", "battery_weight", "..."],
      "optional_fields": ["energy_round_trip_efficiency", "..."]
    }
  ]
}

11 / EndpointsDocumentos

GET /products/{productId}/documents requer products:read

Declarações de conformidade, relatórios de ensaio e certificados anexados ao produto. Um documento público fica ligado a partir de todos os passaportes publicados do produto.

Pedido
curl https://myproductpassport.eu/api/v1/products/512/documents \
  -H "Authorization: Bearer pk_your_key"
Resposta
{
  "data": [
    {
      "id": 31,
      "product_id": 512,
      "filename": "declaration-of-conformity.pdf",
      "mime_type": "application/pdf",
      "file_size": 184322,
      "is_public": true,
      "processing_status": "completed",
      "public_url": "https://myproductpassport.co.uk/p/3f0c.../document/31",
      "created_at": "2026-09-22T10:12:00+00:00"
    }
  ]
}
POST /products/{productId}/documents requer products:write

Carregamento multipart. PDF, Word, Excel, CSV, texto, PNG e JPEG até 10 MB, no máximo 20 por produto. O texto é extraído em segundo plano.

ParâmetroTipoDescrição
filefileobrigatórioO documento.
is_publicbooleanMostrar no passaporte público (predefinição false).
Pedido
curl -X POST https://myproductpassport.eu/api/v1/products/512/documents \
  -H "Authorization: Bearer pk_your_key" \
  -F "[email protected]" \
  -F "is_public=1"
PATCH /products/{productId}/documents/{id} requer products:write

Define se o documento está ligado a partir do passaporte público.

ParâmetroTipoDescrição
is_publicbooleanobrigatório
Pedido
curl -X PATCH https://myproductpassport.eu/api/v1/products/512/documents/31 \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"is_public": false}'
DELETE /products/{productId}/documents/{id} requer products:write

Remove o ficheiro e a sua ligação ao passaporte.

Pedido
curl -X DELETE https://myproductpassport.eu/api/v1/products/512/documents/31 \
  -H "Authorization: Bearer pk_your_key"
Resposta
{ "message": "Document deleted." }

12 / EndpointsCadeia de abastecimento

GET /products/{productId}/supply-chain requer products:read

Os passos apresentados no passaporte do produto, por ordem.

Pedido
curl https://myproductpassport.eu/api/v1/products/512/supply-chain \
  -H "Authorization: Bearer pk_your_key"
PUT /products/{productId}/supply-chain requer products:write

Substitui todos os passos pela lista que enviar, pela ordem enviada. Envie uma lista vazia para a limpar. Tipos de passo: raw_material, processing, manufacturing, assembly, packaging, distribution.

ParâmetroTipoDescrição
stepsarrayobrigatórioAté 50 passos.
steps[].step_typestringobrigatório
steps[].supplier_namestringobrigatório
steps[].supplier_locationstring
steps[].supplier_countrystringISO 3166-1 alpha-2.
steps[].lat / lngnumber
steps[].descriptionstring
steps[].certificationsarray
steps[].datedate
Pedido
curl -X PUT https://myproductpassport.eu/api/v1/products/512/supply-chain \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"steps": [{"step_type": "raw_material", "supplier_name": "Merino Growers Co-op", "supplier_country": "NZ", "certifications": ["RWS"]}, {"step_type": "manufacturing", "supplier_name": "Northloom Mill", "supplier_location": "Biella", "supplier_country": "IT"}]}'

13 / EndpointsTraduções

GET /passports/{id}/translations requer passports:read

Cada valor de campo traduzido por idioma, com a sua origem: auto (automática, feita na publicação) ou manual.

Pedido
curl https://myproductpassport.eu/api/v1/passports/96/translations \
  -H "Authorization: Bearer pk_your_key"
Resposta
{
  "data": {
    "passport_id": 96,
    "available_locales": ["bg", "cs", "da", "de", "..."],
    "translations": {
      "de": {"care_instructions": {"value": "Kalt waschen", "source": "manual"}}
    }
  }
}
PUT /passports/{id}/translations/{locale} requer passports:write

Define as traduções de um idioma por chave de campo. Uma tradução manual nunca é substituída por tradução automática. Envie uma string vazia para remover uma.

ParâmetroTipoDescrição
fieldsobjectobrigatóriofield_key: valor traduzido
Pedido
curl -X PUT https://myproductpassport.eu/api/v1/passports/96/translations/de \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"fields": {"care_instructions": "Kalt waschen, nicht bleichen"}}'
Resposta
{ "message": "1 translation(s) written, 0 removed.", "locale": "de", "written": 1, "removed": 0 }

14 / EndpointsIntegridade e exportações

GET /passports/{id}/integrity requer passports:read

Cada estado publicado do passaporte como um registo encadeado por hash e assinado com Ed25519: impressão digital (SHA-256), valor da cadeia e assinatura. As chaves públicas estão em /.well-known/mpp-integrity-keys.json, pelo que qualquer pessoa pode verificar a cadeia.

Pedido
curl https://myproductpassport.eu/api/v1/passports/96/integrity \
  -H "Authorization: Bearer pk_your_key"
Resposta
{ "data": { "state": "intact", "hash_algorithm": "SHA-256", "signature_algorithm": "Ed25519", "records": [ { "sequence": 1, "event": "published", "content_hash": "8f3a...", "chain_hash": "c21e...", "signature": "MEUC...", "key_id": "3fa9c21e0b7d4a11" } ], "problems": [] } }
GET /passports/{id}/integrity/{sequence} requer passports:read

O registo completo tal como foi assinado, incluindo o instantâneo: o que o passaporte indicava nesse momento, até ao hash de cada ficheiro anexado.

Pedido
curl https://myproductpassport.eu/api/v1/passports/96/integrity/1 \
  -H "Authorization: Bearer pk_your_key"
GET /passports/{id}/epcis requer passports:read

O passaporte como documento GS1 EPCIS 2.0 JSON-LD: o comissionamento do artigo, cada passo da cadeia de abastecimento como uma observação, as baterias individuais e um passaporte de segunda vida como uma transformação. Os identificadores são URIs GS1 Digital Link quando o produto tem um GTIN.

Pedido
curl https://myproductpassport.eu/api/v1/passports/96/epcis \
  -H "Authorization: Bearer pk_your_key"

15 / EndpointsPedidos a fornecedores

POST /passports/{id}/supplier-requests requer passports:write

Envia a um fornecedor, por email, uma ligação privada para preencher os campos que escolher, no idioma dele. Nada chega ao passaporte até que alguém do seu espaço de trabalho o aprove.

ParâmetroTipoDescrição
supplier_namestringobrigatório
supplier_emailstringobrigatório
field_keysarrayobrigatórioChaves de campo do modelo do passaporte.
localestringIdioma do email e do formulário, por exemplo de.
due_atdateData limite de resposta; 14 dias se for omitida.
messagestring
Pedido
curl -X POST https://myproductpassport.eu/api/v1/passports/96/supplier-requests \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"supplier_name": "Mei Chen", "supplier_email": "[email protected]", "field_keys": ["recycled_content_cobalt", "carbon_footprint"], "locale": "de"}'
GET /passports/{id}/supplier-requests requer passports:read

Todos os pedidos do passaporte, com o respetivo estado.

Pedido
curl https://myproductpassport.eu/api/v1/passports/96/supplier-requests \
  -H "Authorization: Bearer pk_your_key"
GET /supplier-requests/{id} requer passports:read

Um pedido com as respostas do fornecedor, a nota e os nomes dos ficheiros anexados.

Pedido
curl https://myproductpassport.eu/api/v1/supplier-requests/12 \
  -H "Authorization: Bearer pk_your_key"

16 / EndpointsPós-venda

POST /passports/{id}/items requer items:write

Dê aos artigos de um produto (qualquer setor exceto baterias, que usam /units) o seu próprio número de série: cada um recebe endereço e código QR próprios, um código de autenticidade oculto para a etiqueta, e pode ser registado pelo proprietário. Envie até 10 000 artigos ou um intervalo. Com um GTIN, o endereço é o GS1 Digital Link /01/{gtin}/21/{serial}.

ParâmetroTipoDescrição
items[].serialstringobrigatórioAté 20 letras, algarismos, pontos, hífenes ou carateres de sublinhado.
items[].batchstringLote, até 20 caracteres.
items[].manufactured_onstringData de fabrico, AAAA-MM-DD.
rangeobjectEm vez de items: prefix, start, count, digits e batch, por exemplo SN-00001 a SN-00500.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/passports/96/items \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"range": {"prefix": "SN-", "start": 1, "count": 500, "digits": 5, "batch": "B2026-10"}}'
Resposta
{ "created": 500, "updated": 0, "skipped": 0, "over_limit": 0, "errors": [] }
GET /passports/{id}/items/{serial} requer items:read

Um artigo com endereço, estado, se está registado e até quando dura a garantia, as verificações de autenticidade e o histórico. Uma chave com items:write obtém também o código oculto, para impressão. GET /passports/{id}/items lista-os (filtros status e batch, per_page até 500).

Pedido
curl https://myproductpassport.eu/api/v1/passports/96/items/SN-00001 \
  -H "Authorization: Bearer pk_your_key"
Resposta
{
  "data": { "serial": "SN-00001", "status": "active", "url": "https://myproductpassport.co.uk/01/05012345678900/21/SN-00001", "registered": true, "warranty_ends_on": "2028-10-02", "events": [ { "type": "registered", "country": "IE", "at": "2026-10-03T09:12:00+00:00" } ] }
}
PATCH /passports/{id}/items/{serial} requer items:write

Defina status como stolen ou recalled e a sua página avisa quem o ler, com a sua status_note; um artigo roubado não pode ser registado. retired retira a página do ar. Também pode alterar batch e manufactured_on.

ParâmetroTipoDescrição
statusstringactive, stolen, recalled ou retired.
status_notestringMostrado na página do artigo, até 500 caracteres.
Pedido
curl -X PATCH https://myproductpassport.eu/api/v1/passports/96/items/SN-00001 \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"status": "stolen", "status_note": "Reported stolen on 2 October 2026."}'
GET /owner-registrations requer aftersales:read

Pessoas que registaram os seus produtos: nome, e-mail, país, data de compra, vendedor, datas de garantia e se aceitaram novidades e ofertas (marketing_consent=1 lista só esses). Registos ativos por predefinição; status=pending, transferred ou ended para os outros; since= para alterações após uma data.

Pedido
curl "https://myproductpassport.eu/api/v1/owner-registrations?marketing_consent=1&since=2026-10-01" \
  -H "Authorization: Bearer pk_your_key"
GET /service-requests requer aftersales:read

Reparações, pedidos de garantia, recolhas, peças sobresselentes e perguntas enviados a partir dos seus passaportes, os mais recentes primeiro, com filtros status e type. GET /service-requests/{reference} acrescenta a conversa.

Pedido
curl "https://myproductpassport.eu/api/v1/service-requests?status=new" \
  -H "Authorization: Bearer pk_your_key"
POST /service-requests/{reference}/replies requer aftersales:write

A sua resposta é enviada ao cliente por e-mail com uma ligação para a página do pedido, no idioma dele. internal: true acrescenta uma nota que só a sua equipa vê. PATCH /service-requests/{reference} com um status fá-lo avançar (o cliente é avisado quando está em curso, resolvido ou fechado).

ParâmetroTipoDescrição
bodystringobrigatórioA resposta, até 5000 caracteres.
internalbooleanUma nota para a sua equipa em vez de uma resposta.
statusstringnew, in_progress, waiting, resolved ou closed.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/service-requests/SR-7K3F9Q/replies \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"body": "A new lid is on its way today.", "status": "waiting"}'

17 / EndpointsEdições em massa e imagens

PATCH /products/bulk-fields requer products:write

Define um dado de produto ou um campo do passaporte em até 5000 produtos. mode é set, fill (apenas onde estiver vazio) ou clear. Até 100 produtos são atualizados no próprio pedido; conjuntos maiores são colocados em fila (202).

ParâmetroTipoDescrição
product_idsarrayobrigatório
targetstringobrigatórioproduct | field
keystringobrigatório
valuestring
modestringset | fill | clear
Pedido
curl -X PATCH https://myproductpassport.eu/api/v1/products/bulk-fields \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"product_ids": [12, 13, 14], "target": "field", "key": "warranty_period", "value": "10 years", "mode": "fill"}'
Resposta
{ "data": { "changed": 2, "skipped": 1, "errors": [] } }
POST /products/{id}/images requer products:write

Carregamento multipart de um JPG, PNG ou WebP (até 15MB, 8 por produto). A primeira imagem é a capa do passaporte público.

ParâmetroTipoDescrição
imagefileobrigatório
altstringDescrição da imagem.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/products/12/images \
  -H "Authorization: Bearer pk_your_key" \
  -F [email protected] -F alt="Front of the battery"
PUT /products/{id}/images/order requer products:write

Indique image_ids pela ordem pretendida; a primeira passa a ser a capa.

ParâmetroTipoDescrição
image_idsarrayobrigatório
Pedido
curl -X PUT https://myproductpassport.eu/api/v1/products/12/images/order \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"image_ids": [31, 30]}'
DELETE /products/{id}/images/{imageId} requer products:write

Remove a imagem e o respetivo ficheiro.

Pedido
curl -X DELETE https://myproductpassport.eu/api/v1/products/12/images/31 \
  -H "Authorization: Bearer pk_your_key"

18 / EndpointsWebhooks

GET /webhooks requer webhooks:manage

Os endpoints registados para o seu espaço de trabalho. Os segredos não estão incluídos aqui; obtenha um endpoint para ver o respetivo segredo.

Pedido
curl https://myproductpassport.eu/api/v1/webhooks \
  -H "Authorization: Bearer pk_your_key"
POST /webhooks requer webhooks:manage

Regista um URL HTTPS público para um ou mais eventos. A resposta inclui o segredo de assinatura. Anfitriões privados ou internos são recusados.

ParâmetroTipoDescrição
urlstringobrigatório
eventsarrayobrigatórioQualquer um dos eventos indicados abaixo.
Pedido
curl -X POST https://myproductpassport.eu/api/v1/webhooks \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://erp.acme.example/mpp", "events": ["passport.published", "product.updated"]}'
Resposta
{
  "data": {
    "id": 3,
    "url": "https://erp.acme.example/mpp",
    "events": ["passport.published", "product.updated"],
    "is_active": true,
    "failure_count": 0,
    "secret": "9f1c...64 hex characters...",
    "created_at": "2026-09-22T10:12:00+00:00"
  }
}
GET /webhooks/{id} requer webhooks:manage

Pedido
curl https://myproductpassport.eu/api/v1/webhooks/3 \
  -H "Authorization: Bearer pk_your_key"
PUT /webhooks/{id} requer webhooks:manage

Altere o URL ou os eventos, ou pause e retome o endpoint. Retomar repõe a contagem de falhas; um endpoint é pausado automaticamente após 10 entregas falhadas consecutivas.

ParâmetroTipoDescrição
urlstring
eventsarray
is_activeboolean
Pedido
curl -X PUT https://myproductpassport.eu/api/v1/webhooks/3 \
  -H "Authorization: Bearer pk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"is_active": true}'
POST /webhooks/{id}/test requer webhooks:manage

Coloca em fila uma entrega webhook.test para poder verificar o recetor e o código de assinatura.

Pedido
curl -X POST https://myproductpassport.eu/api/v1/webhooks/3/test \
  -H "Authorization: Bearer pk_your_key"
Resposta
{ "message": "Test delivery queued." }
GET /webhooks/{id}/deliveries requer webhooks:manage

Entregas recentes, da mais recente para a mais antiga, com o estado HTTP devolvido pelo seu endpoint e os primeiros 500 caracteres do corpo da resposta.

ParâmetroTipoDescrição
per_pageintegerAté 100.
Pedido
curl https://myproductpassport.eu/api/v1/webhooks/3/deliveries \
  -H "Authorization: Bearer pk_your_key"
DELETE /webhooks/{id} requer webhooks:manage

Pedido
curl -X DELETE https://myproductpassport.eu/api/v1/webhooks/3 \
  -H "Authorization: Bearer pk_your_key"
Resposta
{ "message": "Webhook endpoint deleted." }

19 / EventosWebhooks

Em vez de consultar periodicamente, registe um endpoint de webhook na aplicação (página Webhooks, disponível a partir do plano Starter) e a MyProductPassport enviará JSON por POST para o seu URL à medida que os eventos acontecem:

EventoDispara quando
product.createdÉ criado um produto (aplicação, API ou importação CSV)
product.updatedUm produto é atualizado
product.deletedUm produto é eliminado
passport.createdUm passaporte é gerado
passport.publishedUm passaporte fica ativo
passport.archivedUm passaporte é arquivado
supplier_request.submittedUm fornecedor envia as informações que pediu
owner.registeredUm proprietário confirma o seu registo
owner.transferredUm artigo passa para um novo proprietário registado
service_request.createdUm cliente envia um pedido de assistência a partir de um passaporte
service_request.updatedUm pedido de assistência recebe uma resposta ou um novo estado
item.status_changedUm artigo é assinalado como roubado, recolhido ou retirado, ou a marcação é removida
item.verification_failedUma leitura segura falha, os códigos errados acumulam-se ou um número de série aparece em demasiados locais
webhook.testEnvia uma entrega de teste a partir da aplicação

Cada entrega é um envelope JSON: um ID de entrega (o mesmo ID é reenviado nas novas tentativas, para poder eliminar duplicados), o evento, o número da tentativa, um carimbo temporal e os dados do evento. Os eventos de passaporte incluem o uuid e o URL público do passaporte, pelo que raramente precisa de um segundo pedido:

Corpo da entrega
{
  "id": 8123,
  "event": "passport.published",
  "attempt": 1,
  "created_at": "2026-09-22T10:12:00+00:00",
  "data": {
    "passport_id": 96,
    "uuid": "3f0c8f1e-...",
    "version": 2,
    "status": "published",
    "public_url": "https://myproductpassport.co.uk/p/3f0c8f1e-...",
    "product_id": 512,
    "product": {"id": 512, "name": "Alpine Merino Crew Sweater", "sku": "NL-AMC-001", "gtin": "5012345678900"}
  }
}

Os cabeçalhos incluem o nome do evento, o ID da entrega, um carimbo temporal Unix e uma assinatura HMAC do corpo em bruto, para que possa verificar que veio de nós e rejeitar repetições:

Cabeçalhos da entrega
Content-Type: application/json
User-Agent: MyProductPassport-Webhooks/1.0
X-MPP-Event: passport.published
X-MPP-Delivery: 8123
X-MPP-Timestamp: 1790084320
X-MPP-Signature: sha256=<hex hmac of the raw body, keyed with your endpoint secret>

Responda com qualquer 2xx no prazo de 10 segundos. Tudo o resto é repetido cinco vezes ao longo de cerca de 90 minutos (30 s, 1 min, 5 min, 15 min, 1 h); após 10 falhas consecutivas o endpoint é pausado até o voltar a ativar.

Verificar (PHP)
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $endpointSecret);
abort_unless(hash_equals($expected, $request->header('X-MPP-Signature')), 401);