# Campañas GTM

> Cree y gestione campañas, documentos y catálogos de pasos de secuencias en AI Studio

Source: https://docs.graph8.com/es/developers/gtm-campaigns/

Las campañas GTM son los objetos de campaña de AI-Studio de graph8: un brief, una secuencia (referencias ordenadas de pasos) y un catálogo de pasos (las definiciones reales de cada paso). Cada campaña gestiona un conjunto de documentos generados (brief de campaña, documento de secuencia, copy de anuncios, copy de landing page, etc.).

Estos endpoints son la variante de **alcance organizacional** que utilizan Studio, MCP y el modo GTM de Claude Desktop. La misma superficie también se expone en `/repos/{repo_id}/campaigns` para usuarios de CLI con spine instalado; consulte la referencia de la [CLI](https://docs.graph8.com/developers/cli/) para esa variante.

| Endpoint | Método | Descripción |
|----------|--------|-------------|
| `/campaigns` | GET | Listar campañas |
| `/campaigns` | POST | Crear una campaña |
| `/campaigns/ideas` | GET | Listar ideas de campaña guardadas |
| `/campaigns/{id}` | GET | Obtener una campaña con sus documentos |
| `/campaigns/{id}` | PATCH | Actualizar campos de contenido de la campaña |
| `/campaigns/{id}/documents` | GET | Listar documentos de una campaña |
| `/campaigns/{id}/documents` | POST | Crear un documento |
| `/campaigns/{id}/documents/{doc_id}` | GET | Obtener el contenido completo del documento |
| `/campaigns/{id}/documents/{doc_id}` | PUT | Actualizar el contenido del documento |
| `/campaigns/{id}/documents/{doc_id}` | DELETE | Eliminar un documento |
| `/campaigns/{id}/sequence` | GET | Obtener documentos de secuencia y catálogo de pasos |
| `/campaigns/{id}/sequence` | PUT | Reemplazar el orden de los pasos de la secuencia |
| `/campaigns/{id}/sequence/steps` | POST | Agregar un paso |
| `/campaigns/{id}/sequence/steps/{step_id}` | PUT | Actualizar la definición de un paso |
| `/campaigns/{id}/sequence/steps/{step_id}` | DELETE | Eliminar un paso |
| `/campaigns/{id}/launch` | POST | Poner en cola el lanzamiento de la campaña |

Para esquemas legibles por máquina, consulte la [documentación interactiva de la API](https://be.graph8.com/api/v1/docs).

---

> **Note: Ids en estos ejemplos**
> Los ejemplos de solicitud usan variables de shell (`$CAMPAIGN_ID`, `$DOCUMENT_ID` and `$IMAGE_ID`) para los ids. Asígnelas a partir de los campos `id` que devuelven las llamadas de creación o listado. Los ids de las respuestas de ejemplo son solo ilustrativos y no existen.

## Listar campañas

`GET /campaigns`

Devuelve todas las campañas no archivadas de la organización, paginadas.

### Parámetros de consulta

| Parámetro | Tipo | Predeterminado | Descripción |
|-----------|------|----------------|-------------|
| `page` | integer | 1 | Número de página |
| `limit` | integer | 50 | 1-200 |

### Ejemplo

**cURL**

```bash
curl "https://be.graph8.com/api/v1/campaigns?limit=10" \
  -H "Authorization: Bearer $API_KEY"
```

### Respuesta

```json
{
  "data": [
    {
      "id": "cmp_abc",
      "name": "Q2 Outbound - VP Marketing",
      "slug": "q2-outbound-vp-marketing",
      "status": "draft",
      "category": "Outbound",
      "goal": "Book discovery calls",
      "target_persona": "VP Marketing at mid-market SaaS",
      "created_at": "2026-04-01T10:00:00Z"
    }
  ]
}
```

---

## Crear campaña

`POST /campaigns`

Crea una nueva campaña. El slug se genera automáticamente a partir de `name`.

### Cuerpo de la solicitud

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `name` | string | **Sí** | Nombre de la campaña |
| `category` | string | No (predeterminado `Outbound`) | Categoría de la campaña |
| `brief` | string | No | Brief de la campaña |
| `core_concept` | string | No | Concepto en una línea |
| `primary_hook` | string | No | Texto del gancho principal |
| `target_persona` | string | No | Persona objetivo |
| `goal` | string | No | Objetivo de la campaña |

### Ejemplo

**cURL**

```bash
curl -X POST "https://be.graph8.com/api/v1/campaigns" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Q2 Outbound - VP Marketing",
    "category": "Outbound",
    "primary_hook": "Cut SDR ramp time in half",
    "goal": "Book discovery calls"
  }'
```

### Respuesta

```json
{
  "data": {
    "id": "cmp_abc",
    "name": "Q2 Outbound - VP Marketing",
    "slug": "q2-outbound-vp-marketing",
    "status": "draft",
    "category": "Outbound"
  }
}
```

---

## Listar ideas de campaña

`GET /campaigns/ideas`

Devuelve las ideas de campaña guardadas o generadas con IA (antes de su conversión). Utilícelas para inicializar `POST /campaigns`.

### Parámetros de consulta

| Parámetro | Tipo | Predeterminado | Descripción |
|-----------|------|----------------|-------------|
| `favorited` | boolean | - | Filtrar solo las ideas marcadas como favoritas |
| `limit` | integer | 50 | 1-200 |

### Respuesta

```json
{
  "data": [
    {
      "id": "idea_001",
      "rank": 1,
      "campaign_name": "Sales Velocity Diagnostic",
      "campaign_category": "Outbound",
      "campaign_focus": "Mid-market RevOps",
      "core_concept": "...",
      "why_this_works": "...",
      "primary_hook": "Find your stuck deals in 5 minutes",
      "secondary_hooks": ["..."],
      "target_channels": ["email", "linkedin"],
      "required_assets": ["landing page", "demo video"],
      "execution_complexity": "medium",
      "expected_impact": "high",
      "proof_points": ["..."],
      "framework_inspiration": "Challenger",
      "source": "studio_generated",
      "favorited": true,
      "converted_to_campaign": false,
      "converted_campaign_id": null,
      "created_at": "2026-04-01T10:00:00Z",
      "updated_at": "2026-04-01T10:00:00Z"
    }
  ]
}
```

---

## Obtener campaña

`GET /campaigns/{campaign_id}`

Devuelve los detalles de la campaña junto con un resumen de los documentos completados.

### Ejemplo

**cURL**

```bash
curl "https://be.graph8.com/api/v1/campaigns/$CAMPAIGN_ID" \
  -H "Authorization: Bearer $API_KEY"
```

### Respuesta

```json
{
  "data": {
    "id": "cmp_abc",
    "name": "Q2 Outbound - VP Marketing",
    "slug": "q2-outbound-vp-marketing",
    "status": "draft",
    "category": "Outbound",
    "goal": "Book discovery calls",
    "target_persona": "VP Marketing at mid-market SaaS",
    "brief": "...",
    "core_concept": "...",
    "primary_hook": "Cut SDR ramp time in half",
    "channels": ["email", "linkedin"],
    "documents": [
      {"id": "doc_001", "name": "Campaign Brief", "type": "campaign_brief"},
      {"id": "doc_002", "name": "Sequence", "type": "sequence"}
    ],
    "created_at": "2026-04-01T10:00:00Z",
    "updated_at": "2026-04-10T14:30:00Z"
  }
}
```

### Errores

| Estado | Significado |
|--------|-------------|
| `404` | Campaña no encontrada |

---

## Actualizar campaña

`PATCH /campaigns/{campaign_id}`

Actualiza los campos de contenido de una campaña.

### Cuerpo de la solicitud

| Campo | Tipo | Descripción |
|-------|------|-------------|
| `name` | string | Nombre de la campaña |
| `brief` | string | Brief de la campaña |
| `core_concept` | string | Concepto central |
| `primary_hook` | string | Texto del gancho principal |
| `target_persona` | string | Persona objetivo |
| `category` | string | Categoría de la campaña |
| `goal` | string | Objetivo de la campaña |

### Errores

| Estado | Significado |
|--------|-------------|
| `400` | No se proporcionaron campos |
| `404` | Campaña no encontrada |

---

## Listar documentos de la campaña

`GET /campaigns/{campaign_id}/documents`

Devuelve los metadatos de cada documento asociado a la campaña (sin el payload de contenido).

### Respuesta

```json
{
  "data": {
    "campaign_id": "cmp_abc",
    "documents": [
      {
        "id": "doc_001",
        "campaign_id": "cmp_abc",
        "display_name": "Campaign Brief",
        "name": "Campaign Brief",
        "file_type": "campaign_brief",
        "type": "campaign_brief",
        "folder_path": "/brief",
        "status": "completed",
        "version": 2,
        "current_version": 2,
        "created_at": "2026-04-01T10:00:00Z",
        "updated_at": "2026-04-05T11:00:00Z"
      }
    ],
    "count": 1
  }
}
```

---

## Obtener documento de la campaña

`GET /campaigns/{campaign_id}/documents/{document_id}`

Devuelve el contenido completo del documento.

### Ejemplo

**cURL**

```bash
curl "https://be.graph8.com/api/v1/campaigns/$CAMPAIGN_ID/documents/$DOCUMENT_ID" \
  -H "Authorization: Bearer $API_KEY"
```

### Respuesta

```json
{
  "data": {
    "id": "doc_001",
    "campaign_id": "cmp_abc",
    "name": "Campaign Brief",
    "type": "campaign_brief",
    "status": "completed",
    "version": 2,
    "content": "# Campaign Brief\n\nGoal: ...",
    "created_at": "2026-04-01T10:00:00Z",
    "updated_at": "2026-04-05T11:00:00Z"
  }
}
```

---

## Crear documento de campaña

`POST /campaigns/{campaign_id}/documents`

Crea un nuevo documento adjunto a la campaña.

### Cuerpo de la solicitud

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `file_type` | string | **Sí** | Tipo de documento (`campaign_brief`, `sequence`, `step_catalog`, etc.) |
| `display_name` | string | **Sí** | Nombre legible para humanos |
| `content` | string | No | Contenido del documento (predeterminado `""`) |
| `folder_path` | string | No | Ruta de carpeta opcional |
| `status` | string | No (predeterminado `draft`) | Estado del documento |

### Respuesta `201 Created`

Devuelve la misma estructura de documento que `GET .../documents/{document_id}`.

---

## Actualizar documento de campaña

`PUT /campaigns/{campaign_id}/documents/{document_id}`

Actualiza el contenido. Incrementa `version` y `current_version` en 1, y registra `completed=true` y `generating=false` en los metadatos.

### Cuerpo de la solicitud

| Campo | Tipo | Descripción |
|-------|------|-------------|
| `content` | string | Nuevo contenido (mantiene el existente si está vacío) |
| `status` | string | Anulación de estado opcional |
| `structured_data` | object | Payload estructurado opcional almacenado en los metadatos |

### Errores

| Estado | Significado |
|--------|-------------|
| `404` | Documento no encontrado (o su campaña principal está archivada) |

---

## Eliminar documento de campaña

`DELETE /campaigns/{campaign_id}/documents/{document_id}`

Eliminación permanente. Devuelve `404` si no se encuentra el documento o su campaña principal.

### Respuesta

```json
{ "data": { "status": "deleted", "document_id": "doc_001" } }
```

---

## Obtener secuencia

`GET /campaigns/{campaign_id}/sequence`

Devuelve tanto el documento de **secuencia** (lista ordenada de referencias de pasos) como el documento de **catálogo de pasos** (definiciones de pasos identificadas por `step_id`).

### Respuesta

```json
{
  "data": {
    "campaign_id": "cmp_abc",
    "sequence": {
      "steps": [
        {"step_id": "step_1", "day": 0, "condition": null, "stop_on_reply": true},
        {"step_id": "step_2", "day": 3, "condition": "no_reply", "stop_on_reply": true}
      ]
    },
    "step_catalog": {
      "steps": {
        "step_1": {"name": "Intro email", "channel": "email", "mode": "send", ...},
        "step_2": {"name": "LinkedIn follow-up", "channel": "linkedin", "mode": "send", ...}
      }
    },
    "sequence_doc_id": "doc_seq_001",
    "catalog_doc_id": "doc_cat_001"
  }
}
```

### Errores

| Estado | Significado |
|--------|-------------|
| `404` | Campaña no encontrada |

---

## Actualizar secuencia

`PUT /campaigns/{campaign_id}/sequence`

Reemplaza la lista ordenada de referencias de pasos. Cada `step_id` debe existir en el catálogo de pasos.

### Cuerpo de la solicitud

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `steps` | object[] | **Sí** | Referencias ordenadas de pasos |

Cada elemento `step`:

| Campo | Tipo | Descripción |
|-------|------|-------------|
| `step_id` | string | ID del paso (debe existir en el catálogo) |
| `day` | integer | Desplazamiento en días desde el inicio de la secuencia |
| `condition` | string | Condición opcional (`no_reply`, etc.) |
| `stop_on_reply` | boolean | Predeterminado `true` |

### Errores

| Estado | Significado |
|--------|-------------|
| `400` | `step_id` no está en el catálogo |
| `404` | Documento de secuencia no encontrado |

---

## Crear paso de secuencia

`POST /campaigns/{campaign_id}/sequence/steps`

Crea un nuevo paso **y** lo agrega a la secuencia en una sola llamada. El endpoint genera un nuevo `step_id` (`step_N`).

### Cuerpo de la solicitud

| Campo | Tipo | Requerido | Descripción |
|-------|------|-----------|-------------|
| `name` | string | **Sí** | Nombre del paso |
| `channel` | string | **Sí** | `email`, `linkedin`, `sms`, `phone`, etc. |
| `mode` | string | **Sí** | `send`, `manual`, etc. |
| `day` | integer | **Sí** | Desplazamiento en días para la ubicación en la secuencia |
| `platform` | string | No | Plataforma del subcanal |
| `angle_id` | string | No (predeterminado `angle_1`) | Referencia del ángulo de mensajería |
| `cta_type` | string | No (predeterminado `soft_ask`) | Tipo de CTA |
| `personalization_level` | string | No (predeterminado `medium`) | Nivel de personalización |
| `constraints` | object | No | Diccionario de restricciones |
| `condition` | string | No | Condición de la secuencia |
| `stop_on_reply` | boolean | No (predeterminado `true`) | Detiene la inscripción del contacto al recibir respuesta |

### Respuesta `201 Created`

```json
{
  "data": {
    "status": "created",
    "step_id": "step_3",
    "step": {
      "step_id": "step_3",
      "name": "Final follow-up",
      "channel": "email",
      "mode": "send",
      "platform": null,
      "angle_id": "angle_1",
      "cta_type": "soft_ask",
      "personalization_level": "medium",
      "constraints": {}
    },
    "day": 7
  }
}
```

---

## Actualizar paso de secuencia

`PUT /campaigns/{campaign_id}/sequence/steps/{step_id}`

Actualiza la definición de un paso en el catálogo y, opcionalmente, su ubicación en la secuencia. Todos los campos son opcionales: envíe solo los que desee modificar.

### Cuerpo de la solicitud

| Campo | Tipo | Descripción |
|-------|------|-------------|
| `name` | string | Nombre del paso |
| `channel` | string | Canal |
| `mode` | string | Modo |
| `platform` | string | Plataforma |
| `angle_id` | string | Ángulo de mensajería |
| `cta_type` | string | Tipo de CTA |
| `personalization_level` | string | Nivel |
| `constraints` | object | Diccionario de restricciones |
| `do_not_send_rules` | string[] | Reglas que deben suprimir el envío |
| `day` | integer | Ubicación en la secuencia (actualiza el documento de secuencia, no el catálogo) |
| `condition` | string | Condición de ubicación en la secuencia |
| `stop_on_reply` | boolean | Anulación de ubicación en la secuencia |

Los campos `day`, `condition` y `stop_on_reply` modifican el documento de secuencia; el resto modifica la entrada del catálogo.

### Errores

| Estado | Significado |
|--------|-------------|
| `404` | Paso o catálogo de pasos no encontrado |

---

## Eliminar paso de secuencia

`DELETE /campaigns/{campaign_id}/sequence/steps/{step_id}`

Elimina un paso del catálogo y todas sus referencias en la secuencia.

### Respuesta

```json
{ "data": { "status": "deleted", "step_id": "step_3" } }
```

### Errores

| Estado | Significado |
|--------|-------------|
| `404` | Paso no encontrado |

---

## Lanzar campaña

`POST /campaigns/{campaign_id}/launch`

**Advertencia:** inicia prospección real hacia contactos reales. La validación
de audiencia, contenido, remitente y pasos ejecutables es obligatoria. La ruta
usa el flujo V2 de Sequencer y devuelve el estado real: `live` después de una
inicialización síncrona o `scheduling` mientras se ejecuta un trabajo en
segundo plano.

### Ejemplo

**cURL**

```bash
curl -X POST "https://be.graph8.com/api/v1/campaigns/$CAMPAIGN_ID/launch" \
  -H "Authorization: Bearer $API_KEY"
```

### Respuesta

```json
{
  "data": {
    "status": "scheduling",
    "campaign_id": "cmp_abc",
    "sequence_id": "seq_001",
    "execution": {
      "status": "scheduling",
      "job_id": "job_001",
      "polling_url": "/sequencer/sequences/jobs/job_001/status"
    },
    "message": "Sequence initialization started in background"
  }
}
```

Si se crea el borrador pero falla la activación, la ruta devuelve `502` con el
`sequence_id`, el estado confirmado cuando esté disponible y una instrucción
de recuperación. No repita un lanzamiento cuyo estado sea incierto.
