npm package: @framemesh/sdk
Description: Official TypeScript SDK for the Framemesh cloud platform API
Latest version: 0.3.0

# @framemesh/sdk

Official TypeScript SDK for the Framemesh cloud platform API. Provides a typed, ergonomic interface to manage compute, databases, storage, networking, apps, streaming, billing, and more.

- Full TypeScript types for all resources and requests
- Automatic pagination with async iteration
- Built-in retry with exponential backoff
- Typed error classes for precise error handling
- Works in Node.js, Deno, Bun, and edge runtimes (uses standard `fetch`)

## Installation

```bash
npm install @framemesh/sdk
# or
pnpm add @framemesh/sdk
# or
yarn add @framemesh/sdk
```

Requires Node.js >= 20.

## Quick Start

```ts
import { Framemesh } from '@framemesh/sdk';

const fm = new Framemesh({ apiKey: 'fm_your_api_key' });

// List all organizations
const orgs = await fm.orgs.list();
console.log(orgs.data);

// Create a VM
const vm = await fm.compute.vms.create('my-org', 'my-project', {
  name: 'web-1',
  flavorId: 'c1.medium',
  imageId: 'ubuntu-24.04',
  networkIds: ['net-1'],
  securityGroupIds: ['sg-default'],
  sshKeyIds: ['my-key'],
});
```

## Authentication

The SDK supports two authentication methods:

**API Key** (recommended for server-side use):

```ts
const fm = new Framemesh({ apiKey: 'fm_your_api_key' });
```

**JWT Access Token** (for browser/session-based auth):

```ts
const fm = new Framemesh({ accessToken: 'eyJhbGci...' });
```

When both `apiKey` and `accessToken` are provided, `accessToken` takes precedence.

**Environment variables:** While the SDK itself does not read environment variables, the CLI reads `FRAMEMESH_API_KEY` and `FRAMEMESH_API_URL`. In your own code you can do:

```ts
const fm = new Framemesh({
  apiKey: process.env.FRAMEMESH_API_KEY,
});
```

## Client Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `apiKey` | `string` | -- | API key (prefixed with `fm_`). |
| `accessToken` | `string` | -- | JWT access token. Takes precedence over `apiKey`. |
| `baseUrl` | `string` | `https://api.framemesh.cloud/api/v1` | Base URL for the API. |
| `fetch` | `typeof fetch` | `globalThis.fetch` | Custom fetch implementation. |
| `timeout` | `number` | `30000` | Request timeout in milliseconds. |
| `maxRetries` | `number` | `2` | Max automatic retries on transient errors (429, 500, 502, 503). |

## Services

All resources are accessed through properties on the `Framemesh` client instance:

| Property | Resource | Scope |
|----------|----------|-------|
| `fm.orgs` | Organizations | Global |
| `fm.projects` | Projects | Per org |
| `fm.compute.vms` | Virtual Machines | Per project |
| `fm.compute.flavors` | VM Flavors (sizes) | Per project |
| `fm.compute.images` | OS Images | Per project |
| `fm.databases` | Managed Databases | Per project |
| `fm.storage.volumes` | Block Storage Volumes | Per project |
| `fm.storage.buckets` | Object Storage Buckets | Per project |
| `fm.storage.s3Credentials` | S3 API Credentials | Per project |
| `fm.network.networks` | Private Networks | Per project |
| `fm.network.floatingIPs` | Floating IPs | Per project |
| `fm.network.securityGroups` | Security Groups | Per project |
| `fm.network.loadBalancers` | Load Balancers | Per project |
| `fm.apps` | PaaS Applications | Per project |
| `fm.gitProviders` | Git Provider Integrations | Per org |
| `fm.streams` | Live Streams | Per project |
| `fm.billing.invoices` | Invoices | Per org |
| `fm.billing.paymentMethods` | Payment Methods | Per org |
| `fm.billing.settings` | Billing Settings | Per org |
| `fm.usage` | Resource Usage / Metering | Per project |
| `fm.audit` | Audit Logs | Per org |
| `fm.notifications` | Notifications & Webhooks | Per org |

