Reten Docs

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

FieldTypeRequiredDescription
namestringYesConfig name
descriptionstringNoFree-text description
audience_idUUIDNoOwn 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)
activationobjectYesActivation pillar (see below)
engagementobjectYesEngagement pillar (see below)
resurrectionobjectYesResurrection 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

FieldTypeRequiredDescription
namestringYesPillar name
descriptionstringNoFree-text description
source_tablestringYesSource table for activation data
source_columnsstring[]NoColumns used to compute activation
date_columnstringYesDate column used for windowing
aggregation_methodenumYesnunique, count, sum, or active_weeks
momentsobject[]YesActivation moments (see below)

Each item in moments:

FieldTypeRequiredDescription
status_codestringYesRetention status code assigned by this moment
user_retention_status_config_idUUIDNoRetention status catalog entry. If omitted, the API derives it from status_code; if sent, it must be the entry of that status_code
min_actionsint ≥ 0NoMinimum actions to reach this moment
window_daysint ≥ 0NoLook-back window in days
time_windowint ≥ 0NoTime window for the moment
priorityint ≥ 0YesResolution priority (lower wins)

engagement object

FieldTypeRequiredDescription
namestringYesPillar name
descriptionstringNoFree-text description
source_tablestringYesSource table for engagement data
source_columnsstring[]NoColumns used to compute engagement
date_columnstringYesDate column used for windowing
engagement_window_daysint ≥ 1YesRolling window for engagement counting
min_lifetime_actions_for_engagedint ≥ 1YesMinimum lifetime actions to be considered engaged (platform default 1)
counting_methodenumYesevent_ids, active_days, or active_weeks
levelsobject[]YesEngagement levels (see below)

Each item in levels:

FieldTypeRequiredDescription
status_codestringYesRetention status code for this level
user_retention_status_config_idUUIDNoRetention status catalog entry. If omitted, the API derives it from status_code; if sent, it must be the entry of that status_code
labelstringYesDisplay label
min_thresholdint ≥ 0YesLower bound (inclusive) of the level
max_thresholdint ≥ 0NoUpper bound; omit for the top level
orderint ≥ 0YesSort order of the level

resurrection object

FieldTypeRequiredDescription
namestringYesPillar name
descriptionstringNoFree-text description
source_tablestringYesSource table for resurrection data
source_columnsstring[]NoColumns used to compute resurrection
date_columnstringYesDate column used for windowing
thresholdsobject[]YesResurrection thresholds (see below)

Each item in thresholds:

FieldTypeRequiredDescription
status_codestringYesRetention status code for this threshold
user_retention_status_config_idUUIDNoRetention status catalog entry. If omitted, the API derives it from status_code; if sent, it must be the entry of that status_code
labelstringYesDisplay label
threshold_daysint ≥ 1YesDays of inactivity that trigger this status
orderint ≥ 0YesSort 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

StatusDescription
400Validation failed, or a required pillar (activation / engagement / resurrection) is missing
400status, projectId or project_id in the body
400A 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
400A 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>"
400audience_id is not an audience of the active project — La audiencia no existe en este proyecto.
409Another AGC of the active project already has that name — An activity generation config with name "<name>" already exists