
# API para agencias

Como agencia, puede utilizar la misma API REST que utilizan sus clientes, pero dirigiendo las solicitudes individuales a una de sus **subcuentas** gestionadas en lugar de a su propia cuenta. Esto le permite crear herramientas que incorporen a un cliente de principio a fin: creando sus campañas, entrenando a su IA en una base de conocimientos, importando sus contactos, conectando sus canales de mensajería y comprando números de teléfono, todo ello sin tener que iniciar sesión manualmente en cada subcuenta.

Esta página cubre únicamente el comportamiento específico de la agencia: cómo actuar en nombre de una subcuenta con el parámetro `sub_account_id`. Para conocer los aspectos básicos (generación de claves, autenticación, URL base, formato de error, límites de velocidad), comience con la guía de [Acceso a la API](../integrations/api-access.md). Todo lo que se indica allí también se aplica aquí: usted se autentica con la clave de API de **su cuenta de agencia**.

::: note
**Nota:** Esta página es técnica. Si no es desarrollador, compártala con la persona que está creando su integración.
:::


***

## Cómo funciona "actuar en nombre de"

De forma predeterminada, cada solicitud de API actúa sobre la cuenta propietaria de la clave de API: su cuenta de agencia. Para actuar en nombre de una cuenta de cliente gestionada, añada el parámetro opcional `sub_account_id` a la solicitud, configurado con el ID de cuenta de dicho cliente.

- **Omitir `sub_account_id`** → la solicitud actúa sobre su propia cuenta de agencia.
- **Incluir `sub_account_id`** → la solicitud actúa sobre esa subcuenta, pero solo después de que la plataforma confirme que la subcuenta es realmente suya.

Usted siempre se autentica con la clave de API de **su cuenta de agencia**. Nunca necesita la clave propia de la subcuenta y nunca maneja las credenciales de la subcuenta.

### Dónde colocarlo

- **Endpoints GET / DELETE** → páselo como un parámetro de consulta: `?sub_account_id=THE_SUB_ACCOUNT_ID` (junto con su `apiKey`, si se autentica mediante consulta).
- **Endpoints POST / PUT / PATCH** → inclúyalo en el cuerpo de la solicitud JSON como `"sub_account_id": "THE_SUB_ACCOUNT_ID"`.
- **Asistentes de IA** → nada que configurar. El [servidor MCP](../integrations/connect-ai-clients.md) lleva la misma configuración en sus herramientas de lectura, por lo que una conexión con su clave de agencia puede informar sobre cada cliente: simplemente nombre al cliente en su solicitud ("¿cuántos contactos tiene Bella's Bistro?"). Las acciones de escritura también están disponibles: cada endpoint que acepta `sub_account_id` se expone como una herramienta, por lo que puede crear, cambiar y enviar en nombre de un cliente desde la misma conexión.

### Cómo encontrar el ID de una subcuenta

El `sub_account_id` es el identificador único de la cuenta del cliente. Puede obtener la lista de sus subcuentas y sus identificadores desde los endpoints de la API de **SubAccounts** (consulte la guía de [Sub-Accounts](sub-accounts.md)) o desde la página de **Sub Accounts** en la barra lateral.

***

## La propiedad siempre se verifica

Cuando usted pasa un `sub_account_id`, la plataforma comprueba que la cuenta sea una subcuenta real **y** que pertenezca a su agencia. Solo entonces se procesa la solicitud.

Si el ID es desconocido, no es una subcuenta o pertenece a una agencia diferente, la solicitud fallará con una respuesta **`404`**:

```json
{
  "success": false,
  "error_code": 404,
  "error": "Sub-account not found."
}
```

> **¿Por qué 404 y no 403?** Una respuesta de "prohibido" le diría a un extraño que el id existe pero no le pertenece. Devolver el mismo `404` para "no existe" y "no es tuyo" significa que el endpoint no puede utilizarse para descubrir qué ids de cuenta pertenecen a otras agencias. Trata un `404` aquí como "esta no es una subcuenta que tú administras".

***

## Dónde se admite `sub_account_id`

`sub_account_id` se acepta en prácticamente todos los endpoints de **recursos**: cualquier llamada que cree, lea, actualice o elimine los datos propios de una cuenta. En la práctica, puede aprovisionar y ejecutar toda la configuración de una subcuenta con su clave de agencia:

- **Configuración de IA** — campañas, agentes, preguntas frecuentes, fuentes de la base de conocimientos (rastreo de sitios web **y** carga de documentos), grupos de bases de conocimientos, difusiones, funciones personalizadas, servidores MCP
- **Contactos y CRM** — contactos (incluida la importación), listas, etiquetas, tareas, tratos, citas, eventos
- **Canales y números** — conectar WhatsApp / WhatsApp Web / Telegram / Instagram y Messenger / LINE, buscar / comprar / gestionar números de teléfono, plantillas de WhatsApp, enrutamiento de canales
- **Mensajería y contenido** — enviar mensajes, sesiones de chat, exportaciones de chat, resúmenes diarios
- **Configuración e integraciones** — webhooks, configuración del widget de chat, configuración de marca blanca, SMS BYOK y otros ajustes de cuenta, análisis

En todos ellos, el parámetro es **opcional**: si lo omite, la llamada actuará sobre su propia cuenta de agencia, por lo que una única integración sirve para ambos casos. Los créditos y el uso siempre provienen de la cuenta a la que se dirige: los cargos por las campañas, mensajes, etiquetas y números de una subcuenta se aplican al saldo **de la subcuenta**.

### Dónde NO se aplica

Algunos endpoints son de nivel de agencia o se dirigen a sí mismos e ignoran `sub_account_id`:

