# SDKs

> [!SOON] **Coming soon.** The Python, TypeScript and Go libraries are built and tested but **not published yet**, and there are no packages to install today. The install commands below are what you will run at launch. Until then, please do not install anything named "onekey" from a package registry. The plain HTTP API works from any language right now: see the [Quickstart](https://onekey.dev/docs/quickstart.md).

The official libraries wrap the same [HTTP API](https://onekey.dev/docs/quickstart.md) in a few lines of idiomatic code. They read your key from the environment, retry safely, tell you what every call cost, and give you typed methods for the most-used platforms.

| Language | Package | Install (available at launch) | Needs |
| --- | --- | --- | --- |
| Python | `onekey` | `pip install onekey` | Python 3.9+, sync and async |
| TypeScript / JavaScript | `onekey` | `npm install onekey` | Node 18+, or anything with `fetch`; no dependencies |
| Go | `onekey-go` | `go get github.com/onekey-hq/onekey-go` | Go 1.21+, standard library only |

## Quickstart

Set your key once, then make a call. Each snippet looks up a GitHub profile (1 credit) and prints the data and what the call cost.

```bash
export ONEKEY_KEY="YOUR_API_KEY"
```

### Python

```python
from onekey import Onekey

client = Onekey()  # reads ONEKEY_KEY
env = client.github.profile(username="torvalds")
print(env.data)
print(env.meta.credits_charged, env.meta.cached)
```

### TypeScript

```typescript
import { Onekey } from "onekey";

const client = new Onekey(); // reads ONEKEY_KEY
const env = await client.github.profile({ username: "torvalds" });
console.log(env.data);
console.log(env.meta.creditsCharged, env.meta.cached);
```

### Go

```go
c, err := onekey.New() // reads ONEKEY_KEY
if err != nil { log.Fatal(err) }
env, err := c.Github.Profile(ctx, &onekey.GithubProfileParams{Username: "torvalds"})
if err != nil { log.Fatal(err) }
fmt.Println(string(env.Data))
fmt.Println(env.Meta.CreditsCharged, env.Meta.Cached)
```

## Configuration

| Setting | Default | Notes |
| --- | --- | --- |
| API key | `ONEKEY_KEY` environment variable | Or pass it to the constructor. Sent only in the `x-api-key` header, never in a URL, and hidden when you print the client. |
| Base URL | `ONEKEY_BASE_URL`, else `https://api.onekey.dev` | Override to point at another deployment or a test server. |
| Timeout | 30 seconds per attempt | Can be set per client and per call. |
| Retries | 2 | Set to 0 to turn retries off. |

```python
client = Onekey(api_key="YOUR_API_KEY", base_url="https://api.onekey.dev", timeout=30.0, max_retries=2)
```

```typescript
const client = new Onekey({ apiKey: "YOUR_API_KEY", baseUrl: "https://api.onekey.dev", timeoutMs: 30000, maxRetries: 2 });
```

```go
c, _ := onekey.New(onekey.WithAPIKey("YOUR_API_KEY"), onekey.WithBaseURL("https://api.onekey.dev"), onekey.WithTimeout(30*time.Second), onekey.WithMaxRetries(2))
```

> [!WARN] Call Onekey from your server. In a browser, anything you ship, including the key, is public.

## Typed methods and the generic request

Every platform and endpoint is reachable through one generic call, which works for all endpoints in the [catalog](https://onekey.dev/docs/platforms.md), including ones added after the library was released:

```python
env = client.request("github", "profile", {"username": "torvalds"})
```

```typescript
const env = await client.request("github", "profile", { username: "torvalds" });
```

```go
env, err := c.Request(ctx, "github", "profile", onekey.Params{"username": "torvalds"})
```

On top of that, the libraries ship **typed methods** (`client.github.profile(...)`) for the 20 most-used platforms, 355 endpoints in this first release: GitHub, YouTube, Reddit, Hacker News, X, Instagram, TikTok, LinkedIn, Facebook, Threads, Bluesky, npm, PyPI, Wikipedia, Product Hunt, Web, Telegram, Twitch, Pinterest and Stack Exchange. Typed methods give you editor completion for parameter names, mark required parameters, and (in Go) reject a missing required parameter locally, before any request or charge. Everything else uses `request`.

The catalog helpers are free and need no key: `client.platforms()` returns every endpoint with its price and status, `client.categories()` the categories with platform and endpoint counts, and `client.account()` your credit balance.

## The response

Every call returns the standard [response](https://onekey.dev/docs/response-envelope.md): `success`, `data`, `meta` and `error`. In the libraries the block is called `meta` (the API sends it as `metadata`). `data` is plain JSON.

| Field | Meaning |
| --- | --- |
| `credits_charged` | What this call cost, or 0 for a cache hit. |
| `cached`, `stale`, `age_s` | Whether it came from Onekey's cache and how old it is. See [Caching](https://onekey.dev/docs/caching.md). |
| `fetched_at`, `request_id` | When it was fetched, and the id to quote to support. |
| `platform`, `endpoint` | Which endpoint answered. |

In TypeScript the fields are camelCase (`meta.creditsCharged`, `meta.requestId`); in Go they are `Meta.CreditsCharged` and `Meta.RequestID`.

## Pagination

Endpoints that take a `cursor` (or `page`) parameter can be walked with a helper. Each page is a normal call and is charged like one, so always set a page limit.

```python
for item in client.iter_items("tiktok", "comments", {"id": "123"}, max_pages=5):
    print(item)
```

```typescript
for await (const item of client.iterItems("tiktok", "comments", { id: "123" }, { maxPages: 5 })) {
  console.log(item);
}
```

```go
p := c.NewPager("tiktok", "comments", onekey.Params{"id": "123"}, &onekey.PageOptions{MaxPages: 5})
for p.Next(ctx) {
	for _, item := range p.Envelope().Items() { fmt.Println(item) }
}
if err := p.Err(); err != nil { log.Fatal(err) }
```

> [!NOTE] The helpers follow a next-page cursor when the response carries one. Today most list endpoints do not return one yet, so iteration ends after the first page until they do. Nothing extra is charged for that.

## Retries and errors

The libraries retry `429`, `500`, `502`, `503`, `504`, timeouts and network errors, up to 2 times by default, with exponential backoff and jitter. A `Retry-After` header is honoured. They never retry `400`, `401`, `402`, `403`, `404` or `422`, because the same request would fail the same way. Retrying is safe: failed calls are refunded, and a repeated successful call is a free cache hit. See [Errors](https://onekey.dev/docs/errors.md) and [Rate limits](https://onekey.dev/docs/rate-limits.md).

When retries run out, or the error is not retryable, you get a typed error carrying the code, HTTP status and request id:

| Error | When |
| --- | --- |
| `UnauthorizedError` | 401: key missing, wrong or revoked. |
| `InsufficientCreditsError` | 402: top up, then retry. |
| `NotFoundError` | 404: the record does not exist (refunded). |
| `InvalidParamsError` | 422: a parameter is missing or malformed (also raised locally for a bad platform or endpoint name). |
| `RateLimitedError` | 429, with the seconds to wait. |
| `UpstreamError` | 502: the source platform failed (refunded). |
| `ConfigurationError` | No API key, raised before any request. |

```python
from onekey import InsufficientCreditsError, RateLimitedError

try:
    client.github.profile(username="torvalds")
except InsufficientCreditsError:
    ...  # top up
except RateLimitedError as e:
    print(e.retry_after, e.request_id)
```

```typescript
import { InsufficientCreditsError, RateLimitedError } from "onekey";

try {
  await client.github.profile({ username: "torvalds" });
} catch (e) {
  if (e instanceof InsufficientCreditsError) { /* top up */ }
  else if (e instanceof RateLimitedError) console.log(e.retryAfter, e.requestId);
  else throw e;
}
```

```go
var ke *onekey.Error
switch {
case errors.Is(err, onekey.ErrInsufficientCredits): // top up
case errors.Is(err, onekey.ErrRateLimited) && errors.As(err, &ke): time.Sleep(ke.RetryAfter)
}
```

## Async Python

`AsyncOnekey` has the same surface on `httpx`:

```python
import asyncio
from onekey import AsyncOnekey

async def main():
    async with AsyncOnekey() as client:
        env = await client.github.profile(username="torvalds")
        print(env.meta.credits_charged)

asyncio.run(main())
```

## Until the libraries are published

Use the HTTP API directly. It is a few lines in any language: see the [Quickstart](https://onekey.dev/docs/quickstart.md) and the request examples on every [endpoint page](https://onekey.dev/docs/platforms.md). Working with an AI tool instead? See the [MCP server](https://onekey.dev/docs/mcp.md) and [AI agents](https://onekey.dev/docs/ai-agents.md).
