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

# Create a client

> Choose Client or MessagingClient, authenticate, and set the API version, timeouts, and retries.

The SDK has two clients. Most integrations create both with the same key.

| Client | Use it to |
| - | - |
| `Client` | Manage your team and projects: Numbers, webhooks, events, operations, customers, campaigns, audiences, billing, and call records. |
| `MessagingClient` | Act through a Number: send messages, connect Numbers with QuickLink, manage templates, run campaigns by project slug, and control calls. |

Both clients accept a team key or a project credential:

| Credential | `Client` | `MessagingClient` |
| - | - | - |
| Team key (`pmfa_…`) | `{ type: "organizationApiKey" }` | `{ type: "apiKey" }` |
| Project credential (`pmfa_pt_…`) | `{ type: "projectToken" }` plus `projectId` | `{ type: "projectToken" }` |

A key only reaches what its permissions allow. Each task page lists the
permissions its methods need. See [API keys](/console/api-keys) for how to
create keys.

The examples in these guides use three clients named `platform`, `project`, and
`messaging`, created as shown below.

## Create a team client

```typescript theme={null}
import { Client } from "@polymorfa/sdk";

const platform = new Client({
  credential: { type: "organizationApiKey", value: process.env.POLYMORFA_KEY! },
  apiVersion: "2026-09-22",
});
```

A team client reaches every project in the team. Methods that act on one project
take a `projectId` argument.

## Work inside one project

Call `project(projectId)` to get a client bound to one project:

```typescript theme={null}
const project = platform.project("<project-id>");
const events = await project.events.list({ limit: 25 });
```

A project client has the project-level resources: `events`, `webhooks`,
`webhookDeliveries`, `operations`, `flows`, `sipTrunks`, `calls`,
`quickLinkSettings`, `sessionConfiguration`, `usage`, and `callRetention`.
Team resources such as `projects`, `members`, `billing`, `customers`, and
`campaigns` stay on the team client.

With a project credential, create the project client directly:

```typescript theme={null}
import { Client } from "@polymorfa/sdk";

const project = new Client({
  credential: { type: "projectToken", value: process.env.POLYMORFA_KEY! },
  projectId: "<project-id>",
  apiVersion: "2026-09-22",
});
```

The API checks that the credential belongs to that project.

## Create a messaging client

```typescript theme={null}
import { MessagingClient } from "@polymorfa/sdk";

const messaging = new MessagingClient({
  credential: { type: "apiKey", value: process.env.POLYMORFA_KEY! },
  apiVersion: "2026-09-22",
});
```

Use `{ type: "projectToken", value }` for a project credential. Messaging
methods take the Number as their first argument, for example
`messaging.messages.send("<number-id>", ...)`.

## Client options

Both clients accept these options:

| Option | Default | Effect |
| - | - | - |
| `apiVersion` | `2026-09-22` | API contract date sent in the `Polymorfa-Version` header. |
| `timeoutMs` | `30000` | Time limit for each attempt, in milliseconds. |
| `maxNetworkRetries` | `2` | Automatic retries for requests that are safe to repeat. See [Errors and retries](/sdks/typescript/errors#automatic-retries). |
| `baseUrl` | `https://api.polymorfa.com` | API host. |
| `fetch` | global `fetch` | A custom `fetch` implementation. |

## Set the API version

`apiVersion` is the API contract date, in `YYYY-MM-DD` format. It is separate
from the package version. Pin it so a new API version cannot change response
shapes under you. Read [API versioning](/api/versioning) for supported dates.

You can override it for one request:

```typescript theme={null}
const numbers = await platform.sessions.list(undefined, { apiVersion: "2026-09-22" });
console.log(numbers.metadata.apiVersion);
```

## Set request options

Every method takes an optional last argument with per-request options:

```typescript theme={null}
const controller = new AbortController();

const sent = await messaging.messages.send(
  "<number-id>",
  { conversation: { phoneNumber: "+15550001111" }, content: { text: "Your order shipped" } },
  {
    idempotencyKey: "order-1042-shipped",
    timeoutMs: 10_000,
    maxNetworkRetries: 3,
    signal: controller.signal,
    headers: { "x-correlation-id": "order-1042" },
  },
);
```

| Option | Effect |
| - | - |
| `idempotencyKey` | Sent as `Idempotency-Key`. Lets the SDK retry a write without running it twice. |
| `timeoutMs` | Overrides the client timeout for this request. |
| `maxNetworkRetries` | Overrides the client retry count for this request. |
| `signal` | Cancels the request. The SDK throws `PolymorfaCancelledError`. |
| `headers` | Adds request headers. |
| `apiVersion` | Overrides the client API version. |

## Read a response

Methods that return one result resolve to `{ data, metadata }`:

```typescript theme={null}
const response = await messaging.sessions.retrieve("<number-id>");

console.log(response.data.data.status);
console.log(response.metadata.status, response.metadata.requestId);
```

* `data` is the parsed response body. Most bodies wrap the result in their own
  `data` field, so you read `response.data.data`. The return type tells you
  which shape each method has.
* `metadata` holds the HTTP `status`, the `requestId`, the resolved
  `apiVersion`, the number of `attempts`, and the response `headers`.

Include `requestId` when you contact support.

Lists of events, webhooks, deliveries, operations, call records, and call
opt-outs return a page object instead. See
[Read every page](/sdks/typescript/errors#read-every-page).

## Give a browser a client token

Browser and mobile code must not hold a team key or project credential. Mint a
short-lived client token on your server and send it to the browser:

```typescript theme={null}
const minted = await messaging.clientTokens.mint({
  session: "<number-id>",
  ephemeralId: "user_42",
  ttlSeconds: 900,
});

console.log(minted.data.data.token, minted.data.data.expiresAt);
```

The token can use only the actions allowed by the Number's client rules. Read
and change the rules with `clientTokens.retrieveRules` and
`clientTokens.updateRules`. Minting needs all of these permissions:
`sessions:manage`, `messages:write`, `contacts:read`, `presence:read`,
`presence:observe`, and `mcp`. See [Client tokens](/console/client-tokens).

## Call an endpoint without an SDK method

`raw.request` sends an authenticated request to any API path. It uses the
client's credential, API version, timeout, and retry settings:

```typescript theme={null}
const updated = await platform.raw.request<{ data: unknown }>({
  method: "PATCH",
  path: "/messaging/projects/<project-slug>/campaigns/<campaign-id>",
  body: { name: "October launch" },
  idempotencyKey: "rename-october-campaign",
});
console.log(updated.metadata.status, updated.data);
```

A project client confines `raw.request` to its own project.

## Check API status

`SystemClient` needs no credential. Use it in health checks:

```typescript theme={null}
import { SystemClient } from "@polymorfa/sdk";

const system = new SystemClient();
const version = await system.version();
console.log(version.data.apiVersion, version.data.minSupportedVersion);
```

It also has `status()`, `health()`, and `ping()`.

## Resources on each client

`Client` (team):

| Property | Covers |
| - | - |
| `sessions` | Numbers: list, start, stop, Safe Mode, tier changes. See [Numbers](/sdks/typescript/numbers). |
| `webhooks`, `webhookDeliveries` | Webhook endpoints and their deliveries. See [Webhooks](/sdks/typescript/webhooks). |
| `events`, `operations` | Event history and asynchronous work. See [Events and operations](/sdks/typescript/events). |
| `customers` | Customers and pairing links. See [Customers](/sdks/typescript/customers). |
| `campaigns`, `audiences`, `optOuts` | Campaigns and their audiences. See [Campaigns](/sdks/typescript/campaigns). |
| `calls`, `callRetention`, `sipTrunks`, `callPolicy`, `callOptOuts` | Call records and call controls. See [Calls](/sdks/typescript/calls). |
| `quickLinkSettings`, `sessionConfiguration` | Saved QuickLink settings and team defaults for Numbers. |
| `banSafe` | BanSafe health, findings, incidents, and claims. |
| `billing`, `usage` | Balance, transactions, pricing, and metered usage. |
| `projects`, `members`, `apiKeys`, `projectTokens`, `auditLogs`, `securityIncidents`, `sessionBans`, `organizations`, `media` | Team administration and media storage. |
| `raw` | Any API path. |

`MessagingClient`:

| Property | Covers |
| - | - |
| `messages`, `chats`, `media` | Send, edit, and delete messages; read stored history; download media. See [Messages](/sdks/typescript/messages). |
| `sessions`, `quickLinks` | Connect Numbers and read their status. See [Numbers](/sdks/typescript/numbers). |
| `templates` | Project message templates. See [Templates](/sdks/typescript/templates). |
| `campaigns` | Campaigns addressed by project slug. See [Campaigns](/sdks/typescript/campaigns). |
| `voip`, `calls` | Place, answer, and end calls. See [Calls](/sdks/typescript/calls). |
| `clientTokens` | Browser client tokens and the rules that limit them. |
| `contacts`, `identities`, `users` | Contacts, identity lookup, and security codes. |
| `groups`, `channels`, `labels` | WhatsApp groups, channels, and chat labels. |
| `profile`, `privacy`, `presence`, `observationPolicies` | The Number's own profile, privacy, and presence. |
| `business`, `quickReplies` | WhatsApp Business app profile, catalog, and quick replies. |
| `banSafe` | Safe Mode settings. |
| `testing` | Test events for Test Numbers. |
| `webhooks` | Per-Number webhook registrations. |
| `raw` | Any API path. |

The [API reference](/api/overview) documents every endpoint behind these
methods.


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