- **Gestión de las subcuentas en sí** — los endpoints de SubAccounts (crear / listar / actualizar una subcuenta) y el endpoint de límite de gasto BYOK ya nombran la subcuenta en su propia ruta URL. Los [endpoints de precios y políticas](#set-per-client-ai-pricing-and-policy) y los [endpoints de monitoreo de chat](#read-a-sub-accounts-conversations) siguen el mismo patrón.
- **Copiar un Agente entre cuentas** — `POST /v1/subaccounts/agents/copy` nombra ambas cuentas, tomando el destino como `targetUserId`. Consulte el [ejemplo práctico](#worked-example-ship-a-template-agent-into-every-new-client) a continuación. (El `POST /v1/subaccounts/campaigns/copy` más antiguo funciona de la misma manera, pero está obsoleto junto con el resto de la [API de Campañas](../api/campaigns.md).)
- **Ajuste de créditos y los dos resúmenes a nivel de agencia** — [`POST /v1/subaccounts/credits`](#grant-or-deduct-credits-directly) identifica la subcuenta mediante `email` en su lugar; [`GET /v1/subaccounts/credit-usage`](#read-credit-usage-and-campaign-health-across-your-book) y `GET /v1/subaccounts/campaign-status` informan sobre todas las subcuentas a la vez, por lo que no hay una sola cuenta a la cual dirigirse.
- **La propia cuenta de su agencia** — La gestión de claves API, los informes de uso de la agencia, la gestión de equipos y sus [niveles de precios](#manage-your-pricing-tiers-over-the-api) siempre actúan sobre la cuenta de su agencia.
- **Webhooks de mensajes entrantes** — los endpoints en los que los sistemas externos publican *hacia* están vinculados a la cuenta cuyas credenciales los configuraron, por lo que no hay nada que redirigir.

> La lista siempre actualizada y legible por máquina de los parámetros que acepta cada endpoint se encuentra en la referencia de la API de su panel de control (**Settings → Integrations → API Key**) y en la especificación OpenAPI en `GET /v1/docs/openapi.yaml`. Realizamos cambios en la API con frecuencia; considérelos como la fuente de información definitiva.

::: master-only
<figure><img src="../.gitbook/assets/v2-api-access-key-section.png" alt="Página de configuración de la clave API con la clave enmascarada y el control de regeneración"><figcaption><p>Configuración → Integraciones → Clave API — la clave de tu agencia se encuentra aquí, junto con el enlace a la referencia completa de la API.</p></figcaption></figure>
:::

***

## Ejemplo práctico: conectar Instagram y Messenger para una subcuenta

Conectar Instagram y Messenger es un flujo basado en navegador. Lo inicias con la API, entregas la URL de consentimiento devuelta al cliente (o la abres por él), esperas a que autorice en su navegador y luego eliges qué página conectar, todo ello mientras apuntas a su subcuenta con `sub_account_id`.

### Paso 1 — Iniciar la conexión

Llama al endpoint de conexión con el `sub_account_id` del cliente en el body. Aquí no se envían credenciales; la plataforma devuelve una URL de consentimiento que el cliente debe abrir en un navegador, además de un token de correlación de un solo uso.

**cURL**

```bash
curl -X POST "https://api.dmchamp.com/v1/channels/meta/connect?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sub_account_id": "abc123def456"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.dmchamp.com/v1/channels/meta/connect", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    sub_account_id: "abc123def456",
  }),
});

const data = await res.json();
// data.oauth_url -> open this in the client's browser
```

**Python**

```python
import requests

res = requests.post(
    "https://api.dmchamp.com/v1/channels/meta/connect",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "sub_account_id": "abc123def456",
    },
)

data = res.json()
# data["oauth_url"] -> open this in the client's browser
```

**Respuesta:**

```json
{
  "success": true,
  "oauth_url": "https://www.facebook.com/v21.0/dialog/oauth?client_id=...&state=...",
  "state_token": "8sFq2yV0kQ7m4n1pZr3tWb6cXe9hJl2aD5gK7uN0oI",
  "expires_at": "2026-06-10T12:30:00.000Z"
}
```

Envía al cliente a `oauth_url` en un navegador para autorizar. El `state_token` correlaciona este intento y es un secreto de corta duración; no lo registres. El intento caduca en `expires_at`; si vence, comienza de nuevo.

### Paso 2 — Realizar sondeos hasta que las páginas se carguen

Después de que el cliente autorice, consulte el endpoint de estado (con el mismo `sub_account_id`, esta vez como parámetro de consulta) hasta que aparezcan las páginas conectables.

**cURL**

```bash
curl "https://api.dmchamp.com/v1/channels/meta/status?apiKey=YOUR_API_KEY&sub_account_id=abc123def456"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.dmchamp.com/v1/channels/meta/status?sub_account_id=abc123def456",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);

const data = await res.json();
// Wait until data.status === "pages_loaded", then read data.pages
```

**Python**

```python
import requests

res = requests.get(
    "https://api.dmchamp.com/v1/channels/meta/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"sub_account_id": "abc123def456"},
)

data = res.json()
# Wait until data["status"] == "pages_loaded", then read data["pages"]
```

**Respuesta:**

```json
{
  "success": true,
  "status": "pages_loaded",
  "pages": [
    {
      "id": "1098765432101234",
      "name": "Acme Studio",
      "category": "Hair Salon",
      "instagram_business_account": {
        "id": "17841400000000000",
        "username": "acme.studio"
      }
    }
  ],
  "selected_page": null
}
```

El campo `status` avanza a través de `pending` → `token_received` → `pages_loaded` → `connected`. Espere a `pages_loaded` antes de seleccionar una página. También pueden aparecer dos estados de error terminal en lugar de avanzar: `failed` y `expired` (el cliente rechazó el consentimiento o el periodo de ~30 minutos del token de estado ha caducado); se incluye un campo `reason` cuando ocurre cualquiera de ellos. Deje de realizar sondeos y reinicie en el Paso 1 si ve uno; no espere en `pending` indefinidamente. Los tokens de acceso a la página nunca se devuelven.

### Paso 3 — Seleccionar la página para conectar

Elija uno de los identificadores de página del Paso 2 y selecciónelo. Al seleccionar una página, se conectan tanto Instagram como Messenger para dicha página. Incluya `sub_account_id` en el cuerpo nuevamente.

**cURL**

```bash
curl -X POST "https://api.dmchamp.com/v1/channels/meta/select-page?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "page_id": "1098765432101234",
    "sub_account_id": "abc123def456"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.dmchamp.com/v1/channels/meta/select-page", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    page_id: "1098765432101234",
    sub_account_id: "abc123def456",
  }),
});

const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.dmchamp.com/v1/channels/meta/select-page",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "page_id": "1098765432101234",
        "sub_account_id": "abc123def456",
    },
)

data = res.json()
```

**Respuesta:**

```json
{
  "success": true,
  "page_id": "1098765432101234",
  "instagram_business_account_id": "17841400000000000"
}
```

Eso es todo: Instagram y Messenger ya están conectados en la subcuenta del cliente. Usted solo proporcionó el `page_id`; la credencial subyacente se resuelve en el servidor y nunca pasa a través de su integración.

***

## Ejemplo práctico: comprar un número para una subcuenta

La compra de un número funciona de la misma manera: busque con `sub_account_id` en la consulta y luego realice la compra incluyéndolo en el cuerpo. Los créditos se deducen del saldo **de la subcuenta** y el número se aprovisiona en la subcuenta.

**Búsqueda (cURL):**

```bash
curl "https://api.dmchamp.com/v1/phone-numbers/available?apiKey=YOUR_API_KEY&country_code=US&sub_account_id=abc123def456"
```

**Compra (JavaScript):**

```javascript
const res = await fetch("https://api.dmchamp.com/v1/phone-numbers", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phone_number: "+14155551234",
    country_code: "US",
    display_name: "Support line",
    sub_account_id: "abc123def456",
  }),
});

const data = await res.json();
```

**Compra (Python):**

```python
import requests

res = requests.post(
    "https://api.dmchamp.com/v1/phone-numbers",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "phone_number": "+14155551234",
        "country_code": "US",
        "display_name": "Support line",
        "sub_account_id": "abc123def456",
    },
)

data = res.json()
```

**Respuesta:**

```json
{
  "success": true,
  "phone_number": "+14155551234",
  "channel": "whatsapp",
  "whatsapp_status": "PURCHASED",
  "outgoing_status": "PURCHASED",
  "status": "PURCHASED",
  "purchase_credits": 11.5,
  "monthly_credits": 11.5
}
```

El número se aprovisiona en el estado `PURCHASED` y el registro del remitente de WhatsApp continúa en segundo plano. Realice sondeos en `GET /v1/phone-numbers/{phoneNumber}/status?sub_account_id=abc123def456` hasta que el estado llegue a `ONLINE` antes de enviar.

***

## Ejemplo práctico: enviar un Agente de plantilla a cada cliente nuevo

El patrón habitual de las agencias es mantener un Agente maestro en su cuenta de agencia, configurado de la forma en que desea que cada cliente comience, y estampar una copia del mismo en cada subcuenta nueva en el momento del aprovisionamiento. Son tres llamadas y no es necesario repetir nada después: la copia conserva su configuración hasta que usted la cambie.

### Paso 1 — Copiar el Agente

`POST /v1/subaccounts/agents/copy`

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts/agents/copy?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "YOUR_TEMPLATE_AGENT_ID",
    "targetUserId": "abc123def456",
    "newName": "Inbound Instagram Leads",
    "copyFaqs": true
  }'
```

La respuesta contiene el id del nuevo Agente en `data.agent_id`. Las preguntas frecuentes, la base de conocimientos y la biblioteca de medios se incluyen; las plantillas de WhatsApp, las publicaciones sociales conectadas y los contactos de la cuenta de origen deliberadamente no se incluyen. Lista completa de campos en la [API de Agentes de IA](../api/agents.md#copy-an-agent-into-a-sub-account-agencies).

Ten en cuenta que este endpoint utiliza `targetUserId` en lugar de `sub_account_id`; nombra ambas cuentas por sí mismo. Las dos llamadas siguientes utilizan el parámetro normal `sub_account_id`.

### Paso 2 — Activarlo

La copia siempre llega en pausa, por lo que no puede enviar mensajes a nadie hasta que usted lo indique. Este es también el momento de fijar el nivel de IA en el que desea que esté el cliente; permanece allí, por lo que no es necesario volver a aplicarlo según un cronograma.

```bash
curl -X PATCH "https://api.dmchamp.com/v1/agents/NEW_AGENT_ID/active?apiKey=YOUR_API_KEY&sub_account_id=abc123def456" \
  -H "Content-Type: application/json" \
  -d '{ "active": true }'

curl -X PUT "https://api.dmchamp.com/v1/agents/NEW_AGENT_ID?apiKey=YOUR_API_KEY&sub_account_id=abc123def456" \
  -H "Content-Type: application/json" \
  -d '{ "anthropic_model": "max" }'
```

Para evitar que el cliente cambie el nivel después, [bloquee los niveles permitidos](#set-per-client-ai-pricing-and-policy) en la subcuenta en lugar de volver a enviar el valor.

### Paso 3 — Dirigir los canales del cliente hacia ella

La copia tampoco llega con enrutamiento, por lo que nada llega a ella hasta que usted la convierte en el respondedor en los canales que el cliente ha conectado. Una llamada por canal:

```bash
curl -X PUT "https://api.dmchamp.com/v1/entry-points/channel-defaults?apiKey=YOUR_API_KEY&sub_account_id=abc123def456" \
  -H "Content-Type: application/json" \
  -d '{ "channel": "instagram", "agent_id": "NEW_AGENT_ID" }'
```

A partir de aquí, un mensaje inicial de un contacto desconocido en ese canal es captado automáticamente por el Agente copiado. Consulte [Apuntar un canal a un Agente](../api/entry-points.md#point-a-channel-at-an-agent) para conocer los otros canales y el enrutamiento por número.

> **Establece la zona horaria del cliente cuando crees la subcuenta.** Pasa `time_zone_id` en `POST /v1/subaccounts`. Las horas activas de la campaña se evalúan en la propia zona horaria de la subcuenta, por lo que un cliente creado sin una tendrá su programación leída según UTC, lo que cambia silenciosamente cuándo se permite responder al asistente.

***

## Omitir el asistente de configuración para un cliente que usted mismo configura

`POST /v1/subaccounts`

De forma predeterminada, la primera vez que el propietario de una nueva subcuenta inicia sesión, se le guía a través del Asistente de configuración. Para clientes con servicio completo (done-for-you), donde usted crea la campaña y conecta los canales antes de que el cliente inicie sesión, pase `guided_onboarding: false` al crear la cuenta. En su lugar, llegarán al panel de control y la entrada **Asistente de configuración** se ocultará de su barra lateral.

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "client@example.com",
    "first_name": "Alex",
    "last_name": "Client",
    "business_name": "Client Co",
    "guided_onboarding": false,
    "usage_limits": { "monthly_credits": 500 }
  }'
```

Omite el campo (o envía `true`) y el asistente se comportará exactamente como siempre lo ha hecho, por lo que las integraciones existentes no necesitan cambios. Para devolverle el asistente a un cliente más tarde, vuelve a mostrar el elemento `guided_onboarding` con `PUT /v1/subaccounts/{subAccountUid}/menu-visibility` (a continuación): la visibilidad del menú controla si el asistente es accesible, `guided_onboarding` controla solo la redirección del primer inicio de sesión.

***

## Desactivar Tareas, Resúmenes diarios o la Biblioteca de medios para un cliente

`POST /v1/subaccounts`

Estas tres funciones están activadas para cada cliente nuevo a menos que indique lo contrario, y se comportan de forma diferente a cualquier otra función de esta guía: son de **exclusión voluntaria** (opt-out), no de inclusión. Dejarlas fuera de `features` no es suficiente por sí solo, porque la lista `features` de una integración antigua simplemente no las mencionaba; no podemos distinguir entre "la agencia desactivó esto" y "esta lista se escribió antes de que existiera la opción".

Por lo tanto, indíquelo explícitamente con `feature_settings`:

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "client@example.com",
    "first_name": "Alex",
    "last_name": "Client",
    "business_name": "Client Co",
    "feature_settings": {
      "tasks": false,
      "daily_summaries": false,
      "ai_media_library": true
    }
  }'
```

Cada clave es opcional; todo lo que omita permanecerá activado. Con `tasks: false`, la IA deja de crear tareas para ese cliente y no se envían correos electrónicos de "Nueva tarea creada"; con `daily_summaries: false`, el resumen nocturno nunca se genera ni se envía por correo electrónico.

`feature_settings` es lo único que desactiva estas tres funciones en el momento de la creación. Dejarlas fuera de `features` no hace nada por sí solo, sin importar cómo se vea el resto de su lista; esto es deliberado, para que una integración antigua no pierda las tres funciones de forma silenciosa.

Para cambiar cualquiera de estos ajustes posteriormente, envíe la lista `features` completa a `PUT /v1/subaccounts/{subAccountUid}/features`; allí, la presencia en la lista activa una función y su ausencia la desactiva.

***

## Inicie sesión automáticamente a sus clientes en su subcuenta (SSO)

`POST /v1/subaccounts/{subAccountUid}/sso-link`

Una llamada con la clave API de su agencia devuelve una URL lista para abrir que inicia la sesión del cliente directamente en su propia subcuenta: sin pantalla de inicio de sesión, sin pasos de contraseña, nada que construir adicionalmente. Ábrala en una nueva pestaña, mediante una redirección o en un iframe dentro de su propio producto.

| Campo | Obligatorio | Descripción |
|---|---|---|
| `redirect` | No | Página dentro de la aplicación en la que desea que termine el cliente, p. ej., `"/chats"` o `"/agents"`. Se devuelve como `deep_link_url` en la respuesta. |
| `app_base_url` | No | Host del panel para el enlace. El valor predeterminado es su dominio de aplicación de marca blanca (o el dominio de la plataforma si no tiene ninguno). Debe ser `https`. |

**cURL**

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/sso-link" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "redirect": "/chats" }'
```

**Respuesta**

```json
{
  "success": true,
  "url": "https://app.yourdomain.com/auth?redirect=%2Fchats#token=eyJhbGciOi…",
  "deep_link_url": "https://app.yourdomain.com/chats",
  "expires_at": "2026-07-22T15:04:05.000Z",
  "sub_account_uid": "SUB_ACCOUNT_UID"
}
```

Cómo utilizarlo correctamente:

- **Un solo salto.** Abrir `url` inicia la sesión del cliente y lo lleva directamente a la página `redirect` del panel de control; sin pantalla de inicio de sesión ni páginas intermedias. `deep_link_url` designa el mismo destino, para los integradores que prefieren navegar por un marco explícitamente después de iniciar sesión; una vez que existe la sesión, cualquier ruta del panel de control funciona en ese contexto del navegador.
- **Crear bajo demanda, abrir inmediatamente.** El enlace contiene una credencial de inicio de sesión y caduca después de aproximadamente una hora. Solicítelo en el lado del servidor en el momento en que el cliente haga clic, y nunca lo almacene ni lo envíe por correo electrónico.
- El token de inicio de sesión viaja en el fragmento de la URL (`#…`), que los navegadores nunca envían a los servidores, y se elimina de la barra de direcciones en el momento en que se consume.
- **Solo sus propias subcuentas.** El endpoint rechaza cualquier cuenta que su agencia no posea.
- Un enlace caducado muestra un error claro con una ruta de reintento: cree uno nuevo.

***

## Ocultar elementos de navegación en una subcuenta

`PUT /v1/subaccounts/{subAccountUid}/menu-visibility`

Controla qué elementos de la barra lateral y de configuración ve una subcuenta; es útil cuando integra el panel de control y solo desea las superficies que su producto aún no cubre. Todo lo que no esté en la lista permanece visible; envíe `null` como el valor completo de `menuVisibility` para restablecer todo a visible. Ocultar un elemento oculta la entrada del menú: combínelo con las funciones que otorga a la subcuenta para un control estricto.

**cURL**

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/menu-visibility" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "menuVisibility": {
      "side_nav": { "Dashboard": false, "Campaigns": false, "Automations": false },
      "settings_nav": { "team": false }
    }
  }'
