
# API pentru agenții

În calitate de agenție, puteți utiliza același REST API pe care îl folosesc clienții dvs., dar direcționând cererile individuale către unul dintre **sub-conturile** gestionate, în loc de propriul cont. Acest lucru vă permite să construiți instrumente care să integreze un client cap-la-cap — creându-i campaniile, antrenându-i AI-ul pe o bază de cunoștințe, importându-i contactele, conectându-i canalele de mesagerie și cumpărând numere de telefon — totul fără a vă conecta manual la fiecare sub-cont.

Această pagină acoperă doar comportamentul specific agențiilor: cum să acționați în numele unui sub-cont cu parametrul `sub_account_id`. Pentru elementele de bază (generarea unei chei, autentificare, URL de bază, formatul erorilor, limite de rată), începeți cu ghidul [Acces API](../integrations/api-access.md). Tot ce este acolo se aplică și aici — vă autentificați cu cheia API a **contului dumneavoastră de agenție**.

::: note
**Notă:** Această pagină este tehnică. Dacă nu sunteți dezvoltator, partajați-o cu persoana care se ocupă de integrarea dumneavoastră.
:::


***

## Cum funcționează „acționarea în numele” cuiva

În mod implicit, fiecare cerere API acționează asupra contului care deține cheia API — contul dumneavoastră de agenție. Pentru a acționa în schimb asupra unui cont de client gestionat, adăugați parametrul opțional `sub_account_id` la cerere, setat la id-ul contului acelui client.

- **Omiteți `sub_account_id`** → cererea acționează asupra propriului cont de agenție.
- **Includeți `sub_account_id`** → cererea acționează asupra acelui sub-cont, dar numai după ce platforma confirmă că sub-contul vă aparține cu adevărat.

Vă autentificați întotdeauna cu cheia API a **contului dumneavoastră de agenție**. Nu aveți nevoie niciodată de cheia proprie a sub-contului și nu gestionați niciodată credențialele sub-contului.

### Unde să îl plasați

