# TypeScript SDK

```bash
npm install @ozma_app/sdk
```

**npm:** published **v0.1.0** (2026-07-07). In-repo version is **0.2.0+** with additional methods — pin to published release for stability or build from monorepo for latest.

## Quick start

```typescript
import { OzmaClient } from "@ozma_app/sdk";

const client = new OzmaClient({
  baseUrl: "https://api.ozma.app",
  apiKey: process.env.OZMA_API_KEY,
  sessionToken: process.env.OZMA_SESSION_TOKEN, // optional; wins over apiKey on control plane
  gatewayUrl: "https://gateway.ozma.app",       // optional; auto-derived from baseUrl
});

const { data } = await client.search({ q: "weather", sort: "relevance" });
```

## OzmaClientOptions

| Field | Description |
|-------|-------------|
| `baseUrl` | Control plane (`https://api.ozma.app`) |
| `apiKey` | Optional `ozma_live_*` |
| `sessionToken` | Optional session — **preferred over apiKey** for control-plane auth |
| `gatewayUrl` | Gateway base; defaults to `baseUrl` with `api.` → `gateway.` rewrite |
| `timeoutMs` | Request timeout (default 30_000) |

## Types

**SearchSort:** `ozma_score` | `price` | `relevance` | `new` | `calls` | `gmv` | `reliability` | `value` | `momentum`

All control-plane methods return `Promise<ApiResponse<T>>` (Ozma envelope).

## Method table

| Method | HTTP | Description |
|--------|------|-------------|
| `health()` | `GET /health` | Service status |
| `register()` | `POST /v1/register` | Auto-register → key, 0 credits |
| `getMe()` | `GET /v1/me` | Org + credits |
| `listProviders(opts?)` | `GET /v1/providers` | Provider directory |
| `getProviderProfile(slug)` | `GET /v1/providers/:slug` | Public profile |
| `getMyProfile()` | `GET /v1/me/profile` | Own profile |
| `updateMyProfile(patch)` | `PATCH /v1/me/profile` | Update profile |
| `verifyEmail({ token })` | `POST /v1/auth/verify-email` | Email verify |
| `search({ q?, category?, sort?, limit?, offset? })` | `GET /v1/search` | Catalog search |
| `categories()` | `GET /v1/categories` | Categories |
| `getApi(slug)` | `GET /v1/apis/:slug` | Listing detail |
| `getSchema(slug)` | `GET /v1/apis/:slug/schema` | Schemas |
| `getEndpoints(slug)` | `GET /v1/apis/:slug/endpoints` | Endpoint rows |
| `getApiStats(slug, window?)` | `GET /v1/apis/:slug/stats` | Stats rollup |
| `getApiHistory(slug, limit?)` | `GET /v1/apis/:slug/history` | Score history |
| `getApiRanks(slug)` | `GET /v1/apis/:slug/ranks` | Board ranks |
| `getLeaderboard(board, category?)` | `GET /v1/leaderboards/:board` | Leaderboard |
| `getMarketOverview()` | `GET /v1/market/overview` | Market totals |
| `getMarketActivity({ limit? })` | `GET /v1/market/activity` | Activity feed (auth) |
| `createKey({ name, scopes?, budget_cents? })` | `POST /v1/keys` | Mint key |
| `listKeys()` | `GET /v1/keys` | List keys |
| `revokeKey(id)` | `DELETE /v1/keys/:id` | Revoke |
| `patchKey(id, caps)` | `PATCH /v1/keys/:id` | Budget / daily cap / per-call max |
| `getUsage({ from?, to? })` | `GET /v1/usage` | Usage |
| `getBillingPacks()` | `GET /v1/billing/packs` | Packs |
| `getBalance()` | `GET /v1/billing/balance` | Balance |
| `createCheckout(opts)` | `POST /v1/billing/checkout` | Checkout URL |
| `createSetupIntent()` | `POST /v1/billing/setup-intent` | SetupIntent |
| `createPortalSession()` | `POST /v1/billing/portal` | Portal URL |
| `configureAutoReload(opts)` | `POST /v1/billing/auto-reload` | Auto-reload |
| `proxyCall(apiSlug, path, method, body?)` | Gateway `ALL /v1/proxy/…` | Billed proxy call |
| `getApiTerms(slug)` | `GET /v1/apis/:slug/terms` | Provider terms |
| `acceptApiTerms(slug, { documentId, contentHash })` | `POST …/terms/accept` | Accept terms (session) |
| `providerCreateApi(body)` | `POST /v1/provider/apis` | Create draft |
| `providerListApis()` | `GET /v1/provider/apis` | List APIs |
| `providerVerify(apiId)` | `POST …/verify` | Smoke test |
| `providerPublish(apiId, { acceptTerms, skipVerify? })` | `POST …/publish` | Publish — **`acceptTerms: true` required** |
| `providerUnpublish(apiId)` | `POST …/unpublish` | Unpublish |
| `providerUpdatePricing(apiId, { endpoints })` | `PATCH …/pricing` | Pricing |
| `providerAnalytics()` | `GET /v1/provider/analytics` | Analytics |
| `providerConnectOnboard()` | `POST …/connect/onboard` | Connect URL |
| `providerCreateDocument(body)` | `POST /v1/provider/documents` | Draft document |
| `providerListDocuments(opts?)` | `GET /v1/provider/documents` | List documents |
| `providerActivateDocument(id, body?)` | `POST …/activate` | Activate document |

## proxyCall notes

- Uses **`apiKey`** only (not `sessionToken`).
- Pass explicit `gatewayUrl` when `baseUrl` is localhost.
- Returns full Ozma envelope including `meta.cost_cents` and billing fields.
- Does **not** expose idempotency key options — set `Idempotency-Key` header manually if needed.
- **428** when required provider terms not accepted.

## Scopes

Anonymous register keys: consumer scopes only. Email-verified keys add `billing:write` + `provider:write`. See [Authentication](/docs/getting-started/authentication).

## Related

- [CLI](/docs/reference/cli)
- [MCP](/docs/reference/mcp)
- Python SDK: monorepo `packages/python/ozma/`