```

**Respuesta**

```json
{
  "success": true,
  "data": {
    "subAccountUid": "SUB_ACCOUNT_UID",
    "menuVisibility": {
      "side_nav": { "Dashboard": false, "Campaigns": false, "Automations": false },
      "settings_nav": { "team": false }
    }
  }
}
```

`side_nav` acepta estas 13 claves, que coinciden con los nombres de los elementos de la barra lateral: `Dashboard`, `DailySummaries`, `Chats`, `Contacts`, `Deals`, `Tasks`, `Automations`, `Campaigns`, `Appointments`, `Settings`, `Help`, `CreditsCounter` (el saldo de crédito que se muestra en la barra lateral) y `guided_onboarding` (el asistente de configuración). Se aceptan otras tres claves — `AiInsights`, `Sub Accounts` y `Agency Reselling` — pero no realizan ninguna acción: solo se aplicaban al panel de control clásico retirado, por lo que configurarlas no tiene ningún efecto en sus subcuentas. Las claves que faltan significan que están visibles; cuando usted mismo inicia sesión en la subcuenta, los elementos ocultos se muestran temporalmente para que siempre pueda volver a cambiarlos.

Ocultar una página del menú nunca otorga acceso a ella. `Automations` necesita que la función `automations` esté concedida en la subcuenta; si establece la clave en `true` sin ella, la página seguirá sin aparecer. `Tasks` y `DailySummaries` funcionan a la inversa: están activadas para todos los clientes a menos que las desactive (consulte [Desactivar Tareas, Resúmenes diarios o la Biblioteca de medios para un cliente](#turn-tasks-daily-summaries-or-the-media-library-off-for-a-client)).

***

## Elija qué tipos de canal puede conectar un cliente

`PUT /v1/subaccounts/{subAccountUid}/features`

Los interruptores de **Tipos de canal** que ve en un nivel de plan son ID de funciones comunes, por lo que puede configurarlos por cliente desde la API en lugar del panel de control. Este es uno de los puntos finales que nombra a la subcuenta en su propia URL, por lo que no requiere `sub_account_id`.

| ID de función | Canal |
|---|---|
| `channel_chat_widget` | Widget de chat del sitio web |
| `channel_whatsapp_api` | API de WhatsApp Business |
| `channel_whatsapp_web` | WhatsApp Web (número vinculado por QR) |
| `channel_instagram` | Instagram |
| `channel_messenger` | Facebook Messenger |
| `channel_telegram` | Telegram |
| `channel_line` | LINE |
| `channel_viber` | Viber |
| `channel_email` | Buzón de correo electrónico |
| `channel_sms` | SMS |
| `channel_imessage` | iMessage |

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/features" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "features": [
      "channels_3",
      "channel_chat_widget",
      "channel_whatsapp_web",
      "channel_instagram",
      "image_understanding",
      "contact_tagging",
      "incoming_campaigns",
      "webhooks"
    ]
  }'
```