- **Endpointuri GET / DELETE** → transmite-l ca parametru de interogare: `?sub_account_id=THE_SUB_ACCOUNT_ID` (alături de `apiKey`, dacă te autentifici prin interogare).
- **Endpointuri POST / PUT / PATCH** → include-l în corpul cererii JSON ca `"sub_account_id": "THE_SUB_ACCOUNT_ID"`.
- **Asistenți AI** → nu este nimic de configurat. [Serverul MCP](../integrations/connect-ai-clients.md) poartă aceeași setare pe instrumentele sale de citire, deci o singură conexiune cu cheia ta de agenție poate raporta despre fiecare client: doar menționează clientul în cererea ta („câte contacte are Bella's Bistro?”). Acțiunile de scriere sunt, de asemenea, disponibile: fiecare endpoint care acceptă `sub_account_id` este expus ca instrument, astfel încât poți crea, modifica și trimite în numele unui client din aceeași conexiune.

### Găsirea id-ului unui sub-cont

`sub_account_id` este identificatorul unic al contului de client. Puteți obține lista subconturilor dumneavoastră și identificatorii acestora din endpoint-urile API **SubAccounts** (consultați ghidul [Sub-Accounts](sub-accounts.md)) sau din pagina **Sub Accounts** din bara laterală.

***

## Proprietatea este întotdeauna verificată

Atunci când transmiteți un `sub_account_id`, platforma verifică dacă acel cont este un sub-cont real **și** dacă aparține agenției dumneavoastră. Doar atunci cererea este procesată.

Dacă id-ul este necunoscut, nu este un sub-cont sau aparține unei alte agenții, cererea eșuează cu un răspuns **`404`**:

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

> **De ce 404 și nu 403?** Un răspuns de tip „interzis” (forbidden) i-ar spune unui străin că ID-ul există, dar nu îi aparține. Returnarea aceluiași `404` pentru „nu există” și „nu este al tău” înseamnă că endpoint-ul nu poate fi utilizat pentru a descoperi ce ID-uri de cont aparțin altor agenții. Tratați un `404` aici ca pe „acesta nu este un sub-cont pe care îl gestionați”.

***

## Unde este acceptat `sub_account_id`

`sub_account_id` este acceptat practic pe fiecare endpoint de **resursă** — orice apel care creează, citește, actualizează sau șterge datele proprii ale unui cont. În practică, puteți configura și rula întreaga setare a unui sub-cont cu cheia dvs. de agenție:

- **Configurare AI** — campanii, agenți, întrebări frecvente (FAQ), surse pentru baza de cunoștințe (scanare site **și** încărcare documente), grupuri pentru baza de cunoștințe, difuzări, funcții personalizate, servere MCP
- **Contacte și CRM** — contacte (inclusiv import), liste, etichete, sarcini, tranzacții, programări, evenimente
- **Canale și numere** — conectare WhatsApp / WhatsApp Web / Telegram / Instagram & Messenger / LINE, căutare / achiziționare / gestionare numere de telefon, șabloane WhatsApp, rutare canale
- **Mesagerie și conținut** — trimitere mesaje, sesiuni de chat, exporturi de chat, rezumate zilnice
- **Setări și integrări** — webhook-uri, configurare widget de chat, configurare white-label, SMS BYOK și alte setări de cont, analiză

Pentru fiecare dintre acestea, parametrul este **opțional** — omiteți-l și apelul va acționa asupra propriului cont de agenție, astfel încât o singură integrare servește ambelor scopuri. Creditele și utilizarea provin întotdeauna din contul vizat: taxele pentru campaniile, mesajele, etichetele și numerele unui sub-cont sunt scăzute din soldul **sub-contului respectiv**.

### Unde NU se aplică

Câteva endpoint-uri sunt la nivel de agenție sau se adresează contului propriu și ignoră `sub_account_id`:

- **Gestionarea sub-conturilor propriu-zise** — punctele finale (endpoints) SubAccounts (creare / listare / actualizare a unui sub-cont) și punctul final pentru limita de cheltuieli BYOK denumesc deja sub-contul în propria cale URL. [Punctele finale pentru prețuri și politici](#set-per-client-ai-pricing-and-policy) și [punctele finale pentru monitorizarea chat-ului](#read-a-sub-accounts-conversations) urmează același tipar.
- **Copierea unui Agent între conturi** — `POST /v1/subaccounts/agents/copy` denumește ambele conturi, luând destinația ca `targetUserId`. Consultați [exemplul de lucru](#worked-example-ship-a-template-agent-into-every-new-client) de mai jos. (Vechiul `POST /v1/subaccounts/campaigns/copy` funcționează în același mod, dar este depreciat împreună cu restul [API-ului Campaigns](../api/campaigns.md).)
- **Ajustarea creditelor și cele două centralizări la nivel de agenție** — [`POST /v1/subaccounts/credits`](#grant-or-deduct-credits-directly) identifică sub-contul prin `email` în schimb; [`GET /v1/subaccounts/credit-usage`](#read-credit-usage-and-campaign-health-across-your-book) și `GET /v1/subaccounts/campaign-status` raportează despre fiecare sub-cont simultan, deci nu există un singur cont de vizat.
- **Contul propriei agenții** — gestionarea cheilor API, raportarea utilizării agenției, gestionarea echipei și [nivelurile de preț](#manage-your-pricing-tiers-over-the-api) acționează întotdeauna asupra contului agenției dumneavoastră.
- **Webhook-uri pentru mesaje primite** — punctele finale în care sistemele externe postează *în* sunt legate de contul ale cărui credențiale le-au configurat, deci nu există nimic de redirecționat.

> Lista mereu actualizată, lizibilă automat, cu parametrii acceptați de fiecare endpoint se află în referința API din tabloul de bord (**Settings → Integrations → API Key**) și în specificația OpenAPI la `GET /v1/docs/openapi.yaml`. Lansăm frecvent modificări ale API-ului — tratați-le pe acelea ca fiind sursa de adevăr.

::: master-only
<figure><img src="../.gitbook/assets/v2-api-access-key-section.png" alt="Pagina de setări a cheii API cu cheia mascată și controlul de regenerare"><figcaption><p>Setări → Integrări → Cheie API — cheia agenției dumneavoastră se află aici, alături de linkul către referința completă a API-ului.</p></figcaption></figure>
:::

***

## Exemplu practic: conectarea Instagram și Messenger pentru un sub-cont

Conectarea Instagram și Messenger este un flux bazat pe browser. Îl inițiați prin API, transmiteți clientului URL-ul de consimțământ returnat (sau îl deschideți pentru el), așteptați ca acesta să autorizeze în browserul său, apoi alegeți ce pagină să conectați — totul în timp ce vizați sub-contul acestuia cu `sub_account_id`.

### Pasul 1 — Inițierea conexiunii

Apelați endpoint-ul de conectare cu `sub_account_id` al clientului în body. Nu sunt trimise credențiale aici; platforma returnează un URL de consimțământ pe care clientul trebuie să îl deschidă într-un browser, plus un token de corelare de unică folosință.

**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
```

**Răspuns:**

```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"
}
```

Trimiteți clientul la `oauth_url` într-un browser pentru autorizare. `state_token` corelează această încercare și este un secret cu durată scurtă de viață — nu îl înregistrați în log-uri. Încercarea expiră la `expires_at`; dacă expiră, începeți din nou.

### Pasul 2 — Interogare (polling) până la încărcarea paginilor

După ce clientul autorizează, interogați endpoint-ul de stare (cu același `sub_account_id`, de data aceasta ca parametru de interogare) până când apar paginile care pot fi conectate.

**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"]
```

**Răspuns:**

```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
}
```

Câmpul `status` trece prin `pending` → `token_received` → `pages_loaded` → `connected`. Așteptați `pages_loaded` înainte de a selecta o pagină. Două stări de eroare terminale pot apărea, de asemenea, în loc de progres: `failed` și `expired` (clientul a refuzat consimțământul sau fereastra de ~30 de minute a jetonului de stare a expirat) — un câmp `reason` este inclus atunci când apare oricare dintre acestea. Opriți interogarea și reporniți de la Pasul 1 dacă vedeți una dintre ele; nu așteptați `pending` la nesfârșit. Jetoanele de acces la pagină nu sunt returnate niciodată.

### Pasul 3 — Selectați pagina de conectat

Alegeți unul dintre ID-urile de pagină de la Pasul 2 și selectați-l. Selectarea unei pagini conectează atât Instagram, cât și Messenger pentru acea pagină. Includeți din nou `sub_account_id` în corp.

**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()
```

**Răspuns:**

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

Asta este tot — Instagram și Messenger sunt acum conectate la sub-contul clientului. Ați furnizat doar `page_id`; acreditarea subiacentă este rezolvată pe server și nu trece niciodată prin integrarea dumneavoastră.

***

## Exemplu de lucru: cumpărarea unui număr pentru un sub-cont

Achiziționarea unui număr funcționează în același mod: căutați cu `sub_account_id` în interogare, apoi achiziționați-l folosindu-l în corp. Creditele sunt deduse din soldul **sub-contului**, iar numărul este alocat sub-contului.

**Căutare (cURL):**

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

**Achiziție (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();
```

**Achiziție (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()
```

**Răspuns:**

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

Numărul este furnizat în starea `PURCHASED`, iar înregistrarea expeditorului WhatsApp continuă în fundal. Interogați `GET /v1/phone-numbers/{phoneNumber}/status?sub_account_id=abc123def456` până când starea ajunge la `ONLINE` înainte de a trimite.

***

## Exemplu de lucru: livrarea unui Agent șablon către fiecare client nou

Tiparul obișnuit al agenției este să păstreze un Agent principal în contul agenției, configurat exact așa cum doriți să înceapă fiecare client, și să creeze o copie a acestuia în fiecare sub-cont nou în momentul provizionării. Acestea sunt trei apeluri și nu este nevoie de nicio repetiție ulterior: copia își păstrează setările până când le modificați.

### Pasul 1 — Copierea Agentului

`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
  }'
```

Răspunsul conține ID-ul noului Agent la `data.agent_id`. Întrebările frecvente (FAQ), baza de cunoștințe și biblioteca media sunt incluse; șabloanele WhatsApp, postările sociale conectate și contactele contului sursă sunt omise în mod deliberat. Lista completă a câmpurilor se află în [API-ul AI Agents](../api/agents.md#copy-an-agent-into-a-sub-account-agencies).

Rețineți că acest punct final utilizează `targetUserId` în loc de `sub_account_id` — denumește ambele conturi. Cele două apeluri de mai jos utilizează parametrul normal `sub_account_id`.

### Pasul 2 — Activarea acestuia

Copia ajunge întotdeauna în stare suspendată, deci nu poate trimite mesaje nimănui până când nu decideți altfel. Acesta este, de asemenea, momentul pentru a fixa nivelul AI pe care doriți să îl aibă clientul; acesta rămâne setat, deci nu este nevoie să îl reaplicați conform unui program.

```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" }'
```

Pentru a împiedica clientul să modifice nivelul ulterior, [blocați nivelurile permise](#set-per-client-ai-pricing-and-policy) pe sub-cont în loc să retrimiteți valoarea.

### Pasul 3 — Direcționarea canalelor clientului către aceasta

Copia ajunge, de asemenea, fără nicio rutare, deci nimic nu ajunge la ea până când nu o setați ca răspunzător pe canalele pe care clientul le-a conectat. Un apel per 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" }'
```

De aici, un prim mesaj de la un contact necunoscut pe acel canal este preluat automat de Agentul copiat. Consultați [Direcționarea unui canal către un Agent](../api/entry-points.md#point-a-channel-at-an-agent) pentru celelalte canale și rutarea per număr.

> **Setați fusul orar al clientului atunci când creați contul secundar.** Transmiteți `time_zone_id` pe `POST /v1/subaccounts`. Orele active ale campaniei sunt evaluate în fusul orar propriu al contului secundar, astfel încât un client creat fără unul va avea programul citit în raport cu UTC — ceea ce modifică discret momentele în care asistentului îi este permis să răspundă.

***

## Omiteți expertul de configurare pentru un client pe care îl configurați singur

`POST /v1/subaccounts`

În mod implicit, prima dată când proprietarul unui nou sub-cont se conectează, acesta este ghidat prin Expertul de configurare. Pentru clienții pentru care faceți totul — unde construiți campania și conectați canalele înainte ca clientul să se conecteze vreodată — transmiteți `guided_onboarding: false` atunci când creați contul. Aceștia vor ajunge direct pe tabloul de bord, iar intrarea **Expert de configurare** va fi ascunsă din bara lor 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ți câmpul (sau trimiteți `true`) și expertul se va comporta exact ca întotdeauna, deci integrările existente nu necesită nicio modificare. Pentru a reda expertul unui client mai târziu, afișați din nou elementul `guided_onboarding` cu `PUT /v1/subaccounts/{subAccountUid}/menu-visibility` (mai jos) — vizibilitatea meniului controlează dacă expertul poate fi accesat, `guided_onboarding` controlează doar redirecționarea la prima autentificare.

***

## Dezactivați Sarcinile, Rezumatele zilnice sau Biblioteca media pentru un client

`POST /v1/subaccounts`

Aceste trei funcții sunt activate pentru fiecare client nou, cu excepția cazului în care specificați altfel, și se comportă diferit față de orice altă funcție din acest ghid: ele sunt de tip **opt-out** (renunțare), nu opt-in (înscriere). Excluderea lor din `features` nu este suficientă de la sine, deoarece lista `features` a unei integrări mai vechi pur și simplu nu le menționa — nu putem face distincția între „agenția a dezactivat acest lucru” și „această listă a fost scrisă înainte ca opțiunea să existe”.

Așadar, specificați acest lucru direct cu `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
    }
  }'
```

Fiecare cheie este opțională; tot ceea ce omiteți rămâne activat. Cu `tasks: false`, AI-ul nu mai creează sarcini pentru acel client și nu se mai trimit e-mailuri de tip „Sarcină nouă creată”; cu `daily_summaries: false`, rezumatul nocturn nu mai este generat sau trimis prin e-mail.

`feature_settings` este singurul lucru care dezactivează aceste trei funcții la creare. Excluderea lor din `features` nu are niciun efect de la sine, indiferent cum arată restul listei — acest lucru este deliberat, astfel încât o integrare mai veche să nu piardă silențios toate cele trei funcții.

Pentru a modifica oricare dintre acestea ulterior, trimiteți lista completă `features` către `PUT /v1/subaccounts/{subAccountUid}/features` — acolo, prezența în listă activează o funcție, iar absența o dezactivează.

***

## Conectați automat clienții în subcontul lor (SSO)

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

Un singur apel cu cheia API a agenției dvs. returnează un URL gata de utilizare care conectează clientul direct în propriul său subcont — fără ecran de autentificare, fără pas de parolă, fără nimic de construit suplimentar. Deschideți-l într-o filă nouă, printr-o redirecționare sau într-un iframe în cadrul propriului produs.

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `redirect` | Nu | Pagina din aplicație pe care doriți să ajungă clientul, de exemplu `"/chats"` sau `"/agents"`. Returnat ca `deep_link_url` în răspuns. |
| `app_base_url` | Nu | Gazda tabloului de bord pentru link. Implicit este domeniul aplicației dvs. white-label (sau domeniul platformei, dacă nu aveți unul). Trebuie să fie `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" }'
```

**Răspuns**

```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"
}
```

Cum să îl utilizați eficient:

- **O singură etapă.** Deschiderea `url` autentifică clientul și îl direcționează direct către pagina `redirect` a tabloului de bord — fără ecran de autentificare, fără pagină intermediară. `deep_link_url` indică aceeași destinație, pentru integratorii care preferă să navigheze explicit într-un cadru după autentificare; odată ce sesiunea există, orice cale a tabloului de bord funcționează în acel context de browser.
- **Generare la cerere, deschidere imediată.** Linkul conține o credențială de autentificare și expiră după aproximativ o oră. Solicitați-l pe partea de server în momentul în care clientul dă clic și nu îl stocați și nu îl trimiteți niciodată prin e-mail.
- Tokenul de autentificare circulă în fragmentul URL (`#…`), pe care browserele nu îl trimit niciodată către servere, și este eliminat din bara de adrese în momentul în care este consumat.
- **Doar propriile sub-conturi.** Endpoint-ul refuză orice cont care nu aparține agenției dumneavoastră.
- Un link expirat afișează o eroare clară cu o cale de reîncercare — generați unul nou.

***

## Ascundeți elementele de navigare dintr-un subcont

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

Controlează ce elemente din bara laterală și din setări vede un subcont — util atunci când încorporați tabloul de bord și doriți doar suprafețele pe care produsul dvs. nu le acoperă deja. Orice element care nu este listat rămâne vizibil; trimiteți `null` ca întreaga valoare `menuVisibility` pentru a reseta totul la vizibil. Ascunderea unui element ascunde intrarea din meniu — asociați acest lucru cu funcționalitățile pe care le acordați subcontului pentru restricționare strictă.

**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 }
    }
  }'
```

**Răspuns**

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

`side_nav` acceptă aceste 13 chei, care corespund numelor elementelor din bara laterală: `Dashboard`, `DailySummaries`, `Chats`, `Contacts`, `Deals`, `Tasks`, `Automations`, `Campaigns`, `Appointments`, `Settings`, `Help`, `CreditsCounter` (soldul de credit afișat în bara laterală) și `guided_onboarding` (Expertul de configurare). Alte trei chei — `AiInsights`, `Sub Accounts` și `Agency Reselling` — sunt acceptate, dar nu fac nimic: acestea s-au aplicat doar vechiului tablou de bord clasic, retras între timp, așa că setarea lor nu are niciun efect asupra subconturilor tale. Cheile lipsă înseamnă vizibil; atunci când te conectezi singur la subcont, elementele ascunse sunt afișate temporar, astfel încât să poți oricând să revii la setările anterioare.

Ascunderea unei pagini din meniu nu oferă niciodată acces la aceasta. `Automations` necesită funcția `automations` acordată sub-contului — setați cheia la `true` fără aceasta și pagina tot nu va apărea. `Tasks` și `DailySummaries` funcționează invers: ele sunt activate pentru fiecare client, cu excepția cazului în care le dezactivați (consultați [Dezactivați Sarcinile, Rezumatele zilnice sau Biblioteca media pentru un client](#turn-tasks-daily-summaries-or-the-media-library-off-for-a-client)).

***

## Alegeți ce tipuri de canale poate conecta un client

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

Comutatoarele pentru **Tipuri de canale** pe care le vedeți la un nivel de abonament sunt ID-uri de funcționalitate obișnuite, așa că le puteți seta per client din API în loc de tabloul de bord. Acesta este unul dintre punctele finale care denumește sub-contul în propria sa adresă URL, deci nu necesită `sub_account_id`.

| ID Funcționalitate | Canal |
|---|---|
| `channel_chat_widget` | Widget de chat pentru site-ul web |
| `channel_whatsapp_api` | API WhatsApp Business |
| `channel_whatsapp_web` | WhatsApp Web (număr conectat prin QR) |
| `channel_instagram` | Instagram |
| `channel_messenger` | Facebook Messenger |
| `channel_telegram` | Telegram |
| `channel_line` | LINE |
| `channel_viber` | Viber |
| `channel_email` | Căsuță poștală e-mail |
| `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"
    ]
  }'