**Scope conventions:** Most project-scoped methods take `(org, project, ...)` as the first two parameters. Org-scoped methods take `(org, ...)`.

---

## Usage Examples

### Organizations & Projects

```ts
// List organizations
const orgs = await fm.orgs.list();

// Create an organization
const org = await fm.orgs.create({ name: 'Acme Corp' });

// Get a specific org
const acme = await fm.orgs.get('acme-corp');

// Update an org
await fm.orgs.update('acme-corp', { description: 'Updated description' });

// Delete an org
await fm.orgs.delete('acme-corp');

// Manage org members
const members = await fm.orgs.members.list('acme-corp');
await fm.orgs.members.add('acme-corp', { email: 'alice@example.com', role: 'admin' });
await fm.orgs.members.update('acme-corp', memberId, { role: 'member' });
await fm.orgs.members.remove('acme-corp', memberId);
```

```ts
// List projects in an org
const projects = await fm.projects.list('acme-corp');

// Create a project
const project = await fm.projects.create('acme-corp', { name: 'Production' });

// Get, update, delete
const prod = await fm.projects.get('acme-corp', 'production');
await fm.projects.update('acme-corp', 'production', { description: 'Prod env' });
await fm.projects.delete('acme-corp', 'production');

// Project members
const projectMembers = await fm.projects.members.list('acme-corp', 'production');
await fm.projects.members.add('acme-corp', 'production', { email: 'bob@example.com', role: 'developer' });
```

### Compute (VMs, Flavors, Images)

```ts
const org = 'acme-corp';
const project = 'production';

// List VMs
const vms = await fm.compute.vms.list(org, project);

// Create a VM
const vm = await fm.compute.vms.create(org, project, {
  name: 'web-1',
  flavorId: 'c1.medium',
  imageId: 'ubuntu-24.04',
  networkIds: ['net-1'],
  securityGroupIds: ['sg-default'],
  sshKeyIds: ['my-key'],
  volumeSize: 50,
});

// Get a VM
const myVm = await fm.compute.vms.get(org, project, vm.id);

// Perform actions: start, stop, reboot
await fm.compute.vms.performAction(org, project, vm.id, 'stop');
await fm.compute.vms.performAction(org, project, vm.id, 'start');
await fm.compute.vms.performAction(org, project, vm.id, 'reboot');

// Get VNC console URL
const console = await fm.compute.vms.console(org, project, vm.id);
console.log(console.url);

// Update and delete
await fm.compute.vms.update(org, project, vm.id, { name: 'web-1-renamed' });
await fm.compute.vms.delete(org, project, vm.id);

// List available flavors and images
const flavors = await fm.compute.flavors.list(org, project);
const images = await fm.compute.images.list(org, project);
```

### Databases

```ts
// List databases
const dbs = await fm.databases.list(org, project);

// Create a PostgreSQL database
const db = await fm.databases.create(org, project, {
  name: 'main-db',
  engine: 'postgresql',
  version: '16',
  planId: 'medium',
});

// Get connection info (host, port, credentials, connection string)
const connInfo = await fm.databases.connectionInfo(org, project, db.id);
console.log(connInfo.connectionString);

// List available plans and versions
const plans = await fm.databases.listPlans(org, project);
const versions = await fm.databases.listVersions(org, project);

// Backup management
const backups = await fm.databases.backups.list(org, project, db.id);
const backup = await fm.databases.backups.create(org, project, db.id);
await fm.databases.backups.restore(org, project, db.id, backup.id);

// Update and delete
await fm.databases.update(org, project, db.id, { planId: 'large' });
await fm.databases.delete(org, project, db.id);
```

### Storage (Volumes, Buckets, S3 Credentials)

