Create Activity Generation Config
Create a lifecycle-only activity generation config with all three pillars.
POST /api/activity-generation-configs
Create an activity generation config. The operation is transactional: the AGC and all three lifecycle pillars (with their children) are created together, or nothing is created.
The AGC is created in the active project, always with status: "draft" (see Status). To make it run, publish it.
Auth: Required — activity-generation-config:create permission
Three-pillar invariant. activation, engagement, and resurrection are all required. Omitting any one returns 400 Bad Request. There is no way to create an AGC without all three pillars.
Request bodies are snake_case. In the admin UI, the wizard prefills each pillar with sensible defaults from GET /api/lifecycle-defaults; the admin then edits and submits the full data. The user_retention_status_config_id values reference entries in the tenant's retention status catalog.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Config name |
description | string | No | Free-text description |
audience_id | UUID | No | Own audience of the AGC; it must be an audience of the active project. Without it, the AGC runs over the project's root audience (see Effective audience) |
activation | object | Yes | Activation pillar (see below) |
engagement | object | Yes | Engagement pillar (see below) |
resurrection | object | Yes | Resurrection pillar (see below) |
source_config_id, usage_type, and any template/clone field are not accepted. An AGC is created with full lifecycle data only.
status, projectId and project_id are not accepted either: the AGC is always created in the active project and in draft. Sending any of them responds 400.
activation object
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Pillar name |
description | string | No | Free-text description |
source_table | string | Yes | Source table for activation data |
source_columns | string[] | No | Columns used to compute activation |
date_column | string | Yes | Date column used for windowing |
aggregation_method | enum | Yes | nunique, count, sum, or active_weeks |
moments | object[] | Yes | Activation moments (see below) |
Each item in moments:
| Field | Type | Required | Description |
|---|---|---|---|
status_code | string | Yes | Retention status code assigned by this moment |
user_retention_status_config_id | UUID | No | Retention status catalog entry. If omitted, the API derives it from status_code; if sent, it must be the entry of that status_code |
min_actions | int ≥ 0 | No | Minimum actions to reach this moment |
window_days | int ≥ 0 | No | Look-back window in days |
time_window | int ≥ 0 | No | Time window for the moment |
priority | int ≥ 0 | Yes | Resolution priority (lower wins) |
engagement object
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Pillar name |
description | string | No | Free-text description |
source_table | string | Yes | Source table for engagement data |
source_columns | string[] | No | Columns used to compute engagement |
date_column | string | Yes | Date column used for windowing |
engagement_window_days | int ≥ 1 | Yes | Rolling window for engagement counting |
min_lifetime_actions_for_engaged | int ≥ 1 | Yes | Minimum lifetime actions to be considered engaged (platform default 1) |
counting_method | enum | Yes | event_ids, active_days, or active_weeks |
levels | object[] | Yes | Engagement levels (see below) |
Each item in levels:
| Field | Type | Required | Description |
|---|---|---|---|
status_code | string | Yes | Retention status code for this level |
user_retention_status_config_id | UUID | No | Retention status catalog entry. If omitted, the API derives it from status_code; if sent, it must be the entry of that status_code |
label | string | Yes | Display label |
min_threshold | int ≥ 0 | Yes | Lower bound (inclusive) of the level |
max_threshold | int ≥ 0 | No | Upper bound; omit for the top level |
order | int ≥ 0 | Yes | Sort order of the level |
resurrection object
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Pillar name |
description | string | No | Free-text description |
source_table | string | Yes | Source table for resurrection data |
source_columns | string[] | No | Columns used to compute resurrection |
date_column | string | Yes | Date column used for windowing |
thresholds | object[] | Yes | Resurrection thresholds (see below) |
Each item in thresholds:
| Field | Type | Required | Description |
|---|---|---|---|
status_code | string | Yes | Retention status code for this threshold |
user_retention_status_config_id | UUID | No | Retention status catalog entry. If omitted, the API derives it from status_code; if sent, it must be the entry of that status_code |
label | string | Yes | Display label |
threshold_days | int ≥ 1 | Yes | Days of inactivity that trigger this status |
order | int ≥ 0 | Yes | Sort order of the threshold |
Example
curl -X POST https://api.reten.ai/api/activity-generation-configs \
-H "Authorization: Bearer <token>" \
-H "x-tenant-id: <tenant-id>" \
-H "x-project-id: <project-id>" \
-H "Content-Type: application/json" \
-d '{
"name": "Default lifecycle",
"description": "Activation, engagement and resurrection for the main funnel",
"audience_id": "1f0d2c3b-4a59-4687-9c12-abcdef012345",
"activation": {
"name": "Activation",
"source_table": "events",
"source_columns": ["user_id", "event_id"],
"date_column": "occurred_at",
"aggregation_method": "nunique",
"moments": [
{
"status_code": "aha",
"user_retention_status_config_id": "aa11bb22-cc33-4d44-9e55-ff66aa77bb88",
"min_actions": 3,
"window_days": 7,
"time_window": 30,
"priority": 1
},
{
"status_code": "setup",
"user_retention_status_config_id": "bb22cc33-dd44-4e55-9f66-aa88bb99ccaa",
"min_actions": 1,
"priority": 2
}
]
},
"engagement": {
"name": "Engagement",
"source_table": "events",
"source_columns": ["user_id", "event_id"],
"date_column": "occurred_at",
"engagement_window_days": 28,
"min_lifetime_actions_for_engaged": 1,
"counting_method": "active_days",
"levels": [
{
"status_code": "casual",
"user_retention_status_config_id": "cc33dd44-ee55-4f66-a077-bb99ccaaddbb",
"label": "Casual",
"min_threshold": 1,
"max_threshold": 7,
"order": 1
},
{
"status_code": "core",
"user_retention_status_config_id": "dd44ee55-ff66-4077-b188-ccaaddbbeecc",
"label": "Core",
"min_threshold": 8,
"order": 2
}
]
},
"resurrection": {
"name": "Resurrection",
"source_table": "events",
"source_columns": ["user_id"],
"date_column": "occurred_at",
"thresholds": [
{
"status_code": "dormant",
"user_retention_status_config_id": "ee55ff66-aa77-4188-c299-ddbbeeccffdd",
"label": "Dormant",
"threshold_days": 30,
"order": 1
},
{
"status_code": "churned",
"user_retention_status_config_id": "ff66aa77-bb88-4299-d3aa-eeccffdd00ee",
"label": "Churned",
"threshold_days": 90,
"order": 2
}
]
}
}'import axios from 'axios';
const body = {
name: 'Default lifecycle',
description: 'Activation, engagement and resurrection for the main funnel',
audience_id: '1f0d2c3b-4a59-4687-9c12-abcdef012345',
activation: {
name: 'Activation',
source_table: 'events',
source_columns: ['user_id', 'event_id'],
date_column: 'occurred_at',
aggregation_method: 'nunique',
moments: [
{
status_code: 'aha',
user_retention_status_config_id: 'aa11bb22-cc33-4d44-9e55-ff66aa77bb88',
min_actions: 3,
window_days: 7,
time_window: 30,
priority: 1,
},
{
status_code: 'setup',
user_retention_status_config_id: 'bb22cc33-dd44-4e55-9f66-aa88bb99ccaa',
min_actions: 1,
priority: 2,
},
],
},
engagement: {
name: 'Engagement',
source_table: 'events',
source_columns: ['user_id', 'event_id'],
date_column: 'occurred_at',
engagement_window_days: 28,
min_lifetime_actions_for_engaged: 1,
counting_method: 'active_days',
levels: [
{
status_code: 'casual',
user_retention_status_config_id: 'cc33dd44-ee55-4f66-a077-bb99ccaaddbb',
label: 'Casual',
min_threshold: 1,
max_threshold: 7,
order: 1,
},
{
status_code: 'core',
user_retention_status_config_id: 'dd44ee55-ff66-4077-b188-ccaaddbbeecc',
label: 'Core',
min_threshold: 8,
order: 2,
},
],
},
resurrection: {
name: 'Resurrection',
source_table: 'events',
source_columns: ['user_id'],
date_column: 'occurred_at',
thresholds: [
{
status_code: 'dormant',
user_retention_status_config_id: 'ee55ff66-aa77-4188-c299-ddbbeeccffdd',
label: 'Dormant',
threshold_days: 30,
order: 1,
},
{
status_code: 'churned',
user_retention_status_config_id: 'ff66aa77-bb88-4299-d3aa-eeccffdd00ee',
label: 'Churned',
threshold_days: 90,
order: 2,
},
],
},
};
const response = await axios.post(
'https://api.reten.ai/api/activity-generation-configs',
body,
{ headers: { Authorization: 'Bearer <token>', 'x-tenant-id': '<tenant-id>', 'x-project-id': '<project-id>' } },
);
const created = response.data;Response 201 Created
Returns the created AGC with its full nested configuration — including projectId and status: "draft" — in the same camelCase shape as GET /:id, but without effectiveAudienceId and configHashes: read the AGC with GET /:id to get them.
Error Responses
| Status | Description |
|---|---|
400 | Validation failed, or a required pillar (activation / engagement / resurrection) is missing |
400 | status, projectId or project_id in the body |
400 | A status_code is not an active code of the tenant's retention status catalog — status_code "<code>" no es un user retention status válido y activo para este tenant |
400 | A user_retention_status_config_id is not the catalog entry of its status_code — user_retention_status_config_id no corresponde al status_code "<code>" |
400 | audience_id is not an audience of the active project — La audiencia no existe en este proyecto. |
409 | Another AGC of the active project already has that name — An activity generation config with name "<name>" already exists |