```

Trei aspecte de reținut:

- **Apelul înlocuiește întreaga listă de funcționalități.** Trimiteți fiecare funcționalitate pe care clientul ar trebui să o păstreze, nu doar pe cele pe care le modificați. Aceleași ID-uri funcționează ca `features` pe `POST /v1/subaccounts` atunci când creați contul.
- **Tipurile de canale și numărul de canale sunt restricții separate și ambele se aplică.** `channels_1` / `channels_3` / `channels_unlimited` controlează *câte* conexiuni sunt permise; ID-urile `channel_*` controlează *ce tipuri*. Exemplul de mai sus înseamnă „până la 3 conexiuni și doar Widget de chat, WhatsApp Web sau Instagram”.
- **Trimiterea a zero ID-uri `channel_*` înseamnă nicio restricție de canal.** Acesta este comportamentul original, motiv pentru care clienții existenți nu au fost afectați când s-a lansat această funcție. Trimiteți unul sau mai multe și tot restul va apărea ca blocat pe pagina de Canale a clientului, cu o notă de actualizare în loc de un buton de Conectare. Canalele pe care clientul le-a conectat deja vor continua să funcționeze.

> Setarea listei de canale pe un **nivel de abonament**, astfel încât fiecare client care achiziționează acel nivel să o moștenească, se face în tabloul de bord, în setările planului de agenție. Acest punct final o setează pentru un anumit sub-cont.

***

## Setați o limită exactă de membri ai echipei pentru un client

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

Funcționalitățile `team_seats_*` oferă doar trepte predefinite (3 / 5 / 10 / nelimitat). Pentru a oferi unui client un număr **exact** de locuri în echipă — 2, 7, 15, orice număr — setați `usage_limits.team_seats_limit` în schimb. Aceasta prevalează asupra setărilor predefinite, iar platforma o impune la fiecare invitație, adăugare directă și acceptare a invitației: odată ce limita este atinsă, invitațiile ulterioare sunt refuzate la nivel de server.

- Un număr întreg pozitiv reprezintă limita exactă.
- `0` înseamnă că membrii echipei **nu sunt incluși** — clientul nu poate invita pe nimeni.
- `-1` înseamnă nelimitat.
- `null` elimină limita personalizată și revine la oricare setare predefinită `team_seats_*` se află în lista de funcționalități.

Reducerea limitei nu elimină niciodată membrii existenți ai echipei; doar împiedică adăugarea unora noi.

```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 }
  }'