```ts
// --- Volumes ---
const volumes = await fm.storage.volumes.list(org, project);

const vol = await fm.storage.volumes.create(org, project, {
  name: 'data-vol',
  sizeGb: 100,
  storageClass: 'ssd',
  encrypted: true,
});

// Attach/detach to a VM
await fm.storage.volumes.attach(org, project, vol.id, vmId);
await fm.storage.volumes.detach(org, project, vol.id);

// Volume metrics and storage classes
const metrics = await fm.storage.volumes.metrics(org, project, vol.id);
const classes = await fm.storage.volumes.listStorageClasses(org, project);

// Snapshots
const snapshot = await fm.storage.volumes.snapshots.create(org, project, vol.id, {
  name: 'before-upgrade',
});
const snapshots = await fm.storage.volumes.snapshots.list(org, project, vol.id);
await fm.storage.volumes.snapshots.delete(org, project, vol.id, snapshot.id);

// --- Buckets ---
const buckets = await fm.storage.buckets.list(org, project);

const bucket = await fm.storage.buckets.create(org, project, {
  name: 'assets',
  versioning: true,
});

// List objects in a bucket
const objects = await fm.storage.buckets.listObjects(org, project, bucket.id, {
  prefix: 'images/',
});

// Delete an object
await fm.storage.buckets.deleteObject(org, project, bucket.id, 'images/old-logo.png');

// --- S3 Credentials ---
// Secret is only returned on creation
const creds = await fm.storage.s3Credentials.create(org, project, {
  name: 'ci-pipeline',
});
console.log(creds.accessKey, creds.secretKey);

const allCreds = await fm.storage.s3Credentials.list(org, project);
await fm.storage.s3Credentials.delete(org, project, creds.id);
```

### Apps (PaaS)

```ts
// List apps
const apps = await fm.apps.list(org, project);

// Create an app
const app = await fm.apps.create(org, project, {
  name: 'my-api',
  description: 'REST API service',
  port: 8080,
});

// Trigger a deployment
const deployment = await fm.apps.deploy(org, project, app.id, { branch: 'main' });

// List deployments
const deployments = await fm.apps.deployments.list(org, project, app.id);

// Cancel or rollback a deployment
await fm.apps.deployments.cancel(org, project, app.id, deployment.id);
await fm.apps.deployments.rollback(org, project, app.id, previousDeploymentId);

// Environment variables
const envVars = await fm.apps.envVars.list(org, project, app.id);
await fm.apps.envVars.set(org, project, app.id, { key: 'DATABASE_URL', value: '...' });
await fm.apps.envVars.delete(org, project, app.id, envVarId);

// Custom domains
const domains = await fm.apps.domains.list(org, project, app.id);
const domain = await fm.apps.domains.add(org, project, app.id, { domain: 'api.example.com' });
await fm.apps.domains.verify(org, project, app.id, domain.id);
await fm.apps.domains.remove(org, project, app.id, domain.id);

// Branches and environments
const branches = await fm.apps.listBranches(org, project, app.id);
const environments = await fm.apps.environments.list(org, project, app.id);
```

```ts
// Git provider integrations (org-scoped)
const providers = await fm.gitProviders.list('acme-corp');
const provider = await fm.gitProviders.create('acme-corp', {
  type: 'github',
  token: 'ghp_...',
  name: 'GitHub',
});

// List repos and branches from a provider
const repos = await fm.gitProviders.listRepos('acme-corp', provider.id);
const branches = await fm.gitProviders.listBranches('acme-corp', provider.id, 'owner/repo');
```

### Streaming

