Reten Docs
Estados de Ciclo de Vida de Comércios

Estados de Ciclo de Vida de Comércios

Consuma e atualize o estado de ciclo de vida de retenção de cada comércio — identificadores duais, frescor, e comportamento com dados sem resolver.

Estados de ciclo de vida (lifecycle states) são a foto atual do estado de retenção de cada comércio, calculada pelo motor da Reten. Cada estado responde à pergunta: "em que ponto do ciclo de retenção está este comércio, sob qual configuração, e desde quando?".

Esta seção documenta o contrato de leitura e escrita desses estados.

Capabilities

A API expõe cinco capabilities sobre o recurso commerce-lifecycle-snapshots:

Autenticação

Todos os endpoints de estados de ciclo de vida aceitam dois métodos de autenticação:

MétodoHeadersUso típico
API Keyx-api-key: YOUR_API_KEYIntegradores externos / parceiros. A key resolve o tenant automaticamente — não envie x-tenant-id.
JWTAuthorization: Bearer <token> + x-tenant-id: <tenant-id>Uso interno / painel administrativo.

Permissões necessárias:

PermissãoCapabilities
commerce-lifecycle-snapshot:viewlistar, consultar por comércio, lookup por lote
commerce-lifecycle-snapshot:createupsert individual, upsert por lote
activity-generation-config:viewdescobrir as AGCs de um projeto (veja Setup de AGC)

Os exemplos desta seção usam o método API Key (x-api-key), que é o caminho esperado para um integrador externo. Se você consumir a partir do painel interno com um token JWT, substitua esse header por Authorization: Bearer <token> + x-tenant-id: <tenant-id>. Os endpoints de estados de ciclo de vida são tenant-level, então nenhum dos métodos envia x-project-id a eles; só a descoberta de AGCs é project-scoped (veja Setup de AGC).

O recurso: snapshot de estado

Um estado de ciclo de vida (snapshot) é representado com esta forma canônica. As superfícies que retornam o recurso "bruto" (list, lookup por lote, upsert) usam exatamente estes campos:

{
  "id": "5d000000-0000-4000-8000-000000000001",
  "commerce_id": "c0000000-0000-4000-8000-000000000001",
  "external_id": "SV-001",
  "activity_generation_config_id": "a1b2c3d4-0000-4000-8000-000000000001",
  "code": "AT_RISK_MONTHLY",
  "label": "At risk (monthly)",
  "stage": "ENGAGEMENT",
  "last_computed_at": "2026-06-10T06:00:00.000Z",
  "state_changed_at": "2026-05-22T06:00:00.000Z"
}
CampoTipoDescrição
idUUIDIdentificador único do snapshot.
commerce_idUUIDUUID do comércio na Reten.
external_idstring | nullCódigo externo do comércio no seu sistema (ex. "SV-001"). Desnormalizado no momento do upsert; null se o comércio não tiver código externo.
activity_generation_config_idUUIDAGC sob a qual este estado foi calculado. Veja identificador de AGC.
codestringCódigo bruto do estado de retenção (ex. "AT_RISK_MONTHLY"). Corresponde a um UserRetentionStatusConfig do tenant.
labelstringRótulo legível do estado, derivado (desnormalizado) da configuração do código. A configuração é a fonte da verdade.
stageenumEstágio do ciclo de vida. Veja estágios.
last_computed_atISO 8601Quando o motor calculou este snapshot pela última vez. Veja frescor.
state_changed_atISO 8601Quando o estado visível (stage, code) mudou pela última vez. Veja frescor.

Modelo de identificadores (dual)

Um comércio pode ser referenciado de duas formas equivalentes em toda a API de estados:

  • UUID da Reten (commerce_id) — o identificador interno, ex. c0000000-0000-4000-8000-000000000001.
  • Código externo (external_id) — o código do comércio no seu próprio sistema, ex. "SV-001".

Cada endpoint declara qual(is) aceita:

EndpointUUIDCódigo externoRegra
Consultar por comércio (GET /:commerceIdentifier)✅✅O path aceita qualquer um dos dois, indistintamente.
Lookup por lote✅ (commerce_ids)✅ (external_ids)Um único tipo por request (sem mistura).
Upsert por lote✅ (commerce_id)✅ (external_id)Homogêneo: todos os items do lote usam o mesmo tipo.
Upsert individual✅ (commerce_id)❌Apenas UUID.

Usar o código externo evita que você tenha que manter um mapeamento de UUIDs da Reten no seu sistema: você escreve e lê usando os mesmos códigos que já usa internamente.

Estágios do ciclo de vida (stage)

O campo stage assume um de três valores possíveis:

  • ACTIVATION
  • ENGAGEMENT
  • RESURRECTION