```

De asemenea, îl poți seta în momentul creării: `POST /v1/subaccounts` acceptă `usage_limits.team_seats_limit` cu aceeași semantică. Pentru a citi valoarea curentă, preia sub-contul cu `GET /v1/subaccounts?email=...` și uită-te la `usage_limits.team_seats_limit` (absent/`null` = setările implicite decid). Același endpoint actualizează și `credits`, `monthly_credits`, `roll_over_to_next_month`, `rollover_cap_months`, `rollover_expiry_days` și `byok_monthly_limit_usd` — trimite doar cheile pe care dorești să le modifici.

**Cum interacționează acest lucru cu limitele de locuri ale planului SaaS.** Planurile tale SaaS pot avea propria alocare de locuri (setată în editorul de plan — vezi [Locuri de echipă într-un plan](agency-accounts.md#step-3--set-up-pricing-tiers)), care este aplicată automat atunci când un client se abonează. O limită pe care o setezi prin acest endpoint contează ca o alocare **manuală**: achiziționarea unui plan o înlocuiește cu propria alocare de locuri a planului (acea achiziție este o alegere explicită a planului), dar **reînnoirile** lunare nesupravegheate **nu suprascriu niciodată o limită manuală** — astfel, o excepție unică pe care o acorzi unui client supraviețuiește ciclului său de facturare. Ștergerea limitei manuale cu `null` redă controlul câmpului către plan la următoarea reînnoire.

**Limitează ceea ce un client păstrează între reînnoiri.** Încă două chei `usage_limits` se află lângă `roll_over_to_next_month`. Ambele sunt acceptate și de `POST /v1/subaccounts` în momentul creării, iar `null` le șterge pe oricare dintre ele.

| Cheie | Ce face |
|---|---|
| `rollover_cap_months` | Numărul de luni de alocație pe care clientul le poate păstra. Un număr de la 0 la 120, fracțiile sunt permise (`0.5` = o jumătate de lună). La fiecare reînnoire, soldul neutilizat este redus la cel mult acest număr de ori alocația pe care o oferă acea reînnoire, înainte de a fi adăugate noile credite; `0` nu reportează nimic. |
| `rollover_expiry_days` | Un număr întreg de zile, de la 1 la 3650. Creditele rămase neutilizate atât de mult timp sunt eliminate la prima reînnoire după ce ating acea vechime. Consumul se scade întotdeauna mai întâi din cele mai vechi credite, astfel încât un client care își consumă alocația în fiecare lună nu pierde niciodată nimic. |

Dacă sunt lăsate nesetate, ambele revin la planul clientului; o valoare trimisă aici prevalează asupra celei din plan. Doar creditele recurente (alocația lunară și creditele planului) sunt supuse acestora: suplimentările, reîncărcările automate și adăugările unice nu sunt niciodată limitate sau expirate. Fiecare reducere este scrisă în istoricul de credite al clientului ca o **Ajustare de Credit pentru Limita de Reportare** sau o **Ajustare de Credit pentru Credite Expirate** și nu contează niciodată ca utilizare. Echivalentele la nivel de plan sunt `rollover_cap_months` și `rollover_expiry_days` pe un nivel de preț — vezi [Câmpurile de pe un nivel](#the-fields-on-a-tier) și [Limitarea a ceea ce se reportează](sub-accounts.md#capping-what-rolls-over).

***

## Setează prețurile și politica AI per client

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

Încă opt comutatoare per-client, alături de `/limits`, `/features` și `/menu-visibility` de mai sus. Fiecare preia uid-ul sub-contului în URL (fără `sub_account_id` parametru de corp/interogare — ținta este deja numită în cale) și este limitat în același mod: cheia agenției tale, iar sub-contul trebuie să aparțină agenției tale.

**Ce modele AI poate folosi un client**

```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 }` înscrie clientul în (sau îl exclude din) nivelul Max AI — infrastructura noastră la prețul de listă al platformei. Activarea acestei opțiuni pentru un client BYOK schimbă costul său AI din „gratuit pe propria cheie” în „taxat din fondul meu de credite”, deci este o decizie deliberată per client, mai degrabă decât o setare implicită la nivel de agenție.

Pentru a restricționa CE niveluri pot alege campaniile și agenții unui client (în loc de a limita doar Max), folosește `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` este o matrice extrasă din `standard`, `economy`, `max`, `mini` — aceasta ÎNLOCUIEȘTE lista permisă a clientului. Trimite `null` (sau `[]`) pentru a șterge restricția și a-i permite să aleagă orice nivel. Acest lucru este important deoarece un sub-cont care își alege propriul nivel AI cheltuiește din **fondul tău** de credite, deci este pârghia pentru a stabili ce modele poate folosi un client revânzător pe factura ta.

**Un răspuns de așteptare în timp ce clientul nu mai are credite**

```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." }'
```

Când soldul clientului (sau fondul tău) este gol, AI-ul nu poate răspunde și contactul nu aude nimic. Cu `enabled: true`, fiecare contact care scrie în timpul indisponibilității primește `message` o dată (maxim 500 de caractere, trimis ca atare pe fiecare canal), iar AI-ul răspunde la acele conversații în mod real odată ce creditele sunt din nou disponibile. `enabled: false` păstrează textul salvat pentru mai târziu; `enabled: false` fără `message` elimină setarea. Același comutator ca **Răspuns de așteptare când nu mai sunt credite** în fereastra de editare a sub-contului — vezi [Un răspuns de așteptare în timp ce un client nu mai are credite](sub-accounts.md#a-holding-reply-while-a-client-is-out-of-credits).

**Ce plătește un client per acțiune AI și adaosul pentru taxa WhatsApp**

Două moduri de a seta tariful pentru clienți, de la cel mai simplu la cel mai 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` este prețul în credite pe care soldul PROPRIU al sub-contului îl consumă per acțiune AI de model Max — adaosul tău pentru client peste ceea ce plătește efectiv fondul tău. `null` șterge suprascrierea revenind la prețul de listă al platformei. Tariful trebuie să fie cel puțin cât costă o acțiune Max pentru propriul tău fond (astfel încât să nu poți taxa niciodată un client sub costul tău) și nu mai mult de 10 credite; o cerere în afara acestui interval este respinsă cu pragul calculat în mesajul de eroare.