```ts
// Create a stream
const stream = await fm.streams.create(org, project, {
  name: 'live-event',
  authMode: 'ingest_only',
  recordEnabled: true,
});

// Stream URLs are returned:
// stream.rtmpUrl  -- RTMP ingest
// stream.whipUrl  -- WebRTC ingest (WHIP)
// stream.hlsUrl   -- HLS playback
// stream.whepUrl  -- WebRTC playback (WHEP)
// stream.streamKey -- Use with RTMP/WHIP

// Auth modes:
//   'open'         -- No auth required
//   'ingest_only'  -- Stream key required for ingest, open playback
//   'egress_only'  -- Open ingest, viewer token required for playback
//   'all'          -- Stream key + viewer token required
//   'disabled'     -- Stream is disabled

// Reset stream key
await fm.streams.resetKey(org, project, stream.id);

// Recordings
const recordings = await fm.streams.recordings.list(org, project, stream.id);
const recording = await fm.streams.recordings.get(org, project, stream.id, recordingId);
await fm.streams.recordings.delete(org, project, stream.id, recordingId);
```

### Network (Networks, Floating IPs, Security Groups, Load Balancers)

```ts
// --- Private Networks ---
const networks = await fm.network.networks.list(org, project);
const net = await fm.network.networks.create(org, project, {
  name: 'internal',
  cidr: '10.0.0.0/24',
});
await fm.network.networks.delete(org, project, net.id);

// --- Floating IPs ---
const fip = await fm.network.floatingIPs.allocate(org, project);
await fm.network.floatingIPs.associate(org, project, fip.id, { instanceId: vmId });
await fm.network.floatingIPs.disassociate(org, project, fip.id);
await fm.network.floatingIPs.release(org, project, fip.id);

// --- Security Groups ---
const sg = await fm.network.securityGroups.create(org, project, {
  name: 'web-servers',
  description: 'Allow HTTP/HTTPS',
});
await fm.network.securityGroups.rules.create(org, project, sg.id, {
  direction: 'ingress',
  protocol: 'tcp',
  portRangeMin: 443,
  portRangeMax: 443,
  remoteIpPrefix: '0.0.0.0/0',
});

// --- Load Balancers ---
const lb = await fm.network.loadBalancers.create(org, project, {
  name: 'web-lb',
  networkId: net.id,
});

// Listeners, pools, members, health monitors
await fm.network.loadBalancers.listeners.create(org, project, lb.id, {
  protocol: 'HTTP',
  port: 80,
});
await fm.network.loadBalancers.pools.create(org, project, lb.id, {
  protocol: 'HTTP',
  lbAlgorithm: 'ROUND_ROBIN',
});
await fm.network.loadBalancers.pools.members.create(org, project, lb.id, poolId, {
  address: '10.0.0.5',
  port: 8080,
});
await fm.network.loadBalancers.pools.healthMonitors.create(org, project, lb.id, poolId, {
  type: 'HTTP',
  delay: 10,
  timeout: 5,
  maxRetries: 3,
});
```

### Billing

```ts
// Invoices
const invoices = await fm.billing.invoices.list('acme-corp');
const invoice = await fm.billing.invoices.get('acme-corp', invoiceId);

// Payment methods
const methods = await fm.billing.paymentMethods.list('acme-corp');
const method = await fm.billing.paymentMethods.create('acme-corp', { type: 'card', token: '...' });
await fm.billing.paymentMethods.setDefault('acme-corp', method.id);
await fm.billing.paymentMethods.delete('acme-corp', method.id);

// Billing settings
const settings = await fm.billing.settings.get('acme-corp');
await fm.billing.settings.update('acme-corp', { vatId: 'DE123456789' });
```

### Usage / Metering

```ts
const usage = await fm.usage.summary(org, project, {
  startDate: '2026-01-01',
  endDate: '2026-01-31',
  granularity: 'daily',
});
```

### Audit Logs

```ts
const logs = await fm.audit.list('acme-corp', { action: 'create', resourceType: 'vm' });
const entry = await fm.audit.get('acme-corp', logEntryId);
const summary = await fm.audit.summary('acme-corp', { startDate: '2026-01-01' });

// Exports
const exp = await fm.audit.exports.create('acme-corp', { format: 'csv' });
const exports = await fm.audit.exports.list('acme-corp');

// Retention policy
const policy = await fm.audit.retention.get('acme-corp');
await fm.audit.retention.update('acme-corp', { retentionDays: 365, archiveEnabled: true });
```