Tres cosas que debe tener en cuenta:

- **La llamada reemplaza toda la lista de funciones.** Envíe todas las funciones que el cliente debe conservar, no solo las que está cambiando. Los mismos ID funcionan como `features` en `POST /v1/subaccounts` cuando crea la cuenta.
- **Los tipos de canal y el recuento de canales son puertas separadas, y ambas se aplican.** `channels_1` / `channels_3` / `channels_unlimited` controlan *cuántas* conexiones; los ID de `channel_*` controlan *qué tipos*. El ejemplo anterior significa "hasta 3 conexiones, y solo Widget de chat, WhatsApp Web o Instagram".
- **No enviar ningún ID de `channel_*` significa que no hay restricción de canal.** Ese es el comportamiento original, razón por la cual los clientes existentes no se vieron afectados cuando se lanzó esto. Envíe uno o más y todo lo demás aparecerá como bloqueado en la página de Canales del cliente con una nota de actualización en lugar de un botón Conectar. Los canales que el cliente ya conectó seguirán funcionando.

> La configuración de la lista de canales en un **nivel de plan**, para que cada cliente que compre ese nivel la herede, se realiza en el panel de control bajo la configuración de su plan de agencia. Este punto final la establece en una subcuenta específica.

***

## Establecer un límite exacto de miembros del equipo para un cliente

`PUT /v1/subaccounts/{subAccountUid}/limits`

Las funciones de `team_seats_*` solo ofrecen niveles preestablecidos (3 / 5 / 10 / ilimitado). Para asignar a un cliente un número **exacto** de puestos de equipo (2, 7, 15, o cualquier otro), configure `usage_limits.team_seats_limit` en su lugar. Esta opción prevalece sobre los valores preestablecidos y la plataforma la aplica en cada invitación, adición directa y aceptación de invitación: una vez alcanzado el límite, se rechazan las invitaciones adicionales desde el lado del servidor.

- Un número entero positivo es el límite exacto.
- `0` significa que los miembros del equipo **no están incluidos**: el cliente no puede invitar a nadie.
- `-1` significa ilimitado.
- `null` borra el límite personalizado y vuelve al valor preestablecido de `team_seats_*` que esté en la lista de funciones.

Reducir el límite nunca elimina a los miembros del equipo existentes; solo impide que se añadan otros nuevos.

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/limits" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "usageLimits": { "team_seats_limit": 7 }
  }'
```

También puede establecerlo en el momento de la creación: `POST /v1/subaccounts` acepta `usage_limits.team_seats_limit` con la misma semántica. Para leer el valor actual, obtenga la subcuenta con `GET /v1/subaccounts?email=...` y consulte `usage_limits.team_seats_limit` (ausente/`null` = los valores predeterminados deciden). El mismo endpoint también actualiza `credits`, `monthly_credits`, `roll_over_to_next_month`, `rollover_cap_months`, `rollover_expiry_days` y `byok_monthly_limit_usd`: envíe solo las claves que desea cambiar.

**Cómo interactúa esto con los límites de asientos de los planes SaaS.** Sus planes SaaS pueden tener su propia asignación de asientos (configurada en el editor de planes; consulte [Asientos de equipo en un plan](agency-accounts.md#step-3--set-up-pricing-tiers)), la cual se aplica automáticamente cuando un cliente se suscribe. Un límite que usted establezca a través de este endpoint cuenta como una concesión **manual**: comprar un plan lo reemplaza con la propia asignación de asientos del plan (esa compra es una elección explícita del plan), pero las **renovaciones** mensuales automáticas **nunca sobrescriben un límite manual**; por lo tanto, una excepción única que usted otorgue a un cliente persiste durante su ciclo de facturación. Borrar el límite manual con `null` devuelve el control del campo al plan en su próxima renovación.

**Limite lo que un cliente transfiere entre renovaciones.** Dos claves `usage_limits` adicionales se encuentran junto a `roll_over_to_next_month`. Ambas también son aceptadas por `POST /v1/subaccounts` en el momento de la creación, y `null` borra cualquiera de las dos.

| Clave | Qué hace |
|---|---|
| `rollover_cap_months` | Meses de asignación que el cliente puede conservar. Un número del 0 al 120, se permiten fracciones (`0.5` = medio mes). En cada renovación, el saldo no utilizado se recorta hasta un máximo de esta cantidad multiplicada por la asignación que otorga esa renovación, antes de que se añadan los nuevos créditos; `0` no transfiere nada. |
| `rollover_expiry_days` | Un número entero de días, de 1 a 3650. Los créditos que quedan sin usar durante tanto tiempo se eliminan en la primera renovación después de alcanzar esa antigüedad. El gasto siempre se descuenta primero de los créditos más antiguos, por lo que un cliente que gasta su asignación cada mes nunca pierde ninguno. |

Si no se establecen, ambos recurren al plan del cliente; un valor enviado aquí prevalece sobre el del plan. Solo los créditos recurrentes (la asignación mensual y los créditos del plan) están sujetos a ellos: las recargas, las recargas automáticas y las adiciones únicas nunca se limitan ni caducan. Cada recorte se registra en el historial de créditos del cliente como un **Ajuste de crédito por límite de transferencia** o un **Ajuste de crédito por créditos caducados** y nunca cuenta como uso. Los equivalentes a nivel de plan son `rollover_cap_months` y `rollover_expiry_days` en un nivel de precios: consulte [Los campos en un nivel](#the-fields-on-a-tier) y [Limitar lo que se transfiere](sub-accounts.md#capping-what-rolls-over).

***

## Establecer precios y políticas de IA por cliente

`PUT /v1/subaccounts/{subAccountUid}/max-tier` · `/ai-tiers` · `/max-rate` · `/action-pricing` · `/insider-rate` · `/locked-bot-fields` · `/notifications` · `/zero-credit-reply`

Ocho interruptores más por cliente, junto con `/limits`, `/features` y `/menu-visibility` anteriores. Cada uno toma el uid de la subcuenta en la URL (sin `sub_account_id` cuerpo/parámetro de consulta: el objetivo ya está nombrado en la ruta) y tiene el mismo alcance: su clave de agencia, y la subcuenta debe pertenecer a su agencia.

**Qué modelos de IA puede usar un cliente**

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/max-tier" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'
```

`{ "enabled": boolean }` inscribe al cliente en (o lo excluye de) el nivel Max AI: nuestra infraestructura al precio de lista de la plataforma. Activar esto para un cliente BYOK cambia su costo de IA de "gratis con mi propia clave" a "cargado contra mi fondo de crédito", por lo que es una decisión deliberada por cliente en lugar de un valor predeterminado para toda la agencia.

Para restringir QUÉ niveles pueden elegir las campañas y agentes de un cliente (en lugar de solo limitar Max), use `ai-tiers`:

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/ai-tiers" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "allowed_ai_tiers": ["standard", "economy"] }'
```

`allowed_ai_tiers` es una matriz extraída de `standard`, `economy`, `max`, `mini` — REEMPLAZA la lista de permitidos del cliente. Envíe `null` (o `[]`) para borrar la restricción y permitirles elegir cualquier nivel. Esto es importante porque una subcuenta que elige su propio nivel de IA gasta de **su** fondo de crédito, por lo que es la palanca para determinar qué modelos puede ejecutar un cliente revendedor en su factura.

**Una respuesta de espera mientras el cliente no tiene créditos**

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/zero-credit-reply" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true, "message": "Thanks for your message, we will get back to you shortly." }'
```

