API Admin › Recursos

Propostas (modo de aprovação)

O lojista que quer revisar o que uma integração muda nos textos da loja (um agente de SEO, de conteúdo, de anúncios) põe a integração em modo proposta, no painel: Configurações › Integrações, em "Nome, escopos e aprovação". Nesse modo, as escritas de texto dela não mudam a loja: cada uma vira uma proposta, que alguém da equipe aprova ou recusa no painel, em Sugestões dos agentes. O padrão é o modo direto, em que a escrita grava na hora.

EscopoO que abre
write_content ou write_productsler as propostas desta integração

O GET /token diz o modo em integration.approval_mode: direct ou proposal. A troca vale já na próxima chamada. No servidor MCP, o mesmo vale para as ferramentas de escrita, e a ferramenta list_proposals faz o que GET /proposals faz.

O que vira proposta

As escritas de texto, as mesmas que vão para o histórico das mudanças:

  • PATCH /products/{id} com título, descrição, SEO ou endereço;
  • PATCH /products/{id}/images/{image_id} (o texto da foto);
  • PATCH /collections/{id} e PATCH /brands/{id} com os textos;
  • POST /pages e PATCH /pages/{id}.

Em modo proposta, elas passam pelas mesmas validações (os limites, o endereço em uso) e respondem 202 Accepted com a proposta, e nada muda na loja. Se não houver o que mudar (o valor já é esse), a resposta é a de sempre. A escrita que não mexe em texto (o preço, o estoque, a situação) continua direta. O PATCH que mistura texto com outro campo é recusado com 422 proposal_text_only, e os campos que não são texto vêm em fields: mande os textos numa chamada e o resto em outra.

curl -X PATCH "https://api.denaryx.com/admin/2026-10/products/5f2c…" \
  -H "Authorization: Bearer dnxa_..." \
  -H "Content-Type: application/json" \
  -d '{"seo": {"title": "Camiseta de algodão orgânico | Minha Loja"}}'
{
  "id": "a41e…",
  "resource_type": "product",
  "resource_id": "5f2c…",
  "product_id": null,
  "label": "Camiseta Básica",
  "action": "update",
  "fields": [
    {
      "field": "seo.title",
      "before": "",
      "after": "Camiseta de algodão orgânico | Minha Loja"
    }
  ],
  "batch_id": null,
  "origin": "api",
  "status": "pending",
  "created_at": "2026-10-21T13:02:11.482Z",
  "expires_at": "2026-10-28T13:02:11.482Z",
  "decided_at": null,
  "rejection_reason": null,
  "conflict": null,
  "change_id": null,
  "reverts": null
}

O before de cada campo é o valor de base, lido na hora da proposta. A página proposta (POST /pages) vem com resource_id null: ela só é criada quando o lojista aprova, ainda fora do ar.

A decisão

Alguém da equipe com a permissão de editar o catálogo (e a de cuidar da loja virtual, nas páginas) aprova ou recusa no painel, uma a uma ou várias de uma vez. A loja recebe por e-mail, todo dia de manhã, um resumo das propostas que chegaram nas últimas 24 horas.

statusO que aconteceu
pendingEspera a decisão, até expires_at.
approvedFoi ao ar. change_id é a mudança no histórico, que o lojista desfaz no painel e o agente desfaz pelo servidor MCP. Na página criada, resource_id passa a ser o id dela.
rejectedRecusada. rejection_reason traz o motivo, quando o lojista escreveu.
conflictNada foi aplicado: o valor de base mudou antes da aprovação (alguém editou o recurso), o recurso foi excluído, o endereço passou a estar em uso, ou a mudança a desfazer já tinha sido desfeita.
expiredNinguém decidiu em 7 dias.

A aprovação aplica só se cada campo ainda tiver o valor de base, como o desfazer, e cada proposta é decidida por si: a que tem conflito não segura as outras. Em conflito, conflict diz o motivo e o valor de agora:

{
  "conflict": {
    "code": "base_changed",
    "message": "Nada foi aplicado: o campo título para os buscadores mudou depois da sugestão.",
    "fields": [
      {
        "field": "seo.title",
        "expected": "",
        "current": "Camiseta básica | Minha Loja"
      }
    ]
  }
}

Leia o recurso de novo e, se a mudança ainda fizer sentido, proponha outra vez.

GET /proposals

As propostas desta integração, da mais nova para a mais velha, em páginas (ver Listas).

ParâmetroO que é
statusSó as que estão nesta situação: pending, approved, rejected, conflict ou expired.
batch_idSó as da mesma chamada (o lote do servidor MCP).
limitDe 1 a 100 (50 sem ele).
cursorO next_cursor da página anterior.
curl "https://api.denaryx.com/admin/2026-10/proposals?status=rejected" \
  -H "Authorization: Bearer dnxa_..."

GET /proposals/{id}

Uma proposta desta integração. A de outra integração da mesma loja é 404 not_found.

Prazos

A proposta pendente expira em 7 dias. As propostas, decididas ou não, ficam 180 dias, como o histórico das mudanças, e somem junto com a integração.