### Notifications & Webhooks

```ts
const notifications = await fm.notifications.list('acme-corp');
const stats = await fm.notifications.stats('acme-corp');

// Webhooks
const webhook = await fm.notifications.webhooks.create('acme-corp', {
  url: 'https://example.com/webhook',
  events: ['vm.created', 'vm.deleted'],
});
await fm.notifications.webhooks.test('acme-corp', webhook.id);
const deliveries = await fm.notifications.webhooks.deliveries('acme-corp', webhook.id);

// Alert rules
const alert = await fm.notifications.alerts.create('acme-corp', {
  name: 'High CPU',
  condition: { metric: 'cpu_usage', operator: 'gt', threshold: 90 },
  actions: [{ type: 'webhook', webhookId: webhook.id }],
});

// Preferences
const prefs = await fm.notifications.preferences.get('acme-corp');
await fm.notifications.preferences.update('acme-corp', { emailEnabled: true });
```

---

## Pagination

All `list` methods return a `Page<T>` object that supports manual navigation and automatic async iteration.

### Page properties and methods

```ts
const page = await fm.compute.vms.list(org, project, { page: 1, perPage: 10 });

page.data          // T[] -- items on the current page
page.meta          // { page, perPage, total, totalPages }
page.hasNextPage()
page.hasPreviousPage()
await page.getNextPage()
await page.getPreviousPage()
```

### Async iteration (auto-paginate)

```ts
// Iterate over all VMs across all pages
for await (const vm of fm.compute.vms.list(org, project)) {
  console.log(vm.name, vm.status);
}
```

### Collect all items into an array

```ts
const allVMs = await fm.compute.vms.list(org, project).then(p => p.toArray());

// With a cap
const first100 = await fm.compute.vms.list(org, project).then(p => p.toArray({ maxItems: 100 }));
```

---

## Error Handling

The SDK throws typed errors that extend `FramemeshError`. Use `instanceof` to handle specific cases:

```ts
import { Framemesh, NotFoundError, RateLimitError, AuthenticationError } from '@framemesh/sdk';

try {
  const vm = await fm.compute.vms.get(org, project, 'nonexistent');
} catch (err) {
  if (err instanceof NotFoundError) {
    console.log('VM not found');
  } else if (err instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${err.retryAfter}s`);
  } else if (err instanceof AuthenticationError) {
    console.log('Invalid credentials');
  }
}
```

Errors can also be accessed as static properties on the class:

```ts
const fm = new Framemesh({ apiKey: '...' });

// These are equivalent:
err instanceof NotFoundError
err instanceof Framemesh.NotFoundError
```

### Error hierarchy

| Class | Status | Description |
|-------|--------|-------------|
| `FramemeshError` | -- | Base class for all errors. |
| `BadRequestError` | 400 | Validation errors. Has `details?: Record<string, string[]>`. |
| `AuthenticationError` | 401 | Missing or invalid credentials. |
| `ForbiddenError` | 403 | Valid credentials but insufficient permissions. |
| `NotFoundError` | 404 | Resource does not exist. |
| `ConflictError` | 409 | Resource already exists or state conflict. |
| `RateLimitError` | 429 | Rate limit exceeded. Has `retryAfter?: number` (seconds). |
| `InternalError` | 500+ | Server-side failure. |
| `ConnectionError` | -- | Network-level error (DNS, refused, etc.). |
| `TimeoutError` | -- | Request exceeded the timeout. |

### Error properties

All errors have these properties:

```ts
err.message    // string -- human-readable message
err.statusCode // number -- HTTP status code (0 for network/timeout errors)
err.code       // string -- machine-readable error code
err.requestId  // string | undefined -- server request ID for support
```

---

## TypeScript

All types are exported from the package root:

```ts
import type {
  VM,
  CreateVMRequest,
  Database,
  CreateDatabaseRequest,
  Organization,
  Page,
  PageMeta,
  PaginationParams,
  ClientOptions,
} from '@framemesh/sdk';
```

See the full list of exported types in [`src/index.ts`](./src/index.ts).

---

## Advanced

### Custom fetch implementation

Useful for testing, logging, or environments without a global `fetch`:

```ts
import { Framemesh } from '@framemesh/sdk';
import nodeFetch from 'node-fetch';