Cuando el saldo del cliente (o su grupo) está vacío, la IA no puede responder y el contacto no recibe nada. Con `enabled: true`, cada contacto que escribe durante la interrupción recibe `message` una vez (máximo 500 caracteres, enviado tal cual en cada canal), y la IA responde a esas conversaciones de verdad una vez que los créditos vuelven. `enabled: false` guarda el texto para más tarde; `enabled: false` sin `message` elimina la configuración. Es el mismo interruptor que **Respuesta de espera cuando no hay créditos** en el modal de edición de la subcuenta: consulte [Una respuesta de espera mientras un cliente no tiene créditos](sub-accounts.md#a-holding-reply-while-a-client-is-out-of-credits).

**Lo que paga un cliente por acción de IA y el margen de beneficio de la tarifa de WhatsApp**

Dos formas de establecer su tarifa orientada al cliente, desde la más simple hasta la más granular:

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/max-rate" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "rate": 0.35 }'
```

`rate` es el precio en créditos que consume el saldo PROPIO de la subcuenta por cada acción de IA del modelo Max: su margen de beneficio orientado al cliente sobre lo que realmente paga su fondo. `null` borra la anulación y vuelve al precio de lista de la plataforma. La tarifa debe ser al menos lo que cuesta una acción Max para su propio fondo (por lo que nunca puede cobrar a un cliente por debajo de su costo) y no más de 10 créditos; una solicitud fuera de ese rango se rechaza con el límite inferior calculado en el mensaje de error.

Para precios por tipo de acción en lugar de una tarifa Max plana, use `action-pricing`:

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/action-pricing" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "actionPricing": {
      "AI_MESSAGE": 0.6,
      "CHAT_SUMMARY": 0.15,
      "wa_carrier_multiplier": null
    }
  }'
```

`actionPricing` es una FUSIÓN en el mapa existente del cliente: una clave que no menciona se deja como estaba, y `null` restablece esa clave a su valor predeterminado. Las claves reconocidas:

| Clave | Precios |
|---|---|
| `AI_MESSAGE` | Una respuesta de IA |
| `AI_TOOL_USE` | Una llamada a herramienta de IA |
| `EVALUATION_CALL` | Una pasada de evaluación de chat |
| `INTERRUPTION_HANDLING` | Manejo de una interrupción a mitad de respuesta |
| `CONTACT_TAG` | Una etiqueta de contacto asignada por IA |
| `CHAT_SUMMARY` | Un resumen de chat |
| `wa_carrier_multiplier` | Un multiplicador de margen aplicado a cada tarifa de WhatsApp que no sea de IA que paga el cliente: alquiler mensual de números, tarifas de entrega en carriles gestionados y costos de transferencia de Meta/Twilio. |

Las tarifas por acción deben ser un número mayor que 0 y hasta 10; `wa_carrier_multiplier` debe ser al menos `1` (sin descuentos por debajo del costo) y hasta 10. Enviar una clave no reconocida, o un valor fuera de rango, rechaza TODA la solicitud y nombra cada clave infractora, por lo que un error tipográfico nunca puede guardar silenciosamente un precio que en realidad no se aplica.

Si eres miembro de [Champions Circle](https://skool.com/dm-champions), `insider-rate` transfiere tu tarifa de 20% de descuento de Max/Lead Finder a un solo cliente en lugar de aplicarla a toda la agencia:

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/insider-rate" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'
```

Activarla requiere que tu propia cuenta de agencia tenga realmente una membresía Circle; desactivarla nunca lo requiere, por lo que un miembro cuya membresía haya caducado siempre puede revertir los cambios de un cliente.

**Bloquear secciones del manual de estrategias de un cliente**

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/locked-bot-fields" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "locked_bot_fields": ["instructions", "rules"] }'
```

`locked_bot_fields` es una matriz extraída de `instructions`, `goal`, `rules`, `personality`, `conclude_unless` — REEMPLAZA la lista bloqueada del cliente. Una sección bloqueada es rechazada por el servidor si la propia SUB-CUENTA intenta cambiarla (directamente o mediante clave API), mientras que tú (a través de `sub_account_id`) y la vista de administrador del panel del cliente aún pueden editar cualquier cosa. Envía `null` (o `[]`) para desbloquear todo. Útil para clientes con servicios gestionados donde tú eres dueño del manual de estrategias y se te juzga por el resultado.

**Establecer las preferencias de notificación de un cliente en su nombre**

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/notifications" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "notifications": {
      "settings": {
        "credit_alerts": { "enabled": true, "channels": ["email", "in_app"] },
        "new_contacts": { "enabled": false }
      }
    }
  }'
```

`notifications` reemplaza todo el conjunto de preferencias de notificación del cliente (no es una combinación por clave; envía todas las categorías que desees mantener, coincidiendo con cómo se guarda la página de Configuración de la propia subcuenta). Cada categoría bajo `settings` acepta `enabled` (booleano) y hasta tres `channels` de `email`, `in_app`, `webhook`. Envía `null` para restablecer a los valores predeterminados de la plataforma.

Los siete endpoints responden `{ "success": true, "data": { "subAccountUid": "...", ...the field(s) you set... } }` y se registran en la auditoría con el valor antes/después. Errores comunes: `403` si tu cuenta no es de Agencia/Desarrollador o la subcuenta no es tuya para administrar, `400` si no es una subcuenta de agencia o un valor está fuera de rango.

***

## Pausar a un cliente que ha suspendido su suscripción

`POST /v1/subaccounts/{subAccountUid}/pause` · `POST /v1/subaccounts/{subAccountUid}/unpause`

Cuando un cliente suspende su suscripción con usted, pause su cuenta en lugar de eliminarla: todo lo que envían se detiene inmediatamente (mensajes salientes, difusiones, respuestas de IA en todos los canales) y, cuando inician sesión, ven un bloqueo de pantalla completa de **Cuenta pausada** (con su mensaje opcional) en lugar de la aplicación. No se elimina ni se desconecta nada: los agentes, las campañas, los canales conectados, los contactos y el historial de chat permanecen exactamente como están, por lo que reanudar la cuenta devuelve al cliente exactamente al punto donde lo dejó, sin necesidad de volver a realizar la configuración.

| Campo | Obligatorio | Descripción |
|---|---|---|
| `message` | No | Se muestra al cliente en su pantalla de bloqueo. Déjelo vacío para usar el texto predeterminado. |
| `reason` | No | Nota interna de la agencia almacenada con la pausa y en el registro de auditoría; nunca se muestra al cliente. |

**cURL**

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/pause" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Your account is on hold — contact us to reactivate it.", "reason": "Subscription suspended per client email" }'
```

**Respuesta**

```json
{
  "success": true,
  "data": {
    "subAccountUid": "SUB_ACCOUNT_UID",
    "paused": true,
    "level": "hard_blocked"
  }
}
```

Cuando el cliente regresa, `POST /v1/subaccounts/SUB_ACCOUNT_UID/unpause` (sin cuerpo) elimina el bloqueo, lo que permite que el envío de mensajes y las respuestas de la IA se reanuden de inmediato.

Información útil:

- **Es el mismo estado que el interruptor de bloqueo estricto (Hard blocked) del panel de control** ([Bloqueo / Pausa de una subcuenta](sub-accounts.md#blocking-pausing-a-sub-account)): un cliente pausado a través de la API aparece como bloqueado en el panel de control y viceversa, y reanudar la cuenta elimina un bloqueo realizado desde cualquier lado. El estado actual se puede leer desde el campo `agency_block` en `GET /v1/subaccounts` (`level` de `"none"`, `"soft_blocked"` o `"hard_blocked"`).
- **Ambas llamadas son idempotentes.** Pausar a un cliente que ya está pausado solo actualiza el mensaje, el motivo y la marca de tiempo; reanudar a un cliente activo no cambia nada.
- **No se envía un correo electrónico automático al cliente**: muchas agencias utilizan marca blanca, por lo que informar al cliente queda a su discreción.
- **Su propia facturación de DM Champ no se ve afectada.** Pausar a un cliente solo afecta su relación con él.
- **Los asistentes de IA también pueden hacer esto**: el [servidor MCP](../integrations/connect-ai-clients.md) expone estos puntos finales como las herramientas `pause_subaccount` y `unpause_subaccount`.

***

## Otorgar o deducir créditos directamente

`POST /v1/subaccounts/credits`

Añade o elimina una cantidad exacta de créditos del saldo de una subcuenta: el equivalente en la API al ajuste manual de crédito del panel de control. Este es un cambio de saldo único, distinto de las configuraciones recurrentes `monthly_credits`, `roll_over_to_next_month`, `rollover_cap_months` y `rollover_expiry_days` en [`PUT /v1/subaccounts/{subAccountUid}/limits`](#set-an-exact-team-member-limit-for-a-client).

Este es el único endpoint en esta página que identifica la subcuenta por **correo electrónico** en lugar de `sub_account_id`.

| Campo | Requerido | Descripción |
|---|---|---|
| `email` | Sí | El correo electrónico de la subcuenta, tal como existe bajo tu agencia. |
| `amount` | Sí | Número de créditos distinto de cero. Positivo agrega, negativo deduce. |
| `description` | No | Se muestra junto al ajuste en el historial de créditos del cliente. Por defecto, aparece una línea genérica "Ajustado por la agencia vía API". |

**cURL**

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts/credits" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "email": "client@example.com", "amount": 500, "description": "Q3 bonus credits" }'
```

**Respuesta**

```json
{
  "success": true,
  "data": {
    "email": "client@example.com",
    "previous_balance": 1200,
    "adjustment": 500,
    "new_balance": 1700
  }
}
```

Un `amount` negativo que llevaría el saldo por debajo de cero se rechaza con `400`, indicándole el saldo disponible y lo que intentó deducir. Si el cliente tiene su propia facturación de Stripe (modo de reventa), una cantidad añadida también cuenta como créditos que compró, por lo que sobrevive a su próximo reinicio mensual de la misma manera que lo haría una recarga real; en un cliente asignado estándar, se trata como parte de su asignación recurrente. De cualquier manera, son una adición única, por lo que un límite de transferencia o una caducidad establecida en la cuenta (o su plan) nunca los recorta: solo la asignación recurrente y los créditos del plan están sujetos a ellos.

***

## Leer las conversaciones de una subcuenta

`GET /v1/subaccounts/{subAccountUid}/chats` · `GET /v1/subaccounts/{subAccountUid}/chats/{contactId}/messages`

Le permite crear una vista de supervisión o soporte de las conversaciones de un cliente sin tener que iniciar sesión en su cuenta. Primero, enumere sus contactos con una vista previa del último mensaje y, a continuación, lea el historial completo de mensajes de un contacto.

**Listar contactos**

```bash
curl "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/chats?apiKey=YOUR_AGENCY_API_KEY&pageSize=25"
```

| Parámetro de consulta | Obligatorio | Descripción |
|---|---|---|
| `pageSize` | No | Contactos por página. Predeterminado 25, máximo 50. |
| `lastActivityAt` | No | Cursor de paginación: pase el `lastActivityAt` de la página anterior para continuar. |
| `searchQuery` | No | Filtrar por nombre de contacto o número de teléfono. |

**Respuesta**

```json
{
  "success": true,
  "data": {
    "contacts": [
      {
        "contactId": "contact456",
        "firstName": "Jamie",
        "lastName": "Lee",
        "phoneNumber": "+14155551234",
        "email": "jamie@example.com",
        "channel": "whatsapp",
        "lastActivityAt": "2026-08-30T14:22:00.000Z",
        "lastMessage": { "body": "Thanks, that fixed it!", "direction": "inbound", "timestamp": "2026-08-30T14:22:00.000Z" },
        "isBotActive": true,
        "markChatClosed": false
      }
    ],
    "subAccountName": "Client Co",
    "subAccountEmail": "client@example.com",
    "hasMore": true,
    "lastActivityAt": "2026-08-30T14:22:00.000Z"
  }
}
```

Los contactos se ordenan por actividad más reciente primero. Siga paginando con `lastActivityAt` mientras `hasMore` sea `true`.

**Leer los mensajes de un contacto**

```bash
curl "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/chats/contact456/messages?apiKey=YOUR_AGENCY_API_KEY&pageSize=30"
```

| Parámetro de consulta | Obligatorio | Descripción |
|---|---|---|
| `pageSize` | No | Mensajes por página. Predeterminado 30, máximo 100. |
| `beforeTimestamp` | No | Cursor de paginación: obtenga mensajes anteriores a esta marca de tiempo ISO. |

**Respuesta**

```json
{
  "success": true,
  "data": {
    "messages": [
      {
        "messageId": "msg789",
        "body": "Thanks, that fixed it!",
        "direction": "inbound",
        "timestamp": "2026-08-30T14:22:00.000Z",
        "status": "received",
        "channel": "whatsapp",
        "botReply": false,
        "mediaUrl": null,
        "mediaContentType": null,
        "name": "Jamie Lee",
        "role": null
      }
    ],
    "contactInfo": { "firstName": "Jamie", "lastName": "Lee", "phoneNumber": "+14155551234", "channel": "whatsapp" },
    "hasMore": false,
    "oldestTimestamp": "2026-08-30T14:22:00.000Z"
  }
}
```

Los mensajes se devuelven del más reciente al más antiguo; navegue hacia atrás por el historial con `beforeTimestamp`.

***

## Leer el uso de créditos y el estado de las campañas en toda su cartera

`GET /v1/subaccounts/credit-usage` · `GET /v1/subaccounts/campaign-status`

Dos resúmenes estilo panel sobre todas las subcuentas que gestiona, para crear sus propios informes de agencia en lugar de hacer clic en cada cliente uno por uno.

**Uso de créditos**

```bash
curl "https://api.dmchamp.com/v1/subaccounts/credit-usage?apiKey=YOUR_AGENCY_API_KEY&from=2026-08-01&to=2026-08-31"
```

| Parámetro de consulta | Obligatorio | Descripción |
|---|---|---|
| `from` / `to` | Sí | Rango de fechas ISO. |
| `subAccountId` | No | Omítalo para obtener un resumen de toda la agencia, una fila por subcuenta. Inclúyalo para cambiar al modo de detalle: el resumen de esa subcuenta más sus registros de uso sin procesar y paginados. |
| `limitCount` | No | Solo modo de detalle. Predeterminado 500, máximo 2000. |
| `startAfterTimestamp` | No | Solo modo de detalle: cursor de paginación. |

```json
{
  "success": true,
  "data": {
    "subAccounts": [
      {
        "subAccountId": "abc123def456",
        "subAccountName": "Client Co",
        "subAccountEmail": "client@example.com",
        "totalCreditsUsed": 842,
        "totalCostUsd": 3.15,
        "byReason": { "AI reply": 620, "Chat summary": 80 },
        "topCampaigns": [{ "campaignName": "Inbound Leads", "creditsUsed": 500 }]
      }
    ],
    "totals": { "totalCreditsUsed": 842, "totalCostUsd": 3.15, "totalRecords": 214 },
    "dateRange": { "from": "2026-08-01", "to": "2026-08-31" },
    "hasMore": false,
    "lastTimestamp": null
  }
}
```

Pase `subAccountId` y la misma respuesta también incluirá `records`: cargos individuales con `amount`, `reason`, `campaignName`, `contactName` y `timestamp`. Un cliente que gasta con su propia clave BYOK en lugar de con sus créditos tendrá las cifras de coste/token ocultas (`costsRedacted: true`); eso es telemetría de costes de la plataforma, no algo que deba mostrarse a un revendedor.

**Estado de la campaña**

```bash
curl "https://api.dmchamp.com/v1/subaccounts/campaign-status?apiKey=YOUR_AGENCY_API_KEY&pageSize=20"
```

| Parámetro de consulta | Requerido | Descripción |
|---|---|---|
| `pageSize` | No | Subcuentas por página. Predeterminado 10, máximo 50. |
| `lastDocumentId` | No | Cursor de paginación. |
| `searchQuery` | No | Filtrar por nombre o correo electrónico de la subcuenta. |

```json
{
  "success": true,
  "data": {
    "totalSubAccounts": 34,
    "subAccountsWithIssues": 3,
    "totalLiveCampaigns": 51,
    "totalPausedCampaigns": 6,
    "subAccounts": [
      {
        "userId": "abc123def456",
        "email": "client@example.com",
        "displayName": "Jamie Lee",
        "businessName": "Client Co",
        "totalCampaigns": 2,
        "liveCampaigns": 1,
        "pausedCampaigns": 1,
        "hasIssues": true,
        "issueDetails": ["1 campaign paused"],
        "lastCampaignActivity": "2026-08-29T09:00:00.000Z"
      }
    ],
    "hasMore": true,
    "lastDocumentId": "abc123def456",
    "pageSize": 20
  }
}
```

`hasIssues` / `issueDetails` marca las subcuentas que merecen atención; por ejemplo, una campaña pausada o una a la que no se le ha asignado ningún canal. Utilice esto para crear un panel de control de estado para toda la cartera en lugar de abrir cada cliente para detectar una campaña estancada.

> Para ver la mensajería de series temporales y la actividad de créditos de todos los clientes (una serie lista para gráficos en lugar de una instantánea puntual), consulte `GET /analytics/agency-rollup` en la guía de la API de Analytics.

***

## Entregar una cuenta de cliente que ya esté configurada

`PUT /v1/snapshots/default` · `POST /v1/snapshots/{snapshotId}/apply`

Una [instantánea](snapshots.md) es una plantilla reutilizable: uno o más agentes de IA junto con su base de conocimientos, herramientas y medios, capturados desde su propia cuenta. Dos endpoints la integran en su flujo de aprovisionamiento.

**Automático: cada cliente nuevo la recibe al crearse.** Marque una instantánea como predeterminada una vez y cada cuenta que cree a partir de entonces llegará con ella instalada. Esto cubre las cuentas creadas a través de `POST /v1/subaccounts`, las cuentas que cree en el panel de control y las cuentas creadas automáticamente cuando un cliente paga a través de su enlace de pago.

Primero, busque el id de la instantánea:

```bash
curl "https://api.dmchamp.com/v1/snapshots" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY"
```

Luego, establézcala como predeterminada:

```bash
curl -X PUT "https://api.dmchamp.com/v1/snapshots/default" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "snapshot_id": "SNAPSHOT_ID" }'
```

Esa es toda la integración. Envíe `{"snapshot_id": null}` para desactivarla de nuevo. Puede hacer lo mismo desde el panel de control haciendo clic en la estrella en la página de **Instantáneas**.

Para leer lo que está marcado actualmente (por ejemplo, antes de que un script de aprovisionamiento decida si establecer uno), `GET /v1/snapshots/default` devuelve `{ "success": true, "data": { "default_snapshot_id": "SNAPSHOT_ID" } }` — `null` cuando no hay nada marcado. `GET /v1/snapshots` (utilizado para encontrar el id anterior) devuelve el mismo `default_snapshot_id` junto con la matriz completa `snapshots`, por lo que la mayoría de las integraciones solo necesitan esa llamada. Los campos completos del objeto de instantánea se encuentran en la guía de [Instantáneas](snapshots.md).

**Bajo demanda: instalar en una cuenta.** Útil para la incorporación de un cliente existente o para proporcionar a un cliente una segunda plantilla más adelante.

```bash
curl -X POST "https://api.dmchamp.com/v1/snapshots/SNAPSHOT_ID/apply" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "sub_account_id": "SUB_ACCOUNT_UID" }'
```

Omita `sub_account_id` y se instalará en su propia cuenta de agencia. Al igual que los endpoints `/subaccounts`, estos nombran la cuenta de destino en la ruta o el cuerpo en lugar de a través del parámetro `sub_account_id` ambiental.

Vale la pena saberlo antes de trabajar con esto:

- **Los agentes instalados comienzan en pausa.** Conecte primero los canales del cliente y luego active el agente. Esto es válido tanto para la ruta automática como para la ruta bajo demanda.
- **El aprovisionamiento nunca falla debido a una instantánea.** Si la instalación no puede completarse, la cuenta del cliente se crea y es utilizable de todos modos; simplemente llega vacía y puede aplicar la instantánea después.
- **Los canales, calendarios y conexiones OAuth nunca se copian.** Cada cuenta conecta los suyos propios. Las herramientas que utilizan una clave API simple siguen funcionando de inmediato.
- **Aplicarla dos veces crea una segunda copia.** No se sobrescribe nada.

***

## Crea la plantilla directamente a través de la API

`POST /v1/snapshots` · agentes, funciones personalizadas y medios a través de la API

La sección anterior distribuye una instantánea creada por alguien en el panel de control. La parte de creación también está expuesta, por lo que todo el ciclo —ensamblar la configuración maestra una vez, capturarla y entregarla a cada cliente— puede ejecutarse desde el código.

Las piezas, en el orden en que las utiliza un script de aprovisionamiento:

1. **Crea tus funciones personalizadas.** `POST /v1/custom-functions` crea una; `GET /v1/custom-functions` enumera las que tienes, y `GET`, `PUT` y `DELETE` en `/v1/custom-functions/{customFunctionId}` leen, actualizan y eliminan una. `POST /v1/custom-functions/test` realiza una prueba de ejecución de una definición antes de guardarla.
2. **Crea y configura el agente.** `POST /v1/agents` lo crea, `PUT /v1/agents/{agentId}` lo actualiza, y `PATCH /v1/agents/{agentId}/active` con `{ "active": false }` lo mantiene en pausa mientras trabajas (la misma llamada con `true` lo pone en funcionamiento). `GET /v1/agents` los enumera.
3. **Dale habilidades al agente.** `POST /v1/agents/{agentId}/custom-functions` con `{ "custom_function_id": "..." }` adjunta una función al agente; el `DELETE /v1/agents/{agentId}/custom-functions/{customFunctionId}` correspondiente la desvincula.
4. **Completa la biblioteca de medios.** `POST /v1/agents/{agentId}/media-library` sube un elemento (JSON con `base64Data`, `mimeType`, `title`, `description`); `GET` enumera los elementos del agente, y `PATCH`/`DELETE` en `/{itemId}` actualizan o eliminan uno.
5. **Captúralo como una instantánea.**

```bash
curl -X POST "https://api.dmchamp.com/v1/snapshots" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Master setup v1",
    "agent_ids": ["AGENT_ID"],
    "include_knowledge": true,
    "include_tools": true,
    "include_media": true
  }'
