> ## Documentation Index
> Fetch the complete documentation index at: https://widgetic.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Editor Sessions

> Let one of your customers use Widgetic's editors in your page, without your API key reaching the browser

An editor session is a short-lived credential that lets the browser of **one** of your customers use Widgetic's editors on **that customer's** content, and nothing else. Your server makes it with your API key and hands only the token to the page. The key never leaves your server.

You rarely call the browser side yourself: the [UI SDK](https://widgetic.com/docs/partners/ui-components.md) asks your page for the token and the editors use it. This page is about the server side: making sessions, what a session can and cannot do, how long it lives, and how to end it.

> [!NOTE]
>
> **Preview.** The editors you mount with the UI SDK are new. The calls on this page are built and tested, and you can try them now, but small details can still change while this label is on. Tell us what you find at [support@widgetic.com](mailto:support@widgetic.com).

## How it works

```mermaid theme={null}
sequenceDiagram
    participant Page as Your page
    participant Server as Your server
    participant Api as Widgetic API
    participant Cdn as Widgetic CDN
    Page->>Cdn: The UI SDK downloads the editor
    Page->>Server: Asks for a token for the signed-in customer
    Server->>Api: Makes an editor session (your API key)
    Api-->>Server: The token, shown once
    Server-->>Page: The token, and nothing else of yours
    Page->>Api: The editor calls the API with the token
```

A session belongs to one [managed user](https://widgetic.com/docs/partners/managed-users.md). Everything that session reads or makes is that managed user's: a composition, widget, canvas or file that was made for another of your customers answers `404`, exactly as if it did not exist.

## Make a session

Call this from your server, when the page that holds the editor opens. `{id}` is Widgetic's `id` for the managed user (the UUID the create call gave you), not your own `external_id`.

```bash cURL theme={null}
curl -sS -X POST "https://api.widgetic.com/v1/managed-users/$MANAGED_USER_ID/editor-sessions" \
  -H "Authorization: Bearer $WIDGETIC_PARTNER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "surfaces": ["creator", "editor", "files"],
    "expires_in_seconds": 3600,
    "allowed_origin": "https://app.example.com"
  }'
```

```typescript TypeScript SDK theme={null}
import { ManagedUsersApi } from '@widgetic/api-sdk-ts';

const managedUsersApi = new ManagedUsersApi(process.env.WIDGETIC_PARTNER_KEY!);

// On your server, when the page that hosts the editor opens for one of your customers:
const session = await managedUsersApi.createManagedUserEditorSession({
  id: managedUserId,
  newEditorSession: {
    surfaces: ['creator', 'editor', 'files'],
    expires_in_seconds: 3600,
    allowed_origin: 'https://app.example.com',
  },
});

// Send session.token to that customer's browser, and nothing else of yours.
```

| Field | Required | |
| - | - | - |
| `surfaces` | Yes | What the session may do. One or more of `files`, `editor`, `creator` and `workflows`. See [Surfaces](#surfaces). |
| `expires_in_seconds` | No | How long the session lasts: 60 to 14400 (four hours). Default 3600. It cannot be extended: make a new session when it ends. |
| `allowed_origin` | No | Bind the session to one web page origin, such as `https://app.example.com` (no path; `http` only for `localhost`). See [Bind it to your page](#bind-it-to-your-page). |
| `max_credits` | No | The most credits this session may spend on the AI: a whole number from 1 to 1000000, refunds taken off. Leave it out for no limit of its own, unless Widgetic has set a default for your account; send `null` to ask for none. See [A limit for one session](#a-limit-for-one-session). |

The answer is `201`:

```json theme={null}
{
  "success": true,
  "data": {
    "token": "wgt_ses_3q2-7wA9vJm5cH1xT0uY8pZkR4nLd6BfGeSoVi2tMqE",
    "sessionId": "9c1d6b7e-5d54-4a0e-8d52-0f3e3c0a6a11",
    "managedUserId": "3f0c9a52-8e0a-4a52-9d52-5d8a1f1b7c10",
    "managedUserExternalId": "your-platform-user-123",
    "surfaces": ["creator", "editor", "files"],
    "allowedOrigin": "https://app.example.com",
    "maxCredits": null,
    "expiresAt": "2026-10-04T14:00:00.000Z",
    "createdAt": "2026-10-04T13:00:00.000Z"
  }
}
```

* **The token is shown once.** It starts with `wgt_ses_`, and the answer is sent with `Cache-Control: no-store`. Widgetic keeps only a fingerprint of it, so a lost token cannot be read back: make another session.
* **`sessionId` is not a credential.** It is only the handle you use to [end the session](#end-a-session).
* Each call makes a new session. It does not take an `Idempotency-Key`, because a retry cannot be given the token back.
* A key that is limited to some scopes needs all of `partner:write`, `content:write` and `generate` to make a session, and is refused with `403` `API_KEY_SCOPE_MISSING` without them (see [Limit what a key can do](https://widgetic.com/docs/authentication.md#limit-what-a-key-can-do)). A key with full access needs nothing more.
* A session is made only while your account is in force and your [storage](https://widgetic.com/docs/partners/storage.md) works. A paused account is refused with `403` `PARTNER_SUSPENDED`, and an account without a storage destination with `409` `PARTNER_STORAGE_REQUIRED` (see [Every session needs your own storage](#every-session-needs-your-own-storage)).

### A server endpoint for your page

Your page needs one endpoint of yours that checks who is signed in, makes a session for that customer and returns the token. The UI SDK calls it again shortly before the token runs out, so the customer is never interrupted.

```javascript theme={null}
// Express. WIDGETIC_PARTNER_KEY lives in your server's environment and goes nowhere else.
app.post('/widgetic-session', requireSignedInUser, async (request, response) => {
  const managedUserId = await lookUpWidgeticIdOf(request.user); // the managed user you made for this customer

  const widgetic = await fetch(`https://api.widgetic.com/v1/managed-users/${managedUserId}/editor-sessions`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.WIDGETIC_PARTNER_KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      surfaces: ['creator', 'editor', 'files'],
      expires_in_seconds: 3600,
      allowed_origin: 'https://app.example.com',
    }),
  });
  if (!widgetic.ok) return response.status(502).json({ error: 'Could not start a Widgetic session' });

  const { data: session } = await widgetic.json(); // every answer of the API is { success, data }
  response.set('Cache-Control', 'no-store').json({ token: session.token, expiresAt: session.expiresAt });
});
```

## Surfaces

A session can do only what its surfaces allow. The surfaces do not imply one another, so ask for every one the editor you mount needs.

| Surface | What the session may do | Editor that needs it |
| - | - | - |
| `files` | Upload a file and list the files uploaded for this customer. Every file is filed under this customer and kept in **your own storage**, and a customer's file is never stored with Widgetic. See [Every session needs your own storage](#every-session-needs-your-own-storage). | File Browser |
| `editor` | Open one of this customer's compositions, read its content, design, embed settings and schemas, and change its name, content, design and embed settings. | Composition editor |
| `creator` | Everything the widget creator does for this customer: draw on canvases and save them, make and change widgets, talk to the AI, build, preview and publish a version, and list and make compositions of the widgets it built. | Widget creator |
| `workflows` | Everything the Workflows screen does for this customer: list, make (also from a [starting point](https://widgetic.com/docs/partners/workflows.md#starting-points) you offer), change, publish, pause, archive, duplicate and delete this customer's workflows, read their versions and their counts, and pick from this customer's compositions the ones to chain. A workflow is filed under this customer when it is made. | Workflows |

* **File Browser:** `["files"]`.
* **Composition editor:** `["editor", "files"]`.
* **Widget creator:** `["creator", "editor", "files"]`. The creator saves the composition it is editing (`editor`) and attaches pictures to its chat (`files`).
* **Workflows:** `["workflows"]`. The screen uploads no file and opens no composition: it chains compositions by their ids. See [Workflows](https://widgetic.com/docs/partners/workflows.md).

The calls behind each surface are listed in the [API Reference](https://widgetic.com/api-reference/introduction.md), under `createManagedUserEditorSession`.

### Every session needs your own storage

The files a customer uploads are yours to keep, so an editor session is made only when you have set up your own [storage destination](https://widgetic.com/docs/partners/storage.md): a bucket you own, on any S3-compatible service. Widgetic never keeps a customer's uploaded file in its own storage. Storage is not optional for a partner, and it does not depend on which surfaces a session asks for.

* **No storage, no session.** The call that makes the session answers `409` with the code `PARTNER_STORAGE_REQUIRED`, whatever the surfaces are. When a destination is saved but cannot be used (it is switched off, its credentials cannot be opened, or your account administers two partners that each have one) it answers `503` with `STORAGE_DESTINATION_UNAVAILABLE`. No session is made, so you hear about it on your server and never from a customer's browser.
* **There is no fallback.** If you remove your storage after a session was made, that customer's uploads are refused until you save a destination again. They are never written to Widgetic's storage, and they never count against your storage allowance.
* **The customer is told one plain sentence:** "This is not available right now. Please try again later." It names neither your storage nor a limit, because it is your setup and not theirs.
* **It covers your customers' uploads, and yours.** What a session makes for itself, such as a widget's code and its previews, stays with Widgetic. The uploads you send with your own key are kept in your storage too: without a destination they are refused with the same `409`, and never stored with Widgetic instead.
* **An account that is not activated yet** cannot make a session at all (`PARTNER_INACTIVE`), and activation needs a storage destination that works. See [Account Status](https://widgetic.com/docs/partners/account-status.md#getting-activated).

### What a session never does

Everything outside its surfaces is refused with `403` and the code `EDITOR_SESSION_ROUTE_NOT_ALLOWED`. In particular a session cannot:

* read or change your account, your keys, your contract, your invoices or your credits;
* make more sessions, or list or end sessions;
* see another of your customers' compositions, widgets, canvases, conversations, files or workflows (those answer `404`);
* delete a composition (create it yourself with your key, then open the editor on it);
* make a widget public: what a customer builds stays private to your account (publishing a version of the widget is allowed while your partner agreement is in force, whatever plan your account is on, and it does not make it public);
* file anything under a project or an organization, or set a field the editors do not set. A body with such a field is refused with `403` and `EDITOR_SESSION_FIELD_NOT_ALLOWED`.

> [!NOTE]
>
> This is the difference between a session and your API key. Your key reaches everything on your account, whoever it was filed under. A session reaches only its own customer's content.

## Content the editors can open

A session reaches only content that was **filed under its managed user**:

* **Compositions:** create them on your server with your key and name the customer (`managedUserId` or `managedUserExternalId`, see [Filing Content Under a Managed User](https://widgetic.com/docs/partners/managed-users.md#filing-content-under-a-managed-user)), then mount the composition editor on the composition's `id`. A composition you made without naming a customer is not reachable by any session.
* **Widgets, canvases and compositions made in the widget creator** are filed under the session's managed user automatically. List them from your server with the same `managedUserId` filter.
* **Files** a session uploads are filed under its managed user and listed back only for it.
* **Workflows** a session makes are filed under its managed user automatically, and a session can chain only that customer's compositions. A workflow of yours that was made without a customer is not reachable by any session. See [Workflows](https://widgetic.com/docs/partners/workflows.md#what-belongs-to-whom).

## Bind it to your page

Give `allowed_origin` the origin of the page that mounts the editor. The session is then refused from any other origin, and from a request that carries no `Origin` header, so a token copied out of your page is useless anywhere else. It is stored as `scheme://host[:port]`: `https` (or `http` for `localhost`, `127.0.0.1` and `[::1]`), no path, query or credentials, and no wildcard.

Leave it out only for a session that is used from a server.

## Lifetime

* A session lasts from 60 seconds to four hours (`expires_in_seconds`, default one hour). It cannot be extended.
* A managed user can hold up to 100 live sessions. Another request answers `429` with `EDITOR_SESSION_LIMIT_REACHED`; end the ones you no longer need.
* Mint a session per page open and per customer, from an endpoint that checks who is signed in. Never give one customer's token to another.
* Switching the managed user off or deleting it ends all of its sessions.

## End a session

End one session, or all of a customer's sessions, for example when they sign out of your platform. Both need your key and take effect on the next request (allow up to 15 seconds for every server of ours to notice).

```bash theme={null}
# One session
curl -sS -X DELETE "https://api.widgetic.com/v1/managed-users/$MANAGED_USER_ID/editor-sessions/$SESSION_ID" \
  -H "Authorization: Bearer $WIDGETIC_PARTNER_KEY"

# Every live session of the customer
curl -sS -X DELETE "https://api.widgetic.com/v1/managed-users/$MANAGED_USER_ID/editor-sessions" \
  -H "Authorization: Bearer $WIDGETIC_PARTNER_KEY"
```

The first answers `200` with the session's id (and `404` `EDITOR_SESSION_NOT_FOUND` for one that was never yours; ending a session that already ended is fine). The second answers `200` with `{ "ended": 2 }`, the number of sessions it ended, and is fine for a customer who has none.

## Credits and limits

The AI is paid for by **your account**, as your own calls are: a generation a customer starts uses the same credit as one you start with your key (see [Credits & Billing](https://widgetic.com/docs/partners/credits-billing.md)). A customer's uploads do not use your account's storage allowance: they are kept in your own storage (see [Every session needs your own storage](#every-session-needs-your-own-storage)).

* **Each customer has an allowance of their own.** What a customer does with the AI is counted per customer, not per account or per session: one busy customer cannot use up the others' turns, a customer who opens many sessions still has one allowance, and your own calls with your key are counted separately. At the moment a customer can start about 26 generations or builds an hour and about 130 a day. A customer who uses it up is refused with `429`, the code `COST_LIMIT_EXCEEDED` and a `Retry-After` header, and only that customer is. It also keeps a script in one browser from spending all your credits. Everybody starts with the same allowance, and Widgetic can set it for your account alone: tell us if your customers need more, and see [Settings that can differ for your account](#settings-that-can-differ-for-your-account).
* **Your credits and plan are yours.** When your account cannot pay, every customer is refused: `402` `BILLING_INSUFFICIENT_CREDITS` (credits) or `403` `AUTHZ_PLAN_RESTRICTION` (your plan does not include it). A customer is never told what your account holds: the message is one plain sentence, "This is not available right now. Please try again later.", with no balance, cost or plan. The same calls made with your key keep the full messages.
* **The editors tell your page.** The widget creator reports these as a `limitReached` event, once per code in half a minute, so your page can offer more or tell its own team. See [Canvas Embedding](https://widgetic.com/docs/partners/canvas-embedding.md#when-a-limit-is-reached).
* **Workflows use no credits and have a limit of their own.** Making, saving and publishing a workflow is not an AI call, so it takes nothing from your credits and is not counted against a customer's allowance. A customer can hold up to 50 workflows, archived ones included. See [Limits and cost](https://widgetic.com/docs/partners/workflows.md#limits-and-cost).
* **Ordinary rate limiting** (`RATE_LIMIT_EXCEEDED`) counts the address each request comes from, not your account, so your customers do not share it. It is not a limit your page needs to report.
* **You can hold one session to a number of credits, and see what each customer spent.** See [A limit for one session](#a-limit-for-one-session) and [What each customer spent](#what-each-customer-spent).

### A limit for one session

Send `max_credits` when you make a session, and that session can spend at most that many credits on the AI. Refunds are taken off: a generation that fails gives its credit back to the session as well as to your account.

```bash theme={null}
curl -sS -X POST "https://api.widgetic.com/v1/managed-users/$MANAGED_USER_ID/editor-sessions" \
  -H "Authorization: Bearer $WIDGETIC_PARTNER_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "surfaces": ["creator", "editor", "files"], "max_credits": 20 }'
```

* **The call that would go past the limit is refused before anything is taken from your account.** The answer is `402` with the code `EDITOR_SESSION_CREDIT_LIMIT_REACHED`. The customer reads the same plain sentence as for any other limit, never the limit or what was spent. The widget creator tells your page with a `limitReached` event whose `code` is this one, so you can tell it from an account that is out of credits (`BILLING_INSUFFICIENT_CREDITS`).
* **The limit belongs to the session.** A new session starts again from zero. For a cap on what a customer may spend in a day or a month, read [their usage](#what-each-customer-spent) on your server and stop making sessions at your own number.
* **Only calls that take credits count.** Building a widget takes none, so it is never counted or held back by `max_credits`.
* **A limit that cannot be checked does not let the call through.** If Widgetic cannot read what the session has spent, the call is refused with `503` and the customer can try again in a moment.

### Settings that can differ for your account

Editor sessions behave the same for every partner by default. If your account needs something different, Widgetic can set any of these three for your account alone, and nothing else about your account changes:

| Setting | What it does | What you see |
| - | - | - |
| Sessions switched off | Editor sessions are not made for your account. It can only narrow what everybody gets: it never switches on what Widgetic has switched off for all. | A new session is refused with `403` `EDITOR_SESSIONS_DISABLED_FOR_PARTNER`, and a customer's open session is refused the same way |
| A larger allowance | What one operation of your customers costs against their own allowance is smaller, so each customer can do more before `COST_LIMIT_EXCEEDED` | Customers are refused later. Nothing to change in your calls |
| A default limit for new sessions | The `max_credits` a session gets when your request does not name one. A request that names its own limit, or `null` for none, keeps it | A session that you made without `max_credits` can still end with `EDITOR_SESSION_CREDIT_LIMIT_REACHED` |

A change reaches every server within about a quarter of a minute. Ask [partners@widgetic.com](mailto:partners@widgetic.com) when you need one.

### What each customer spent

Your account pays for the AI, so your credit ledger does not say which of your customers used what. Widgetic notes every call that a customer's session paid for, and adds the notes up for one customer over a period:

```bash cURL theme={null}
curl -sS "https://api.widgetic.com/v1/managed-users/$MANAGED_USER_ID/usage?startDate=2026-10-01&endDate=2026-11-01" \
  -H "Authorization: Bearer $WIDGETIC_PARTNER_KEY"
```

```typescript TypeScript SDK theme={null}
import { ManagedUsersApi } from '@widgetic/api-sdk-ts';

const managedUsersApi = new ManagedUsersApi(process.env.WIDGETIC_PARTNER_KEY!);

// What this customer's sessions spent in October:
const usage = await managedUsersApi.getManagedUserUsage({
  id: managedUserId,
  startDate: '2026-10-01',
  endDate: '2026-11-01',
});

console.log(usage.totals.credits, usage.operations);
```

```json theme={null}
{
  "success": true,
  "data": {
    "managedUserId": "3f0c9a52-8e0a-4a52-9d52-5d8a1f1b7c10",
    "managedUserExternalId": "your-platform-user-123",
    "from": "2026-10-01T00:00:00.000Z",
    "to": "2026-11-01T00:00:00.000Z",
    "totals": { "calls": 41, "credits": 41, "refundedCalls": 3, "refundedCredits": 3 },
    "operations": [
      { "operation": "agent.code.generate", "calls": 41, "credits": 41, "refundedCalls": 3, "refundedCredits": 3 }
    ]
  }
}
```

* **`calls` and `credits` are what the customer's sessions spent and kept.** A call that failed and was refunded is in `refundedCalls` and `refundedCredits` instead, so it never counts against the customer.
* **The period runs from `startDate` (included) to `endDate` (not included).** Give neither and it is the 30 days before now; it can be 366 days at most. A date without a time is midnight UTC, so for all of October give `2026-10-01` and `2026-11-01`. A date-time must say its offset (`2026-10-01T08:00:00Z`).
* **Only what a customer's sessions spent is counted, from the day Widgetic first recorded it.** What you spend with your own key is not in it, and neither is anything from before.
* **It answers for your managed users only.** One that is not yours answers `404` with `MANAGED_USER_NOT_FOUND`, exactly like one that does not exist. A date that is not a date, a `startDate` that is not before `endDate`, or a period over 366 days answers `400`.

## Browsers

A browser may call the API with a session token from any origin. The API answers the preflight request for the calls a session may make, echoes the origin on the real call, and never sends `Access-Control-Allow-Credentials`: a session does not use cookies, only the `Authorization` header. It exposes the `Retry-After`, `X-Idempotency-Cached` and `X-Correlation-Id` headers to the page. Quote the `X-Correlation-Id` to Widgetic's support when you report a problem.

If your page sends a Content-Security-Policy, see [UI Components](https://widgetic.com/docs/partners/ui-components.md#content-security-policy) for what the editors need.

## Errors

The browser side of a session answers with these. The editors handle them for you and tell your page (`error` event with `sessionEnded: true` when the token cannot be used again).

| Status | Code | Meaning | What to do |
| - | - | - | - |
| 401 | `EDITOR_SESSION_INVALID` | The token is not one of ours | Mint a new session |
| 401 | `EDITOR_SESSION_EXPIRED` | The session ran out | Mint a new session |
| 401 | `EDITOR_SESSION_REVOKED` | You ended it, or the customer was switched off | Mint a new session if the customer should continue |
| 401 | `EDITOR_SESSION_USER_UNAVAILABLE` | The managed user no longer exists or is switched off | Do not mint another until the customer is back |
| 402 | `EDITOR_SESSION_CREDIT_LIMIT_REACHED` | The session has spent the `max_credits` you gave it | Mint a new session if the customer may spend more |
| 403 | `PARTNER_SUSPENDED`, `PARTNER_INACTIVE` | Your partner account is paused, or not activated yet. The customer reads only: "This service is not available right now. Please contact the website that sent you here." | Nothing for the customer to do. See [Account Status](https://widgetic.com/docs/partners/account-status.md) |
| 403 | `EDITOR_SESSIONS_DISABLED_FOR_PARTNER` | Widgetic switched editor sessions off for your account alone. The customer reads: "Editor sessions are not available for this account." | Write to Widgetic |
| 403 | `EDITOR_SESSION_ORIGIN_NOT_ALLOWED` | The session is bound to another page | Mint it with this page's `allowed_origin` |
| 403 | `EDITOR_SESSION_ROUTE_NOT_ALLOWED` | A session cannot make this call | Not a session's job: do it from your server |
| 403 | `EDITOR_SESSION_FIELD_NOT_ALLOWED` | The request sets a field a session may not set | Remove the field |
| 404 | `RESOURCE_…_NOT_FOUND`, such as `RESOURCE_WIDGET_NOT_FOUND` or `RESOURCE_WORKFLOW_NOT_FOUND` | The item is not this customer's, does not exist, or is not even an id (for a workflow, an id that is not a UUID answers `403` `EDITOR_SESSION_ROUTE_NOT_ALLOWED` instead) | File it under the customer, or check the id |
| 409 | `PARTNER_STORAGE_REQUIRED` | The customer uploaded a file and you have no storage destination | Set up your own [storage](https://widgetic.com/docs/partners/storage.md) (see [Every session needs your own storage](#every-session-needs-your-own-storage)). The customer reads only the plain sentence |
| 503 | `EDITOR_SESSIONS_DISABLED` | Editor sessions are switched off for the moment | Try again later |

Making a session can also answer: `400` (a surface that does not exist, `expires_in_seconds` or `max_credits` out of range, or `allowed_origin` that is not an origin), `403` (the caller is not a partner), `404` `MANAGED_USER_NOT_FOUND`, `409` `MANAGED_USER_INACTIVE` (switched off managed users get no sessions), `409` `PARTNER_STORAGE_REQUIRED` (the `files` surface, and no storage destination of your own), `429` `EDITOR_SESSION_LIMIT_REACHED`, `503` `STORAGE_DESTINATION_UNAVAILABLE` (the storage you set up cannot be used) and `503` `EDITOR_SESSIONS_DISABLED`.

## Security checklist

**1. Keep the key on your server**

Make sessions only from your server. Never send your `wgt_prt_` key to a browser: it carries the access of your whole account. Use an editor session instead.

**2. Check who is signed in**

Your endpoint must make the session for the customer who is signed in, and for nobody else.

**3. Bind it to your page**

Send `allowed_origin` so that a copied token is useless on any other web page.

**4. Keep tokens out of logs, storage and URLs**

Hold the token in memory. The UI SDK does.

**5. End sessions when customers leave**

Call `DELETE /managed-users/{id}/editor-sessions` when a customer signs out, and switch the managed user off when their plan on your platform ends.

## Next Steps

> [card] [UI Components](https://widgetic.com/docs/partners/ui-components.md)
>
> Mount the editors in your page with the UI SDK

> [card] [Canvas Embedding](https://widgetic.com/docs/partners/canvas-embedding.md)
>
> The widget creator and the composition editor

> [card] [Workflows](https://widgetic.com/docs/partners/workflows.md)
>
> Let a customer chain their compositions into a path

> [card] [Managed Users](https://widgetic.com/docs/partners/managed-users.md)
>
> File your customers' content under them

> [card] [Credits & Billing](https://widgetic.com/docs/partners/credits-billing.md)
>
> How the AI is paid for


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.