const fm = new Framemesh({
  apiKey: 'fm_...',
  fetch: nodeFetch as unknown as typeof fetch,
});
```

### Timeout and retries

```ts
const fm = new Framemesh({
  apiKey: 'fm_...',
  timeout: 60_000,     // 60 seconds
  maxRetries: 5,       // Retry up to 5 times
});
```

Retries use exponential backoff (500ms, 1s, 2s, ..., max 10s). On 429 responses with a `Retry-After` header, the SDK respects the server-specified delay.

### Request cancellation

```ts
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);

// Pass signal via the underlying client (advanced usage)
```

---

## API Reference

### `fm.orgs`

| Method | Description |
|--------|-------------|
| `list(params?)` | List organizations. |
| `get(slug)` | Get an org by slug. |
| `create(data)` | Create an org. |
| `update(slug, data)` | Update an org. |
| `delete(slug)` | Delete an org. |
| `members.list(orgSlug, params?)` | List org members. |
| `members.add(orgSlug, data)` | Add a member. |
| `members.update(orgSlug, memberId, data)` | Update a member's role. |
| `members.remove(orgSlug, memberId)` | Remove a member. |

### `fm.projects`

| Method | Description |
|--------|-------------|
| `list(orgSlug, params?)` | List projects in an org. |
| `get(orgSlug, slug)` | Get a project by slug. |
| `create(orgSlug, data)` | Create a project. |
| `update(orgSlug, slug, data)` | Update a project. |
| `delete(orgSlug, slug)` | Delete a project. |
| `members.list(orgSlug, projectSlug, params?)` | List project members. |
| `members.add(orgSlug, projectSlug, data)` | Add a member. |
| `members.update(orgSlug, projectSlug, memberId, data)` | Update a member's role. |
| `members.remove(orgSlug, projectSlug, memberId)` | Remove a member. |

### `fm.compute.vms`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List VMs. |
| `get(org, project, id)` | Get a VM. |
| `create(org, project, data)` | Create a VM. |
| `update(org, project, id, data)` | Update a VM. |
| `delete(org, project, id)` | Delete a VM. |
| `performAction(org, project, id, action)` | Start, stop, reboot, etc. |
| `console(org, project, id)` | Get VNC/SPICE console URL. |

### `fm.compute.flavors`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List available VM flavors. |
| `get(org, project, id)` | Get a flavor. |

### `fm.compute.images`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List available OS images. |
| `get(org, project, id)` | Get an image. |

### `fm.databases`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List databases. |
| `get(org, project, id)` | Get a database. |
| `create(org, project, data)` | Create a database. |
| `update(org, project, id, data)` | Update a database. |
| `delete(org, project, id)` | Delete a database. |
| `connectionInfo(org, project, id)` | Get connection details. |
| `listPlans(org, project, params?)` | List available plans. |
| `listVersions(org, project)` | List available engine versions. |
| `backups.list(org, project, dbId, params?)` | List backups. |
| `backups.create(org, project, dbId)` | Create a manual backup. |
| `backups.get(org, project, dbId, backupId)` | Get a backup. |
| `backups.restore(org, project, dbId, backupId)` | Restore from a backup. |

### `fm.storage.volumes`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List volumes. |
| `get(org, project, id)` | Get a volume. |
| `create(org, project, data)` | Create a volume. |
| `update(org, project, id, data)` | Update a volume. |
| `delete(org, project, id)` | Delete a volume. |
| `attach(org, project, id, vmId)` | Attach to a VM. |
| `detach(org, project, id)` | Detach from a VM. |
| `metrics(org, project, id)` | Get performance metrics. |
| `listStorageClasses(org, project)` | List available storage classes. |
| `snapshots.list(org, project, volumeId, params?)` | List snapshots. |
| `snapshots.create(org, project, volumeId, data)` | Create a snapshot. |
| `snapshots.get(org, project, volumeId, snapshotId)` | Get a snapshot. |
| `snapshots.delete(org, project, volumeId, snapshotId)` | Delete a snapshot. |

### `fm.storage.buckets`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List buckets. |
| `get(org, project, id)` | Get a bucket. |
| `create(org, project, data)` | Create a bucket. |
| `update(org, project, id, data)` | Update a bucket. |
| `delete(org, project, id)` | Delete a bucket. |
| `listObjects(org, project, id, params?)` | List objects (supports `prefix`, `delimiter`). |
| `deleteObject(org, project, bucketId, key)` | Delete an object. |

### `fm.storage.s3Credentials`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List S3 credentials. |
| `get(org, project, id)` | Get credentials. |
| `create(org, project, data)` | Create credentials (secret shown once). |
| `delete(org, project, id)` | Delete credentials. |

### `fm.network.networks`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List networks. |
| `get(org, project, id)` | Get a network. |
| `create(org, project, data)` | Create a network. |
| `update(org, project, id, data)` | Update a network. |
| `delete(org, project, id)` | Delete a network. |

### `fm.network.floatingIPs`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List floating IPs. |
| `get(org, project, id)` | Get a floating IP. |
| `allocate(org, project, data?)` | Allocate a floating IP. |
| `release(org, project, id)` | Release a floating IP. |
| `associate(org, project, id, data)` | Associate with a port/instance. |
| `disassociate(org, project, id)` | Disassociate. |

### `fm.network.securityGroups`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List security groups. |
| `get(org, project, id)` | Get a security group. |
| `create(org, project, data)` | Create a security group. |
| `delete(org, project, id)` | Delete a security group. |
| `rules.create(org, project, sgId, data)` | Add a rule. |
| `rules.delete(org, project, sgId, ruleId)` | Delete a rule. |

### `fm.network.loadBalancers`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List load balancers. |
| `get(org, project, id)` | Get a load balancer. |
| `create(org, project, data)` | Create a load balancer. |
| `delete(org, project, id)` | Delete a load balancer. |
| `listeners.list(org, project, lbId)` | List listeners. |
| `listeners.create(org, project, lbId, data)` | Create a listener. |
| `listeners.delete(org, project, lbId, listenerId)` | Delete a listener. |
| `pools.list(org, project, lbId)` | List pools. |
| `pools.create(org, project, lbId, data)` | Create a pool. |
| `pools.delete(org, project, lbId, poolId)` | Delete a pool. |
| `pools.members.create(org, project, lbId, poolId, data)` | Add a pool member. |
| `pools.members.delete(org, project, lbId, poolId, memberId)` | Remove a pool member. |
| `pools.healthMonitors.get(org, project, lbId, poolId)` | Get health monitor. |
| `pools.healthMonitors.create(org, project, lbId, poolId, data)` | Create health monitor. |
| `pools.healthMonitors.delete(org, project, lbId, poolId)` | Delete health monitor. |

### `fm.apps`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List apps. |
| `get(org, project, id)` | Get an app. |
| `create(org, project, data)` | Create an app. |
| `update(org, project, id, data)` | Update an app. |
| `delete(org, project, id)` | Delete an app. |
| `deploy(org, project, id, data?)` | Trigger a deployment. |
| `listBranches(org, project, id)` | List branch summaries. |
| `envVars.list(org, project, appId)` | List env vars. |
| `envVars.set(org, project, appId, data)` | Set an env var. |
| `envVars.delete(org, project, appId, envVarId)` | Delete an env var. |
| `domains.list(org, project, appId)` | List custom domains. |
| `domains.add(org, project, appId, data)` | Add a domain. |
| `domains.remove(org, project, appId, domainId)` | Remove a domain. |
| `domains.verify(org, project, appId, domainId)` | Verify DNS. |
| `deployments.list(org, project, appId, params?)` | List deployments. |
| `deployments.get(org, project, appId, deploymentId)` | Get a deployment. |
| `deployments.cancel(org, project, appId, deploymentId)` | Cancel a deployment. |
| `deployments.rollback(org, project, appId, deploymentId)` | Rollback to a deployment. |
| `environments.list(org, project, appId)` | List environments. |
| `environments.get(org, project, appId, envId)` | Get an environment. |

### `fm.gitProviders`

| Method | Description |
|--------|-------------|
| `list(org, params?)` | List Git providers. |
| `get(org, id)` | Get a Git provider. |
| `create(org, data)` | Create a Git provider connection. |
| `delete(org, id)` | Delete a Git provider. |
| `listRepos(org, id)` | List repos from a provider. |
| `listBranches(org, id, repoFullName)` | List branches for a repo. |

### `fm.streams`

| Method | Description |
|--------|-------------|
| `list(org, project, params?)` | List streams. |
| `get(org, project, id)` | Get a stream. |
| `create(org, project, data)` | Create a stream. |
| `update(org, project, id, data)` | Update a stream. |
| `delete(org, project, id)` | Delete a stream. |
| `resetKey(org, project, id)` | Reset the stream key. |
| `recordings.list(org, project, streamId, params?)` | List recordings. |
| `recordings.get(org, project, streamId, recordingId)` | Get a recording. |
| `recordings.delete(org, project, streamId, recordingId)` | Delete a recording. |

### `fm.billing.invoices`

| Method | Description |
|--------|-------------|
| `list(org, params?)` | List invoices. |
| `get(org, id)` | Get an invoice. |

### `fm.billing.paymentMethods`

| Method | Description |
|--------|-------------|
| `list(org, params?)` | List payment methods. |
| `get(org, id)` | Get a payment method. |
| `create(org, data)` | Add a payment method. |
| `delete(org, id)` | Delete a payment method. |
| `setDefault(org, id)` | Set as default. |

### `fm.billing.settings`

| Method | Description |
|--------|-------------|
| `get(org)` | Get billing settings. |
| `update(org, data)` | Update billing settings. |

### `fm.usage`

| Method | Description |
|--------|-------------|
| `summary(org, project, params?)` | Get usage summary. Accepts `startDate`, `endDate`, `granularity`. |

### `fm.audit`

| Method | Description |
|--------|-------------|
| `list(org, params?)` | List audit log entries (supports filters). |
| `get(org, id)` | Get a log entry. |
| `summary(org, params?)` | Get aggregated audit summary. |
| `exports.create(org, data)` | Request an export. |
| `exports.get(org, exportId)` | Get export status. |
| `exports.list(org, params?)` | List exports. |
| `retention.get(org)` | Get retention policy. |
| `retention.update(org, data)` | Update retention policy. |

### `fm.notifications`

| Method | Description |
|--------|-------------|
| `list(org, params?)` | List notifications. |
| `get(org, id)` | Get a notification. |
| `stats(org)` | Get notification statistics. |
| `webhooks.list(org, params?)` | List webhook endpoints. |
| `webhooks.get(org, id)` | Get a webhook. |
| `webhooks.create(org, data)` | Create a webhook. |
| `webhooks.update(org, id, data)` | Update a webhook. |
| `webhooks.delete(org, id)` | Delete a webhook. |
| `webhooks.deliveries(org, webhookId, params?)` | List deliveries. |
| `webhooks.test(org, id)` | Test a webhook. |
| `alerts.list(org, params?)` | List alert rules. |
| `alerts.get(org, id)` | Get an alert rule. |
| `alerts.create(org, data)` | Create an alert rule. |
| `alerts.update(org, id, data)` | Update an alert rule. |
| `alerts.delete(org, id)` | Delete an alert rule. |
| `preferences.get(org)` | Get notification preferences. |
| `preferences.update(org, data)` | Update preferences. |

## License

MIT