Pentru prețuri per tip de acțiune în loc de o rată fixă Max, folosește `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` este o ÎMBINARE cu harta existentă a clientului — o cheie pe care nu o menționezi este lăsată așa cum a fost, iar `null` resetează acea cheie la valoarea implicită. Cheile recunoscute:

| Cheie | Prețuri |
|---|---|
| `AI_MESSAGE` | Un răspuns AI |
| `AI_TOOL_USE` | Un apel de instrument AI |
| `EVALUATION_CALL` | O trecere de evaluare a chat-ului |
| `INTERRUPTION_HANDLING` | Gestionarea unei întreruperi în timpul răspunsului |
| `CONTACT_TAG` | O etichetă de contact atribuită de AI |
| `CHAT_SUMMARY` | Un rezumat al chat-ului |
| `wa_carrier_multiplier` | Un multiplicator de adaos aplicat fiecărei taxe WhatsApp non-AI pe care o plătește clientul: chirie lunară pentru număr, taxe de livrare pe bandă gestionată și costuri de transmitere a șabloanelor Meta/Twilio. |

Ratele per acțiune trebuie să fie un număr mai mare de 0 și până la 10; `wa_carrier_multiplier` trebuie să fie cel puțin `1` (fără reducere sub prețul de cost) și până la 10. Trimiterea unei chei nerecunoscute sau a unei valori în afara intervalului respinge ÎNTREAGA cerere și numește fiecare cheie problematică, astfel încât o greșeală de scriere nu poate salva niciodată în mod silențios un preț care nu este de fapt aplicat.

