> For the complete documentation index, see [llms.txt](https://docs.robinmesh.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.robinmesh.com/integrations/javascript-sdk.md).

# JavaScript and TypeScript SDK

`@robinmesh/sdk` is the official typed client for the RobinMesh API. Beyond chat completions it covers wallet-native authentication, structured streaming, React hooks, and pulling on-chain receipts for settled jobs.

***

## Installing

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

***

## First request

```typescript
import { RobinMeshClient } from "@robinmesh/sdk"

const client = new RobinMeshClient({
    apiKey: process.env.ROBINMESH_API_KEY
})

// A plain, non-streaming chat completion
const response = await client.chat.completions.create({
    model: "qwen3-8b",
    messages: [{ role: "user", content: "What is WebGPU?" }]
})

console.log(response.choices[0].message.content)
console.log("Job ID:", response.jobId)
console.log("Settlement tx:", response.settlementTx)
```

***

## Streaming

```typescript
const stream = await client.chat.completions.create({
    model: "llama-3.3-70b",
    messages: [{ role: "user", content: "Explain how optimistic rollups work." }],
    stream: true
})

for await (const chunk of stream) {
    process.stdout.write(chunk.choices[0]?.delta?.content ?? "")
}

// Once the stream finishes, its receipt is populated
const receipt = stream.receipt
console.log("Settlement:", receipt.settlementTx)
console.log("Worker:", receipt.workerAddress)
console.log("Credits used:", receipt.creditsCharged)
```

***

## On-chain receipts

Every job that settles leaves a receipt on-chain. You can grab it off the stream object once streaming ends, or look it up later using the job ID.

```typescript
// Off a finished stream
const receipt = stream.receipt
// {
//   jobId: "job_8fx2kp3m...",
//   model: "llama-3.3-70b",
//   tier: "max",
//   creditsCharged: 40,
//   usdgValue: 0.40,
//   workerAddress: "0x9e2d5b7a814cf3068d91e4a2b5c60f7d83a41c9e",
//   escrowTx: "0x4b8e2f7c9a1d6053e8b24f9c7a30d1e5f6829c4b7d0a3e8f1c5b9d2a6e470381",
//   settlementTx: "0xd3a91c5e7f2b8064a1c9e5d27b483f0a6e1c8b5d9f2a7043e6b1d8c4a95f7e20",
//   blockNumber: 3218472,
//   proofHash: "sha256:a1b2c3d4..."
// }

// Or look up any past job by its ID
const job = await client.jobs.get("job_8fx2kp3m9qrstvwxyz")
console.log(job.onChain.settlementTx)

// Build a Blockscout explorer link for the settlement
const explorerUrl = `https://robinhoodchain.blockscout.com/tx/${job.onChain.settlementTx}`
```

***

## React hooks

The React bindings live under the `@robinmesh/sdk/react` entry point.

```typescript
import { useRobinMeshChat } from "@robinmesh/sdk/react"

function ChatComponent() {
    const { send, messages, status, balance, lastReceipt } = useRobinMeshChat({
        model: "qwen3-8b",
        apiKey: process.env.NEXT_PUBLIC_ROBINMESH_API_KEY
    })

    const handleSend = async (text: string) => {
        await send(text)
    }

    return (
        <div>
            <p>Credits remaining: {balance?.creditsRemaining}</p>
            <p>Status: {status}</p>

            {messages.map((msg, i) => (
                <div key={i}>
                    <strong>{msg.role}:</strong> {msg.content}
                </div>
            ))}

            {lastReceipt && (
                <p>
                    Last job settled:{" "}
                    <a href={`https://robinhoodchain.blockscout.com/tx/${lastReceipt.settlementTx}`}>
                        View on Blockscout
                    </a>
                </p>
            )}
        </div>
    )
}
```

### Hook API

```typescript
const {
    send,           // (message: string) => Promise<void>
    messages,       // Array<{ role: string; content: string }>
    status,         // "idle" | "streaming" | "settling" | "error"
    balance,        // { creditsRemaining: number; usdgValue: number } | null
    lastReceipt,    // JobReceipt | null
    error,          // Error | null
    reset           // () => void, wipes the conversation
} = useRobinMeshChat({
    model: "qwen3-8b",
    apiKey: "rmesh_live_...",
    systemPrompt: "You are a helpful assistant.",  // optional
    onComplete: (receipt) => { ... },              // optional callback
    onError: (error) => { ... }                    // optional callback
})
```

***

## Account and credits

```typescript
const account = await client.account.get()
// {
//   wallet: "0x7c41f9b8d2a6e3054cf18a9b62d47e0c93f5a1b8",
//   creditsRemaining: 1420,
//   usdgValue: 14.20,
//   lastTopupAt: Date
// }

// Page through recent jobs
const jobs = await client.jobs.list({ limit: 10, status: "settled" })
for (const job of jobs.data) {
    console.log(`${job.id}: ${job.model} - ${job.creditsCharged} credits`)
}
```

***

## Webhooks

```typescript
import { verifyWebhookSignature, type RobinMeshWebhookEvent } from "@robinmesh/sdk"

// Validate the signature and handle the event inside an Express route
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
    const signature = req.headers["robinmesh-signature"] as string
    const isValid = verifyWebhookSignature(
        req.body.toString(),
        signature,
        process.env.WEBHOOK_SECRET!
    )

    if (!isValid) {
        return res.status(400).json({ error: "Invalid signature" })
    }

    const event: RobinMeshWebhookEvent = JSON.parse(req.body.toString())

    switch (event.event) {
        case "job.completed":
            console.log("Job settled:", event.data.settlementTx)
            break
        case "credit.low":
            console.log("Credits low:", event.data.creditsRemaining)
            break
    }

    res.json({ received: true })
})
```

***

## Client options

```typescript
const client = new RobinMeshClient({
    apiKey: "rmesh_live_...",       // required
    baseURL: "https://api.robinmesh.com/v1",  // the default; point elsewhere for testing
    timeout: 180_000,                 // per-request timeout in ms (default: 120000)
    maxRetries: 3,                    // retries automatically on 5xx and 503 (default: 2)
    defaultHeaders: {                 // merged into every request
        "x-app-version": "1.0.0"
    }
})
```

***

## TypeScript types

The most useful types exported from `@robinmesh/sdk`:

```typescript
import type {
    ChatCompletion,
    ChatCompletionChunk,
    ChatCompletionCreateParams,
    JobReceipt,
    Job,
    Account,
    Model,
    RobinMeshModel,       // Model plus tier, workers, latency
    WebhookEvent,
    JobCompletedEvent,
    CreditLowEvent
} from "@robinmesh/sdk"
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.robinmesh.com/integrations/javascript-sdk.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
