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:
Listar (paginado + filtros)
GET /commerce-lifecycle-snapshots — percorre todos os estados do tenant
com filtros por código, estágio, AGC e frescor.
Consultar por comércio
GET /commerce-lifecycle-snapshots/:commerceIdentifier — o estado (ou
estados) de um único comércio por UUID ou código externo.
Lookup por lote
POST /commerce-lifecycle-snapshots/batch-lookup — resolve até 100
identificadores em uma única chamada, com resultados parciais.
Upsert individual
POST /commerce-lifecycle-snapshots — cria ou atualiza o estado de um
comércio.
Upsert por lote
POST /commerce-lifecycle-snapshots/batch-upsert — grava até 1000
estados em uma única operação, com relatório por item.
Autenticação
Todos os endpoints de estados de ciclo de vida aceitam dois métodos de autenticação:
| Método | Headers | Uso típico |
|---|---|---|
| API Key | x-api-key: YOUR_API_KEY | Integradores externos / parceiros. A key resolve o tenant automaticamente — não envie x-tenant-id. |
| JWT | Authorization: Bearer <token> + x-tenant-id: <tenant-id> | Uso interno / painel administrativo. |
Permissões necessárias:
| Permissão | Capabilities |
|---|---|
commerce-lifecycle-snapshot:view | listar, consultar por comércio, lookup por lote |
commerce-lifecycle-snapshot:create | upsert individual, upsert por lote |
activity-generation-config:view | descobrir 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"
}| Campo | Tipo | Descrição |
|---|---|---|
id | UUID | Identificador único do snapshot. |
commerce_id | UUID | UUID do comércio na Reten. |
external_id | string | null | Có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_id | UUID | AGC sob a qual este estado foi calculado. Veja identificador de AGC. |
code | string | Código bruto do estado de retenção (ex. "AT_RISK_MONTHLY"). Corresponde a um UserRetentionStatusConfig do tenant. |
label | string | Rótulo legível do estado, derivado (desnormalizado) da configuração do código. A configuração é a fonte da verdade. |
stage | enum | Estágio do ciclo de vida. Veja estágios. |
last_computed_at | ISO 8601 | Quando o motor calculou este snapshot pela última vez. Veja frescor. |
state_changed_at | ISO 8601 | Quando 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:
| Endpoint | UUID | Código externo | Regra |
|---|---|---|---|
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:
ACTIVATIONENGAGEMENTRESURRECTION
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.
| Campo | O que responde | Quem 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 olabelou olast_computed_atmudar mas(stage, code)permanecer o mesmo,state_changed_atnão se move.
Exemplo da evolução de um mesmo comércio:
| Evento | stage / code | last_computed_at | state_changed_at resultante |
|---|---|---|---|
| Cálculo 1 (criação) | ENGAGEMENT / AT_RISK_MONTHLY | 2026-05-22T06:00Z | 2026-05-22T06:00Z (inicializado) |
| Cálculo 2 (mesmo estado) | ENGAGEMENT / AT_RISK_MONTHLY | 2026-06-01T06:00Z | 2026-05-22T06:00Z (sem alterações) |
| Cálculo 3 (estágio alterado) | RESURRECTION / WIN_BACK | 2026-06-10T06:00Z | 2026-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:
| Endpoint | Comportamento com um identificador sem resolver |
|---|---|
| Lookup por lote | O identificador aparece no array unresolved. A request não falha. |
| Consultar por comércio | Responde 404 Not Found. |
| Listar | Simplesmente 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-configsAuth: 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.