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

# Node SDK

> The typed TypeScript client for the Platform API

`@synthetiq/platform-sdk` is the official Node/TypeScript client for the Platform API. It's the same library the [CLI](/docs/platform-docs/cli/overview) is built on, so anything the CLI does, you can script. Every REST resource in this section has a typed accessor on the client.

## Install

The SDK ships from the same private registry as the CLI — see [CLI installation](/docs/platform-docs/cli/overview#installation) for the registry/auth setup, then:

```bash theme={null}
npm install @synthetiq/platform-sdk
```

## Instantiate

```ts theme={null}
import { SynthetiqClient } from "@synthetiq/platform-sdk";

const sdk = new SynthetiqClient({
  baseUrl: "https://api.synthetiq.com/api",
  // Called before every request — you own credential storage and refresh.
  getAccessToken: () => process.env.SYNTHETIQ_TOKEN!,
});
```

| Option           | Required | Description                                                         |
| ---------------- | -------- | ------------------------------------------------------------------- |
| `baseUrl`        | Yes      | Platform API base, including `/api`                                 |
| `getAccessToken` | Yes      | Sync or async function returning a bearer token before each request |
| `extraHeaders`   | No       | Headers sent on every request                                       |
| `fetch`          | No       | Override `fetch` (tests, instrumentation)                           |

`getAccessToken` is a callback so the SDK never owns credentials: the CLI reads its credentials file, the desktop app its session, and CI does an OIDC token exchange.

## Resource accessors

Each accessor maps to a resource in this section:

| Accessor                                     | Resource                                                                                            |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `sdk.me`                                     | [Current user](/docs/platform-docs/platform-api/authentication#current-user)                             |
| `sdk.organizations`                          | [Organizations](/docs/platform-docs/platform-api/organizations)                                          |
| `sdk.members`, `sdk.roles`, `sdk.scopes`     | [Members & roles](/docs/platform-docs/platform-api/members-and-roles)                                    |
| `sdk.serviceAccounts`, `sdk.oidcTrusts`      | [Service accounts & OIDC trusts](/docs/platform-docs/platform-api/service-accounts)                      |
| `sdk.awsConfig`                              | [Deployment infrastructure (BYOI)](/docs/platform-docs/platform-api/aws-config)                          |
| `sdk.storageConfig`                          | [Organizations](/docs/platform-docs/platform-api/organizations) (storage config)                         |
| `sdk.entities`                               | [Entities](/docs/platform-docs/platform-api/entities) & [Versions](/docs/platform-docs/platform-api/versions) |
| `sdk.prdComments`                            | [PRD comments](/docs/platform-docs/platform-api/prd-comments)                                            |
| `sdk.shares`, `sdk.publishers`, `sdk.stores` | [Sharing](/docs/platform-docs/platform-api/sharing)                                                      |
| `sdk.productionApps`                         | [Production apps](/docs/platform-docs/platform-api/production-apps)                                      |
| `sdk.deploys`                                | [Deployments](/docs/platform-docs/platform-api/deployments)                                              |

## Example

```ts theme={null}
// Check your own permissions before attempting a scoped operation.
const me = await sdk.me.get();
if (!me.organization?.scopes.some((s) => s.key === "entities:deploy")) {
  throw new Error(`${me.organization?.role.name ?? "no"} role cannot deploy`);
}

// List an org's deployment targets, then trigger a deploy.
const { configs } = await sdk.awsConfig.list(orgId);

const deployment = await sdk.deploys.create({
  productionAppId: app.id,
  versionId: version.id,
});
console.log(deployment.status);
```

Setting an avatar is a three-step flow — request a signed URL, upload the bytes,
point the profile at it — wrapped in one call:

```ts theme={null}
import fs from "fs";

const profile = await sdk.me.uploadAvatar(fs.readFileSync("me.png"), "png");
console.log(profile.avatar_url);

// Revert to whatever picture your identity provider supplies.
await sdk.me.clearAvatar();
```

`uploadAvatar` sends back the exact `publicUrl` the API issued. The API only
accepts avatar URLs it issued for that user, so a reconstructed URL is rejected.

## Error handling

Failed requests throw `SynthetiqApiError` with the HTTP `status` and the API's `error` message. When the API returns a coded error, the machine-readable `code` and the parsed response `body` are on the error as well:

```ts theme={null}
import { SynthetiqApiError } from "@synthetiq/platform-sdk";

try {
  await sdk.organizations.get(orgId);
} catch (err) {
  if (err instanceof SynthetiqApiError && err.status === 403) {
    // missing scope — see Authentication
  }
}
```

Authorization is enforced per-resource; see [Authentication](/docs/platform-docs/platform-api/authentication) for the scope model.