```

A partir de ahí, se aplica la sección anterior: márcala como predeterminada para que cada cliente nuevo nazca con ella, o aplícala bajo demanda. Las tareas de mantenimiento se encuentran junto a esto: `PATCH /v1/snapshots/{snapshotId}` con `{ "name": "..." }` cambia el nombre de una, `DELETE /v1/snapshots/{snapshotId}` elimina una (y le quita la marca de predeterminada si lo era), y `GET /v1/snapshots/apply-targets` enumera todas las cuentas en las que podrías realizar una instalación.

Los endpoints de agente, función personalizada y medios aceptan `sub_account_id`, por lo que las mismas llamadas también pueden mantener un agente directamente dentro de la cuenta de un cliente. Las llamadas de instantánea siempre actúan sobre tu cuenta de agencia: la plantilla reside contigo. Los esquemas completos de solicitud y respuesta para todos estos se encuentran en la [Referencia de la API](../api/reference.md).

***

## Gestiona tus niveles de precios a través de la API

`GET /v1/agency/pricing-tiers` · `POST /v1/agency/pricing-tiers` · `PATCH /v1/agency/pricing-tiers/{tierIndex}` · `DELETE /v1/agency/pricing-tiers/{tierIndex}`

Los planes que vendes en **Modo SaaS → Niveles de precios** se pueden leer y cambiar desde el código, de modo que tu propio panel de administración o script de aprovisionamiento puede añadir un plan, ajustar un precio o proporcionar un enlace de pago sin que nadie tenga que abrir el panel de control. Autentícate con tu clave API de agencia como en cualquier otra llamada de esta página; estos endpoints son de nivel de agencia, por lo que no requieren `sub_account_id`. Cada escritura ejecuta la misma validación y la misma sincronización de producto y precio de Stripe que al guardar en el panel de control, por lo que un plan creado aquí es indistinguible de uno configurado manualmente.

### Lista tus niveles

```bash
curl "https://api.dmchamp.com/v1/agency/pricing-tiers" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY"
```

**Respuesta**

```json
{
  "success": true,
  "data": {
    "tiers": [
      {
        "tierIndex": 0,
        "credits": 1000,
        "price_cents": 2900,
        "currency": "usd",
        "label": "Starter",
        "billing_interval": "month",
        "trial_days": 14,
        "trial_credits": 250,
        "trial_card_required": false,
        "trial_hard_expiry": true,
        "stripe_price_id": "price_1PxAbC…",
        "stripe_product_id": "prod_QxAbC…",
        "checkout_url": "https://app.yourdomain.com/v1/checkout?id=YOUR_AGENCY_UID&tierIndex=0"
      }
    ],
    "count": 1,
    "max_tiers": 20
  }
}
```

Cada nivel devuelve su **`tierIndex`** — su posición en tu lista de Planes, que es cómo lo direccionan las otras tres llamadas — y un **`checkout_url`** listo para compartir, el mismo enlace que te proporciona la pestaña **Pagos**, que ya apunta al [dominio de marca blanca](white-labeling.md) en el que se vende ese plan.

### Añadir un nivel

El cuerpo es un objeto de nivel; se añade al final de tu lista.

```bash
curl -X POST "https://api.dmchamp.com/v1/agency/pricing-tiers" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Starter",
    "credits": 1000,
    "price_cents": 2900,
    "currency": "usd",
    "billing_interval": "month",
    "trial_days": 14,
    "trial_credits": 250,
    "trial_card_required": false,
    "trial_hard_expiry": true,
    "features": ["channels_3", "channel_whatsapp_web", "webhooks"]
  }'