O par (stage, code) define o estado visível de um comércio.

Frescor: last_computed_at vs state_changed_at

São dois timestamps com semânticas distintas; entender a diferença é fundamental para consumir esses dados corretamente.

CampoO que respondeQuem controla
last_computed_at"Quando este estado foi recalculado pela última vez?"Fornecido pelo caller (o motor) em cada upsert.
state_changed_at"Desde quando o comércio está neste estado visível (stage, code)?"Gerenciado automaticamente pela Reten.

Regras de state_changed_at:

  • Ao criar, é inicializado igual a last_computed_at.
  • Ao atualizar, só muda se o par (stage, code) for diferente do que já existia. Se apenas o label ou o last_computed_at mudar mas (stage, code) permanecer o mesmo, state_changed_at não se move.

Exemplo da evolução de um mesmo comércio:

Eventostage / codelast_computed_atstate_changed_at resultante
Cálculo 1 (criação)ENGAGEMENT / AT_RISK_MONTHLY2026-05-22T06:00Z2026-05-22T06:00Z (inicializado)
Cálculo 2 (mesmo estado)ENGAGEMENT / AT_RISK_MONTHLY2026-06-01T06:00Z2026-05-22T06:00Z (sem alterações)
Cálculo 3 (estágio alterado)RESURRECTION / WIN_BACK2026-06-10T06:00Z2026-06-10T06:00Z (atualizado)

Use last_computed_at para responder "quão recente é este dado?" e state_changed_at para "há quanto tempo o comércio está neste estado?" (ex. "está em risco há 19 dias").

Comportamento com dados sem resolver ou stale

Sem resolver (unresolved)

Um identificador está sem resolver quando não existe um snapshot para ele. A API agrupa dois casos igualmente (de forma intencional — o resultado é inobtenível de qualquer forma):

  • O comércio não existe no tenant.
  • O comércio existe mas ainda não tem estado calculado.

Como se manifesta em cada endpoint:

EndpointComportamento com um identificador sem resolver
Lookup por loteO identificador aparece no array unresolved. A request não falha.
Consultar por comércioResponde 404 Not Found.
ListarSimplesmente não aparece em data (o list só retorna estados que existem).

Stale (dados antigos)

A API não marca frescor nem apaga estados antigos: um snapshot vive até que o motor o sobrescreva. O "frescor" é decidido pelo consumidor, comparando last_computed_at com o momento atual e aplicando seu próprio limite (ex. "considero stale tudo o que foi calculado há mais de 24h").

Para encontrar estados recentes sem percorrer tudo, o list aceita o filtro state_changed_since, que retorna apenas os estados cujo state_changed_at é posterior a uma data dada.

Identificador de AGC e fluxo de setup

O estado de ciclo de vida é por par (comércio, AGC), não único por comércio. Uma "Activity Generation Config" (AGC) é a configuração sob a qual o motor calcula os estados; um mesmo comércio pode ter um estado diferente sob cada AGC.

Por isso o parâmetro activity_generation_config_id aparece em todos os endpoints — de leitura e de escrita:

  • É opcional em leitura. Se você omiti-lo, obtém os estados de todas as AGCs do comércio/tenant.
  • Importa se você quiser evitar "misturar" dados. Filtrar por uma AGC específica garante que você leia apenas os estados calculados sob essa configuração, sem misturar resultados de outras AGCs.
  • É obrigatório em escrita (upsert individual e por lote), porque um estado sempre é escrito sob uma AGC específica.

Como obter os IDs de AGC disponíveis

Se você quiser filtrar por AGC, primeiro descubra as AGCs de um projeto com:

GET /api/activity-generation-configs

Auth: requer a permissão activity-generation-config:view. O endpoint é project-scoped: retorna apenas as AGCs do projeto ativo. Uma chave de projeto vê as AGCs do seu próprio projeto; uma chave de tenant ou um token JWT envia x-project-id com o projeto a ler (sem ele a API responde 400 — Falta el header obligatorio x-project-id.) e repete a chamada para cada projeto de GET /api/projects para cobrir todo o tenant — veja Escopo da chave. Responde um array; pegue o id da AGC que te interessa e use-o como activity_generation_config_id:

[
  {
    "id": "a1b2c3d4-0000-4000-8000-000000000001",
    "name": "B2B Retention",
    "description": "Retention cycle for wholesale customers"
  },
  {
    "id": "a1b2c3d4-0000-4000-8000-000000000002",
    "name": "Q1 Resurrection",
    "description": "First-quarter win-back campaign"
  }
]

Se o seu tenant opera com uma única AGC, você pode omitir activity_generation_config_id nas leituras e trabalhar sem ele. O parâmetro se torna importante quando múltiplas AGCs coexistem e você não quer misturar seus estados.