Dacă ești membru [Champions Circle](https://skool.com/dm-champions), `insider-rate` transmite rata ta de reducere de 20% pentru Max/Lead Finder către un singur client, în loc să o aplice la nivelul întregii agenții:

```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 }'
```

Activarea acesteia necesită ca propriul tău cont de agenție să dețină efectiv un abonament Circle; dezactivarea nu necesită niciodată acest lucru, astfel încât un membru al cărui abonament a expirat poate oricând să revină la setările anterioare pentru un client.

**Blochează secțiuni din manualul de utilizare (playbook) al unui client**

```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` este o matrice extrasă din `instructions`, `goal`, `rules`, `personality`, `conclude_unless` — aceasta ÎNLOCUIEȘTE lista blocată a clientului. O secțiune blocată este respinsă la nivel de server dacă SUB-CONTUL încearcă să o modifice (direct sau prin cheia API), în timp ce tu (prin `sub_account_id`) și vizualizarea de administrator a tabloului de bord al clientului puteți edita în continuare orice. Trimite `null` (sau `[]`) pentru a debloca totul. Util pentru clienții pentru care prestezi servicii complete, unde tu deții manualul de utilizare și ești evaluat în funcție de rezultat.

**Setează preferințele de notificare ale unui client în numele acestuia**

```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` înlocuiește întregul set de preferințe de notificare al clientului (nu este o îmbinare per cheie — trimite fiecare categorie pe care dorești să o păstrezi, respectând modul în care pagina de Setări a sub-contului salvează datele). Fiecare categorie din `settings` acceptă `enabled` (boolean) și până la trei `channels` din `email`, `in_app`, `webhook`. Trimite `null` pentru a reseta la valorile implicite ale platformei.

Toate cele șapte endpoint-uri răspund `{ "success": true, "data": { "subAccountUid": "...", ...the field(s) you set... } }` și sunt înregistrate în jurnalul de audit cu valoarea înainte/după. Erori comune: `403` dacă contul tău nu este de tip Agenție/Dev sau sub-contul nu este gestionat de tine, `400` dacă nu este un sub-cont de agenție sau o valoare este în afara intervalului.

***

## Întrerupeți un client care și-a suspendat abonamentul

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

Atunci când un client își suspendă abonamentul la serviciile dumneavoastră, întrerupeți contul acestuia în loc să îl ștergeți: tot ceea ce trimite se oprește imediat — mesajele de ieșire, difuzările, răspunsurile AI pe toate canalele — iar când se conectează, aceștia vor vedea un ecran complet de blocare **Cont întrerupt** (cu mesajul dumneavoastră opțional) în locul aplicației. Nimic nu este șters sau deconectat: agenții, campaniile, canalele conectate, contactele și istoricul chat-ului rămân exact așa cum sunt, deci reluarea activității readuce clientul exact în punctul în care a rămas — fără a fi nevoie de o reconfigurare.

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `message` | Nu | Afișat clientului pe ecranul de blocare. Lăsați necompletat pentru textul implicit. |
| `reason` | Nu | Notă internă a agenției stocată odată cu întreruperea și în jurnalul de audit — nu este afișată niciodată clientului. |

**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" }'
```

**Răspuns**

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

Când clientul revine, `POST /v1/subaccounts/SUB_ACCOUNT_UID/unpause` (fără corp) elimină blocarea — trimiterea mesajelor și răspunsurile AI se reiau imediat.

Bine de știut:

- **Este aceeași stare ca și comutatorul de blocare totală din tabloul de bord** ([Blocarea / Întreruperea unui sub-cont](sub-accounts.md#blocking-pausing-a-sub-account)) — un client întrerupt prin API apare ca blocat în tabloul de bord și invers, iar reluarea activității elimină o blocare plasată din oricare parte. Starea curentă poate fi citită din câmpul `agency_block` de pe `GET /v1/subaccounts` (`level` din `"none"`, `"soft_blocked"` sau `"hard_blocked"`).
- **Ambele apeluri sunt idempotente.** Întreruperea unui client deja întrerupt doar reîmprospătează mesajul, motivul și marcajul temporal; reluarea activității unui client activ nu schimbă nimic.
- **Clientul nu este notificat automat prin e-mail** — multe agenții folosesc white-label, așa că informarea clientului vă revine dumneavoastră.
- **Propria dumneavoastră facturare DM Champ rămâne neatinsă.** Întreruperea unui client afectează doar relația dumneavoastră cu acesta.
- **Asistenții AI pot face și acest lucru**: [serverul MCP](../integrations/connect-ai-clients.md) expune aceste puncte finale ca instrumente `pause_subaccount` și `unpause_subaccount`.

***

## Acordă sau deduce credite direct

`POST /v1/subaccounts/credits`

Adaugă sau elimină o sumă exactă de credite din soldul unui sub-cont — echivalentul API al ajustării manuale de credit din tabloul de bord. Aceasta este o modificare unică a soldului, distinctă de setările recurente `monthly_credits`, `roll_over_to_next_month`, `rollover_cap_months` și `rollover_expiry_days` de pe [`PUT /v1/subaccounts/{subAccountUid}/limits`](#set-an-exact-team-member-limit-for-a-client).

Acesta este singurul endpoint de pe această pagină care identifică sub-contul prin **e-mail** în loc de `sub_account_id`.

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `email` | Da | E-mailul sub-contului, așa cum există în cadrul agenției tale. |
| `amount` | Da | Număr diferit de zero de credite. Pozitiv adaugă, negativ deduce. |
| `description` | Nu | Afișat în dreptul ajustării în istoricul creditelor clientului. Implicit este o linie generică "Ajustat de agenție prin 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" }'
```

**Răspuns**

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

Un `amount` negativ care ar duce soldul sub zero este refuzat cu `400`, informându-te despre soldul disponibil și suma pe care ai încercat să o deduci. Dacă clientul este pe propria facturare Stripe (mod revânzător), o sumă adăugată contează și ca credite pe care le-a achiziționat, deci supraviețuiește următoarei resetări lunare la fel cum ar face-o o reîncărcare reală; pe un client alocat standard, este tratată ca parte a alocației sale recurente. Oricum ar fi, sunt o adăugare unică, deci o limită de reportare sau o expirare setată pe cont (sau pe planul său) nu le reduce niciodată — doar alocația recurentă și creditele planului sunt supuse acestora.

***

## Citește conversațiile unui sub-cont

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

Vă permite să creați o vizualizare de monitorizare sau asistență a conversațiilor unui client fără a vă conecta la contul acestuia. Mai întâi, listați contactele acestuia cu o previzualizare a ultimului mesaj, apoi citiți istoricul complet al mesajelor unui contact.

**Listare contacte**

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

| Parametru interogare | Obligatoriu | Descriere |
|---|---|---|
| `pageSize` | Nu | Contacte pe pagină. Implicit 25, maximum 50. |
| `lastActivityAt` | Nu | Cursor de paginare — transmiteți `lastActivityAt` din pagina anterioară pentru a continua. |
| `searchQuery` | Nu | Filtrare după numele contactului sau numărul de telefon. |

**Răspuns**

```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"
  }
}
```

Contactele sunt ordonate după cea mai recentă activitate. Continuați paginarea cu `lastActivityAt` cât timp `hasMore` este `true`.

**Citirea mesajelor unui contact**

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

| Parametru interogare | Obligatoriu | Descriere |
|---|---|---|
| `pageSize` | Nu | Mesaje pe pagină. Implicit 30, maximum 100. |
| `beforeTimestamp` | Nu | Cursor de paginare — preluați mesajele mai vechi decât acest marcaj temporal ISO. |

**Răspuns**

```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"
  }
}
```

Mesajele sunt returnate începând cu cele mai noi; navigați înapoi prin istoric cu `beforeTimestamp`.

***

## Citirea utilizării creditelor și a stării campaniilor pentru întregul portofoliu

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

Două rezumate de tip tablou de bord pentru toate subconturile pe care le gestionați, utile pentru a vă crea propriile rapoarte de agenție în loc să accesați fiecare client pe rând.

**Utilizarea creditelor**

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

| Parametru interogare | Obligatoriu | Descriere |
|---|---|---|
| `from` / `to` | Da | Interval de date ISO. |
| `subAccountId` | Nu | Omiteți pentru un rezumat la nivel de agenție, un rând per subcont. Includeți pentru a comuta în modul detaliat: rezumatul acelui subcont plus înregistrările brute de utilizare paginate. |
| `limitCount` | Nu | Doar pentru modul detaliat. Implicit 500, maximum 2000. |
| `startAfterTimestamp` | Nu | Doar pentru modul detaliat — cursor de paginare. |

```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
  }
}
```

Transmiteți `subAccountId` și același răspuns va conține și `records`: taxe individuale cu `amount`, `reason`, `campaignName`, `contactName` și `timestamp`. Un client care cheltuiește folosind propria cheie BYOK în loc de creditele dumneavoastră va avea cifrele de cost/token ascunse (`costsRedacted: true`) — aceasta este telemetrie privind costurile platformei, nu ceva ce trebuie afișat unui revânzător.

**Starea campaniei**

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

| Parametru de interogare | Obligatoriu | Descriere |
|---|---|---|
| `pageSize` | Nu | Sub-conturi pe pagină. Implicit 10, maximum 50. |
| `lastDocumentId` | Nu | Cursor de paginare. |
| `searchQuery` | Nu | Filtrare după numele sau adresa de e-mail a sub-contului. |

```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` marchează sub-conturile care merită atenție — o campanie întreruptă sau una fără niciun canal direcționat către ea, de exemplu. Folosiți acest lucru pentru a crea un tablou de bord de verificare a stării pentru întregul portofoliu, în loc să deschideți fiecare client pentru a observa o campanie blocată.

> Pentru mesagerie în serie temporală și activitate de credit pentru fiecare client (o serie pregătită pentru grafice, mai degrabă decât un instantaneu la un moment dat), consultați `GET /analytics/agency-rollup` în ghidul API-ului de Analiză.

***

## Livrați un cont de client care este deja configurat

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

Un [snapshot](snapshots.md) este un șablon reutilizabil: unul sau mai mulți agenți AI plus baza lor de cunoștințe, instrumente și conținut media, capturate din propriul tău cont. Două endpoint-uri îl introduc în fluxul tău de aprovizionare.

**Automat — fiecare client nou îl primește implicit.** Marchează un snapshot ca implicit o singură dată și fiecare cont pe care îl creezi de atunci înainte va veni cu acesta instalat. Aceasta acoperă conturile create prin `POST /v1/subaccounts`, conturile pe care le creezi în tabloul de bord și conturile create automat atunci când un client plătește prin linkul tău de checkout.

Mai întâi, găsește ID-ul snapshot-ului:

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

Apoi setează-l ca implicit:

```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" }'
```

Aceasta este întreaga integrare. Trimite `{"snapshot_id": null}` pentru a-l dezactiva din nou. Poți face același lucru din tabloul de bord făcând clic pe steaua de pe pagina **Snapshots**.

Pentru a citi ce este marcat în prezent cu stea (de exemplu, înainte ca un script de provizionare să decidă dacă să seteze unul), `GET /v1/snapshots/default` returnează `{ "success": true, "data": { "default_snapshot_id": "SNAPSHOT_ID" } }` — `null` când nimic nu este marcat cu stea. `GET /v1/snapshots` (folosit pentru a găsi id-ul de mai sus) returnează același `default_snapshot_id` împreună cu matricea completă `snapshots`, deci majoritatea integrărilor au nevoie doar de un singur apel. Câmpurile obiectului instantaneu complet se află în ghidul [Instantanee](snapshots.md).

**La cerere — instalare într-un singur cont.** Util pentru integrarea unui client existent sau pentru a oferi unui client un al doilea șablon mai târziu.

```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" }'
```

Omite `sub_account_id` și acesta se va instala în propriul tău cont de agenție. La fel ca endpoint-urile `/subaccounts`, acestea denumesc contul țintă în cale sau în corp, mai degrabă decât prin parametrul ambiental `sub_account_id`.

Merită să știi înainte de a construi pe baza acestuia:

- **Agenții instalați pornesc în stare suspendată.** Conectează mai întâi canalele clientului, apoi activează agentul. Acest lucru este valabil atât pentru calea automată, cât și pentru cea la cerere.
- **Aprovizionarea nu eșuează niciodată din cauza unui snapshot.** Dacă instalarea nu se poate finaliza, contul clientului este totuși creat și utilizabil — acesta ajunge pur și simplu gol și poți aplica snapshot-ul ulterior.
- **Canalele, calendarele și conexiunile OAuth nu sunt niciodată copiate.** Fiecare cont își conectează propriile resurse. Instrumentele care utilizează o cheie API simplă continuă să funcționeze imediat.
- **Aplicarea de două ori creează o a doua copie.** Nimic nu este suprascris.

***

## Construiește șablonul propriu-zis prin API

`POST /v1/snapshots` · agenți, funcții personalizate și conținut media prin API

Secțiunea de mai sus distribuie un instantaneu creat de cineva în tabloul de bord. Partea de creare este de asemenea expusă, astfel încât întregul ciclu — asamblarea configurației principale o singură dată, capturarea acesteia, transmiterea către fiecare client — poate fi executat prin cod.

Componentele, în ordinea în care le folosește un script de provizionare:

1. **Creează-ți funcțiile personalizate.** `POST /v1/custom-functions` creează una; `GET /v1/custom-functions` listează ce ai deja, iar `GET`, `PUT` și `DELETE` pe `/v1/custom-functions/{customFunctionId}` citesc, actualizează și elimină una. `POST /v1/custom-functions/test` testează o definiție înainte de a o salva.
2. **Creează și configurează agentul.** `POST /v1/agents` îl creează, `PUT /v1/agents/{agentId}` îl actualizează, iar `PATCH /v1/agents/{agentId}/active` cu `{ "active": false }` îl menține în pauză în timp ce lucrezi (același apel cu `true` îl pune în funcțiune). `GET /v1/agents` îi listează.
3. **Oferă-i agentului abilitățile sale.** `POST /v1/agents/{agentId}/custom-functions` cu `{ "custom_function_id": "..." }` atașează o funcție agentului; `DELETE /v1/agents/{agentId}/custom-functions/{customFunctionId}` corespondent o detașează.
4. **Completează biblioteca media.** `POST /v1/agents/{agentId}/media-library` încarcă un element (JSON cu `base64Data`, `mimeType`, `title`, `description`); `GET` listează elementele agentului, iar `PATCH`/`DELETE` pe `/{itemId}` actualizează sau elimină unul.
5. **Capturează-l ca instantaneu.**

```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
  }'
```

De acolo, se aplică secțiunea anterioară: marchează-l ca implicit, astfel încât fiecare client nou să îl aibă preinstalat, sau aplică-l la cerere. Administrarea se face în paralel: `PATCH /v1/snapshots/{snapshotId}` cu `{ "name": "..." }` redenumește unul, `DELETE /v1/snapshots/{snapshotId}` șterge unul (și elimină marcajul dacă era cel implicit), iar `GET /v1/snapshots/apply-targets` listează fiecare cont în care ai putea face instalarea.

Endpoint-urile pentru agent, funcții personalizate și media acceptă toate `sub_account_id`, astfel încât aceleași apeluri pot menține un agent direct în contul unui client. Apelurile pentru instantanee acționează întotdeauna asupra contului tău de agenție — șablonul rămâne la tine. Schemele complete de cerere și răspuns pentru toate acestea se află în [Referința API](../api/reference.md).

***

## Gestionați-vă nivelurile de preț prin API

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

Planurile pe care le vindeți în **Mod SaaS → Niveluri de preț** pot fi citite și modificate din cod, astfel încât propriul panou de administrare sau scriptul de aprovizionare poate adăuga un plan, ajusta un preț sau oferi un link de finalizare a comenzii fără ca cineva să deschidă tabloul de bord. Autentificați-vă cu cheia API a agenției ca la orice alt apel de pe această pagină; aceste puncte finale sunt la nivel de agenție, deci nu necesită `sub_account_id`. Fiecare scriere rulează aceeași validare și aceeași sincronizare a produselor și prețurilor Stripe ca și salvarea din tabloul de bord, deci un plan creat aici este indistinguibil de unul configurat manual.

### Listați-vă nivelurile

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

**Răspuns**

```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
  }
}
```

Fiecare nivel revine cu **`tierIndex`**-ul său — poziția sa în lista de Planuri, care este modul în care celelalte trei apeluri îl adresează — și un **`checkout_url`** gata de partajat, același link pe care vi-l oferă fila **Plăți**, care indică deja [domeniul white label](white-labeling.md) pe care este vândut acel plan.

### Adăugați un nivel

Corpul este un obiect de nivel; acesta este adăugat la sfârșitul listei dvs.

```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"]
  }'
```

Răspunsul conține nivelul creat, inclusiv `tierIndex`-ul pe care a aterizat și `checkout_url`-ul său.

### Editați un nivel

Trimiteți doar câmpurile pe care doriți să le modificați; tot restul planului rămâne așa cum a fost.

```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 câmp pe care API-ul nu îl recunoaște este refuzat în loc să fie ignorat, iar eroarea îl numește — astfel încât o greșeală de scriere nu poate scrie niciodată în liniște o setare care pare activă, dar nu face nimic. Modificarea prețului, a creditelor, a monedei sau a frecvenței de facturare creează un preț nou în Stripe; clienții care s-au abonat deja rămân la ceea ce au ales inițial.

### Ștergeți un nivel

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

Aceeași regulă ca în tabloul de bord: un plan care are încă abonați activi nu poate fi șters. Cererea revine refuzată, spunându-vă câți abonați sunt pe acesta — anulați sau migrați-i mai întâi. O ștergere reușită răspunde cu nivelurile rămase, deja renumerotate.

### Câmpurile de pe un nivel

| Câmp | Ce este |
|---|---|
| `label` / `description` | Numele planului și linia opțională afișată pe pagina ta de finalizare a comenzii. |
| `credits` | Credite pe care clientul le primește **pe lună** într-un plan lunar sau anual și **pe perioadă de facturare** într-unul săptămânal. |
| `price_cents` | Prețul pe interval de facturare, în cea mai mică unitate monetară (`2900` = $29.00). Într-un plan anual, acesta este prețul pentru întregul an. |
| `currency` | Cod ISO cu litere mici — `usd`, `eur`, `gbp` și așa mai departe. |
| `billing_interval` / `billing_interval_count` | `month` (implicit), `year`, sau `week` cu un număr de 1–52 pentru "la fiecare N săptămâni". |
| `trial_days` | Durata perioadei de probă gratuită, de la 0 la 90. `0` (sau omiterea acesteia) înseamnă fără perioadă de probă. |
| `trial_credits` | Credite cu care clientul începe perioada de probă. Implicit este `credits` al planului. |
| `trial_card_required` | `false` permite clientului să înceapă perioada de probă fără a introduce un card. Implicit este `true`. |
| `trial_hard_expiry` | `true` returnează creditele neutilizate din perioada de probă în fondul tău și blochează contul clientului când o perioadă de probă se termină fără un upgrade. Implicit este `false` — vezi [Expirare strictă după perioada de probă](agency-accounts.md#step-3--set-up-pricing-tiers). |
| `rollover_cap_months` | Luni de alocație pe care clienții din acest plan le pot păstra între reînnoiri — un număr de la 0 la 120, fracțiile sunt permise. `0` nu reportează nimic; `null` (implicit) înseamnă fără limită. Vezi [Limitarea a ceea ce se reportează](sub-accounts.md#capping-what-rolls-over). |
| `rollover_expiry_days` | Zile după care creditele neutilizate sunt eliminate la următoarea reînnoire — un număr întreg de la 1 la 3650. `null` (implicit) înseamnă că nu expiră niciodată. |
| `features` / `feature_settings` | Ce primesc clienții din acest plan — aceleași ID-uri de funcționalități ca la [Alege ce tipuri de canale poate conecta un client](#choose-which-channel-types-a-client-can-connect). |
| `team_seats_limit` | Locuri în echipă pe care planul le oferă: un număr exact, `0` pentru niciunul, `-1` pentru nelimitat. |
| `white_label_config` | Pe care dintre [domeniile tale white label](white-labeling.md#up-to-three-white-labels) este vândut planul. |

Câmpurile pentru perioada de probă au sens doar pentru un plan care are o perioadă de probă: salvează un nivel cu `trial_days: 0` și acestea vor fi eliminate. ID-urile de produs și preț Stripe ale planului sunt gestionate pentru tine și nu pot fi setate manual.

Trei aspecte de reținut:

- **Indicii de nivel sunt poziții, nu ID-uri permanente.** Ștergerea unui plan mută fiecare plan ulterior cu o poziție mai jos, așa că reîncărcați lista după orice modificare — și copiați din nou linkurile de checkout pe care le-ați publicat, exact așa cum ați face după ștergerea unui plan din tabloul de bord.
- **Modul SaaS trebuie configurat mai întâi.** Aceste endpoint-uri necesită un cont de agenție cu white labeling și o cheie Stripe deja salvată; fără acestea, nu există niciun cont Stripe pe care să poată fi găzduite produsul și prețul planului.
- **Douăzeci de planuri este limita maximă**, la fel ca în tabloul de bord. Câmpul `max_tiers` din răspunsul listei vă indică limita curentă.

Schemele complete de cerere și răspuns se află în [Referința API](../api/reference.md), sub secțiunea **Agenție**.

***

## Setează prețul per credit prin API

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

Prețul pe care clienții îl plătesc pentru reîncărcări ad-hoc (**Mod SaaS → Preț per credit**) poate fi citit și modificat și din cod. Această funcționalitate este creată pentru situațiile în care prețul trebuie să se ajusteze automat: o agenție care vinde credite într-o monedă, dar facturează în alta, poate lăsa un job programat să revizuiască prețul pe măsură ce cursul valutar se modifică, în loc ca cineva să îl editeze manual în fiecare săptămână.

### Citește prețul curent

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

**Răspuns**

```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` este cel mai mic preț permis de platformă în acea monedă, astfel încât un job poate verifica un preț nou înainte de a-l trimite. Toate cele trei valori sunt `null` până când un preț a fost setat.

### Modifică-l

```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" }'
```

Trimite doar ceea ce dorești să modifici. `price_per_credit_cents` este prețul în cea mai mică unitate monetară (`130` = 1,30 R$); `currency` este un cod ISO cu litere mici; `note` este un rând opțional de până la 200 de caractere afișat clienților direct sub prețul per credit pe pagina lor de Facturare — util pentru un preț de referință în altă monedă, cum ar fi *"0,25 USD per credit la cursul nostru de referință"*. Trimite `"note": ""` pentru a-l elimina. Răspunsul are aceeași formă ca cel de citire de mai sus, astfel încât un job poate compara și omite scrierea atunci când nimic nu s-a schimbat.

Se aplică aceleași reguli ca în tabloul de bord: prețul nu poate scădea sub minimul platformei pentru acea monedă, iar contul trebuie să aibă activată funcția de white labeling. Spre deosebire de endpoint-urile pentru nivelurile de preț, nu este necesară nicio cheie Stripe pentru a citi sau modifica această valoare.

### Oferă unui job o cheie care nu poate face nimic altceva

Introducerea cheii complete a agenției într-un programator oferă mai multe drepturi de acces decât sunt necesare pentru o actualizare de preț. În schimb, generează o **cheie cu domeniu limitat** (scoped key) restricționată la zona **Preț Credit Agenție**: acea cheie poate citi și modifica prețul per credit și nimic altceva — nu poate accesa sub-conturi, planuri, credite sau conexiunea ta 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"] } }'
```

Răspunsul conține noua cheie în `api_key` **o singură dată** — nu va mai fi afișată niciodată, așa că salveaz-o imediat. Setează `"read_only": true` pentru o cheie care trebuie doar să citească prețul și adaugă `"expires_at"` (o dată ISO) dacă dorești ca aceasta să înceteze să mai funcționeze automat. Doar cheia proprietarului contului poate crea chei cu domeniu limitat; listează-le sau revocă-le folosind `GET /v1/api-keys` și `DELETE /v1/api-keys/{id}`.

***

## Permiteți unui sub-cont să vă citească prețurile

`GET /v1/subaccounts/agency-pricing`

Fiecare alt endpoint de pe această pagină este apelat cu **cheia de agenție**, vizând opțional un client prin `sub_account_id`. Acesta este opusul: este apelat cu **propria cheie API a sub-contului**, fără `sub_account_id`, astfel încât pagina proprie de reîncărcare a unui client (sau o integrare pe care o construiți pentru el) să poată afișa ceea ce îi taxați fără a vedea vreodată contul de agenție.

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

**Răspuns**

```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"
  }
}
```

Acesta oglindește exact ceea ce returnează [`GET /v1/agency/pricing-tiers`](#list-your-tiers) și [`GET /v1/agency/credit-price`](#read-the-current-price) pentru dumneavoastră ca agenție, minus orice nu trebuie să vadă clientul (id-uri Stripe, `max_tiers` și așa mai departe). Funcționează doar pentru un cont care este efectiv un sub-cont cu o agenție conectată — apelarea acestuia din propriul cont de agenție returnează o eroare de permisiune.

***

## Aspecte de reținut

- **Folosiți cheia de agenție.** Autentificați fiecare apel cu cheia API a contului de agenție — nu a sub-contului. Parametrul `sub_account_id` este cel care redirecționează acțiunea.
- **Creditele provin din sub-cont.** Achizițiile și taxele recurente sunt deduse din soldul de credit al sub-contului vizat, nu din al dumneavoastră.
- **O eroare `404` înseamnă „nu este sub-contul dumneavoastră”.** Verificați din nou ID-ul și asigurați-vă că este un cont pe care îl gestionați.
- **Parametrul este opțional peste tot unde este acceptat.** Omiteți-l și același endpoint va acționa asupra contului de agenție, astfel încât să puteți reutiliza o singură integrare pentru ambele.

***

## Legate

- [Acces API](../integrations/api-access.md) — autentificare, URL de bază, erori, limite de rată.
- [Sub-conturi](sub-accounts.md) — listați și gestionați conturile pe care le puteți viza.
- [Reîncărcare automată sub-cont](sub-account-auto-recharge.md) — acordați credite unui sub-cont prin webhook + API.
- [API Campanii](../api/campaigns.md) — creați, actualizați și copiați campanii, inclusiv referința completă a câmpurilor.
- [API Conexiune Canal](../api/channels.md) — conectați canalele unui client și direcționați-le către o campanie.
- Ghid API Analiză (în secțiunea API) — centralizarea sub-conturilor agenției și orice alt endpoint de raportare.
- [Instantanee](snapshots.md) — ce captează un instantaneu și cum să construiți unul în tabloul de bord.