```

La respuesta contiene el nivel creado, incluyendo el `tierIndex` en el que se ubicó y su `checkout_url`.

### Editar un nivel

Envía solo los campos que deseas cambiar; todo lo demás en el plan se deja como estaba.

```bash
curl -X PATCH "https://api.dmchamp.com/v1/agency/pricing-tiers/0" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "price_cents": 3900, "trial_hard_expiry": true }'
```

Un campo que la API no reconoce es rechazado en lugar de ignorado, y el error lo identifica; así, un error tipográfico nunca puede escribir silenciosamente una configuración que parezca activa pero no haga nada. Cambiar el precio, los créditos, la moneda o la frecuencia de facturación crea un nuevo precio en tu Stripe; los clientes que ya se suscribieron permanecen en lo que contrataron.

### Eliminar un nivel

```bash
curl -X DELETE "https://api.dmchamp.com/v1/agency/pricing-tiers/2" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY"
```

La misma regla que en el panel de control: un plan que todavía tiene suscriptores activos no puede ser eliminado. La solicitud es rechazada, indicándote cuántos suscriptores tiene; cancélalos o migralos primero. Una eliminación exitosa responde con tus niveles restantes, ya renumerados.

### Los campos de un nivel

| Campo | Qué es |
|---|---|
| `label` / `description` | El nombre del plan y la línea opcional que se muestra en su página de pago. |
| `credits` | Créditos que obtiene el cliente **por mes** en un plan mensual o anual, y **por periodo de facturación** en uno semanal. |
| `price_cents` | Precio por intervalo de facturación, en la unidad monetaria más pequeña (`2900` = $29.00). En un plan anual, este es el precio de todo el año. |
| `currency` | Código ISO en minúsculas: `usd`, `eur`, `gbp`, etc. |
| `billing_interval` / `billing_interval_count` | `month` (el predeterminado), `year` o `week` con un recuento de 1 a 52 para "cada N semanas". |
| `trial_days` | Duración de la prueba gratuita, de 0 a 90. `0` (u omitirlo) significa que no hay prueba. |
| `trial_credits` | Créditos con los que el cliente comienza la prueba. De forma predeterminada, es el `credits` del plan. |
| `trial_card_required` | `false` permite que el cliente comience la prueba sin ingresar una tarjeta. De forma predeterminada, es `true`. |
| `trial_hard_expiry` | `true` devuelve los créditos de prueba no utilizados a su grupo y bloquea la cuenta del cliente cuando una prueba finaliza sin una actualización. De forma predeterminada, es `false`: consulte [Caducidad estricta después de la prueba](agency-accounts.md#step-3--set-up-pricing-tiers). |
| `rollover_cap_months` | Meses de asignación que los clientes en este plan pueden transferir entre renovaciones: un número del 0 al 120, se permiten fracciones. `0` no transfiere nada; `null` (el predeterminado) significa que no hay límite. Consulte [Limitar lo que se transfiere](sub-accounts.md#capping-what-rolls-over). |
| `rollover_expiry_days` | Días después de los cuales los créditos no utilizados se eliminan en la siguiente renovación: un número entero del 1 al 3650. `null` (el predeterminado) significa que nunca caducan. |
| `features` / `feature_settings` | Lo que obtienen los clientes en este plan: los mismos ID de función que en [Elegir qué tipos de canal puede conectar un cliente](#choose-which-channel-types-a-client-can-connect). |
| `team_seats_limit` | Asientos de equipo que otorga el plan: un número exacto, `0` para ninguno, `-1` para ilimitado. |
| `white_label_config` | En cuál de sus [dominios de marca blanca](white-labeling.md#up-to-three-white-labels) se vende el plan. |

Los campos de prueba solo tienen significado en un plan que tiene una prueba: guarde un nivel con `trial_days: 0` y se eliminarán. Los ID de producto y precio de Stripe del plan se administran por usted y no se pueden configurar manualmente.

Tres cosas que debe tener en cuenta:

- **Los índices de nivel son posiciones, no identificadores permanentes.** Eliminar un plan desplaza todos los planes posteriores una posición, por lo que debe volver a obtener la lista después de cualquier cambio, y volver a copiar los enlaces de pago que haya publicado, exactamente como lo haría después de eliminar un plan en el panel de control.
- **El modo SaaS debe configurarse primero.** Estos puntos finales requieren una cuenta de agencia con marca blanca y una clave de Stripe ya guardada; sin ella, no hay ninguna cuenta de Stripe en la que puedan residir el producto y el precio del plan.
- **El límite es de veinte planes**, igual que en el panel de control. El campo `max_tiers` en la respuesta de la lista le indica el límite actual.

Los esquemas completos de solicitud y respuesta se encuentran en la [Referencia de la API](../api/reference.md), en **Agencia**.

***

## Establezca su precio por crédito a través de la API

`GET /v1/agency/credit-price` · `PATCH /v1/agency/credit-price`

El precio que pagan los clientes por las recargas ad-hoc (**Modo SaaS → Precios por crédito**) también se puede leer y modificar mediante código. Esto está diseñado para casos en los que el precio debe ajustarse automáticamente: una agencia que vende créditos en una moneda pero cobra en otra puede permitir que una tarea programada revise el precio a medida que cambia el tipo de cambio, en lugar de que alguien lo edite manualmente cada semana.

### Leer el precio actual

```bash
curl "https://api.dmchamp.com/v1/agency/credit-price" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY"
```

**Respuesta**

```json
{
  "success": true,
  "data": {
    "price_per_credit_cents": 125,
    "price_per_credit_currency": "brl",
    "note": "USD 0.25 per credit at our reference rate",
    "minimum_cents": 60
  }
}
```

`minimum_cents` es el precio más bajo que permite la plataforma en esa moneda, por lo que una tarea puede verificar un nuevo precio antes de enviarlo. Los tres valores son `null` hasta que se haya establecido un precio.

### Cambiarlo

```bash
curl -X PATCH "https://api.dmchamp.com/v1/agency/credit-price" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "price_per_credit_cents": 130, "currency": "brl" }'
```

Envíe solo lo que desea cambiar. `price_per_credit_cents` es el precio en la unidad monetaria más pequeña (`130` = R$1.30); `currency` es un código ISO en minúsculas; `note` es una línea opcional de hasta 200 caracteres que se muestra a los clientes directamente debajo del precio por crédito en su página de Facturación; es útil para un precio de referencia en otra moneda, como *"USD 0.25 por crédito a nuestra tasa de referencia"*. Envíe `"note": ""` para eliminarlo. La respuesta tiene la misma forma que la lectura anterior, por lo que una tarea puede comparar y omitir la escritura cuando nada ha cambiado.

Se aplican las mismas reglas que en el panel de control: el precio no puede ser inferior al mínimo de la plataforma para esa moneda y la cuenta necesita marca blanca (white labeling). A diferencia de los endpoints de niveles de precios, no se requiere una clave de Stripe para leer o cambiar este valor.

### Asigne a una tarea una clave que no pueda hacer nada más

Poner la clave completa de su agencia en un programador otorga más acceso del que necesita una actualización de precios. En su lugar, cree una **clave con alcance limitado** (scoped key) para el área de **Precio de crédito de agencia**: esa clave puede leer y cambiar el precio por crédito y nada más; no puede tocar subcuentas, planes, créditos ni su conexión con Stripe.

```bash
curl -X POST "https://api.dmchamp.com/v1/api-keys" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "label": "FX price updater", "scopes": { "read_only": false, "tags": ["Agency Credit Price"] } }'
```

La respuesta contiene la nueva clave en `api_key` **una sola vez**; nunca se vuelve a mostrar, así que guárdela de inmediato. Establezca `"read_only": true` para una clave que solo necesite leer el precio, y añada `"expires_at"` (una fecha ISO) si desea que deje de funcionar por sí sola. Solo la clave del propietario de la cuenta puede crear claves con alcance limitado; enumérelas o revóquelas con `GET /v1/api-keys` y `DELETE /v1/api-keys/{id}`.

***

## Permita que una subcuenta lea sus precios

`GET /v1/subaccounts/agency-pricing`

Todos los demás endpoints de esta página se llaman con **su clave de agencia**, apuntando opcionalmente a un cliente a través de `sub_account_id`. Este es lo opuesto: se llama con la **propia clave de API de la subcuenta**, sin `sub_account_id`, de modo que la propia página de recarga de un cliente (o una integración que usted cree para ellos) pueda mostrar lo que usted les cobra sin ver nunca su cuenta de agencia.

```bash
curl "https://api.dmchamp.com/v1/subaccounts/agency-pricing" \
  -H "X-API-Key: THE_SUB_ACCOUNTS_OWN_API_KEY"
```

**Respuesta**

```json
{
  "success": true,
  "data": {
    "tiers": [{ "credits": 1000, "price_cents": 2900, "currency": "usd" }],
    "price_per_credit_cents": 125,
    "price_per_credit_currency": "brl",
    "price_per_credit_note": "USD 0.25 per credit at our reference rate",
    "agency_display_name": "Client Co's Growth Partner"
  }
}
```

Esto refleja exactamente lo que [`GET /v1/agency/pricing-tiers`](#list-your-tiers) y [`GET /v1/agency/credit-price`](#read-the-current-price) le devuelven a usted como agencia, menos todo lo que el cliente no necesita ver (ids de Stripe, `max_tiers`, etc.). Solo funciona para una cuenta que sea realmente una subcuenta con una agencia vinculada; llamarlo desde su propia cuenta de agencia devuelve un error de permiso.

***

## Aspectos a tener en cuenta

- **Utilice su clave de agencia.** Autentique cada llamada con la clave de API de su cuenta de agencia, no la de la subcuenta. El parámetro `sub_account_id` es el que redirige la acción.
- **Los créditos provienen de la subcuenta.** Las compras y los cargos recurrentes afectan al saldo de crédito de la subcuenta objetivo, no al suyo.
- **Un `404` significa "no es su subcuenta".** Verifique dos veces el id y que la cuenta sea una que usted gestione.
- **El parámetro es opcional en todos los lugares donde se acepta.** Omítalo y el mismo endpoint actuará sobre su cuenta de agencia, por lo que puede reutilizar una integración para ambos casos.

***

## Relacionado

- [Acceso a la API](../integrations/api-access.md) — autenticación, URL base, errores, límites de tasa.
- [Subcuentas](sub-accounts.md) — listar y gestionar las cuentas a las que puede dirigirse.
- [Recarga automática de subcuentas](sub-account-auto-recharge.md) — otorgar créditos a una subcuenta mediante webhook + API.
- [API de campañas](../api/campaigns.md) — crear, actualizar y copiar campañas, incluida la referencia completa de campos.
- [API de conexión de canales](../api/channels.md) — conectar los canales de un cliente y dirigirlos a una campaña.
- Guía de la API de Analytics (en la sección de API) — el resumen de subcuentas de la agencia y todos los demás endpoints de informes.
- [Instantáneas](snapshots.md) — qué captura una instantánea y cómo crear una en el panel de control.
