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

# POS API SDK

Reference for `@gomining/pos-api-sdk`, the official client for the GoBTC Pay POS API. Use it to accept Bitcoin payments from a point-of-sale terminal: create a payment, show the customer the QR code, and track it until it settles on-chain.&#x20;

For a setup walkthrough, see [Accept Payments Online](/guides/accept-payments-online.md).

{% hint style="info" %}
**Where to put the `apiKey`.** The `apiKey` is a per-terminal **secret** used to sign every request. Keep it server-side, or on a controlled POS device. Do not ship it in a public website. For browser usage, the API must also allow your origin via **CORS**, otherwise route the calls through your own backend.
{% endhint %}

### Overview

The package is a thin client for the POS API surface. It signs each request for you with a fresh HMAC signature and timestamp, so there is no token to manage or refresh.&#x20;

The same package runs on a server, in a bundled browser app, and in a plain HTML page, because it uses the Web Crypto API (built into both browsers and Node) rather than `node:crypto`.

Use it when you are building a checkout or POS integration against a specific terminal, and you hold that terminal's key.

### Installation

```bash
npm install @gomining/pos-api-sdk
```

Runs on **Node 18 or newer** and in modern **browsers**. Both ESM and CommonJS entry points ship, along with TypeScript declarations.

```ts
import { GoBTCPay } from "@gomining/pos-api-sdk";
```

```js
const { GoBTCPay } = require("@gomining/pos-api-sdk");
```

### Initialization

Construct the client once. The terminal key signs every request automatically.

```ts
import { GoBTCPay } from "@gomining/pos-api-sdk";

const btcPay = new GoBTCPay({
  apiKey: process.env.POS_API_KEY,
  posTerminalId: process.env.POS_TERMINAL_ID,
});
```

| Option          | Required | Default                                           | Description                                     |
| --------------- | -------- | ------------------------------------------------- | ----------------------------------------------- |
| `apiKey`        | yes      | none                                              | Per-terminal secret used to sign every request. |
| `posTerminalId` | no       | none                                              | Default terminal for `createPayment`.           |
| `baseUrl`       | no       | `https://api.btcpay.gomining.com/public/api/v1.1` | Override for staging or dev environments.       |
| `timeoutMs`     | no       | `30000`                                           | Per-request timeout.                            |
| `fetch`         | no       | global `fetch`                                    | Custom fetch implementation.                    |

{% hint style="info" %}
**API version is pinned in the SDK.** The version (`v1.1`, exported as `API_VERSION`) lives inside the package, so you do not put it in a URL. The SDK always speaks the API version it was built and tested against. To target a different environment, override `baseUrl`.
{% endhint %}

### Reference

#### Classes and types

| Name            | Kind          | Description                                                                                                                                                    |
| --------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GoBTCPay`      | class         | The client. Construct it with the options above.                                                                                                               |
| `PaymentPoller` | class         | Returned by `watchPayment()`. Holds live state, subscriptions, and a `done()` promise.                                                                         |
| Payment status  | status values | A payment's `status` is one of `initiated`, `paid`, `cleared`, `expired`, `canceled`, `failed`. The final ones are `cleared`, `expired`, `canceled`, `failed`. |
| `API_VERSION`   | constant      | The API version the SDK speaks (`v1.1`).                                                                                                                       |

#### Methods

| Method          | Signature                                                                                     | Description                                                                       |
| --------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `createPayment` | `createPayment({ amount, currency, description?, ttlSeconds?, externalId?, posTerminalId? })` | Create a payment. Returns `paymentId` and `qrString` to show the customer.        |
| `getPayment`    | `getPayment({ paymentId })`                                                                   | Fetch the current state of a payment.                                             |
| `watchPayment`  | `watchPayment({ paymentId, intervalMs?, timeoutMs?, until?, immediate?, stopOnError? })`      | Poll `getPayment` on an interval until a final status. Returns a `PaymentPoller`. |
| `webhooks`      | `webhooks({ signingSecret })`                                                                 | Create a webhook handler (see Webhooks).                                          |

`PaymentPoller` members:

| Member          | Description                                                                             |
| --------------- | --------------------------------------------------------------------------------------- |
| `state`         | Live, readable object: `{ status, payment, error, attempts, isPolling, isFinal, ... }`. |
| `onChange(cb)`  | Fires on any state change. Returns an unsubscribe function.                             |
| `onUpdate(cb)`  | Fires on every successful poll.                                                         |
| `onPaid(cb)`    | Fires when the customer has paid (not yet on-chain).                                    |
| `onSettled(cb)` | Fires when the payment reaches a final status.                                          |
| `onError(cb)`   | Fires when a poll fails.                                                                |
| `done()`        | Promise that resolves with the final payment.                                           |
| `stop()`        | Stops polling early.                                                                    |

#### Events

The only named event is the webhook event below. The `PaymentPoller` delivers its updates through the subscription methods in the table above (`onChange`, `onUpdate`, `onPaid`, `onSettled`, `onError`), not as named events.

| Event                    | Payload                      | Description                                                                  |
| ------------------------ | ---------------------------- | ---------------------------------------------------------------------------- |
| `payment.status.updated` | same shape as `getPayment()` | A payment changed status. Delivered to your webhook endpoint (see Webhooks). |

#### Errors

All errors extend `GoBTCPayError`:

| Error                   | Description                                                                                |
| ----------------------- | ------------------------------------------------------------------------------------------ |
| `GoBTCPayError`         | Base class for every error the SDK throws.                                                 |
| `GoBTCPayApiError`      | The API returned an error envelope or a non-2xx status. Exposes `.httpStatus` and `.body`. |
| `WebhookSignatureError` | A webhook signature failed verification.                                                   |

### Auto-polling

`watchPayment()` polls `getPayment` on an interval until the payment reaches a final status (`cleared`, `expired`, `canceled`, or `failed`). It starts automatically and returns a `PaymentPoller` with live state, subscriptions, and a `done()` promise. The interval defaults to and is clamped to a minimum of **3 seconds**.

```ts
const watcher = btcPay.watchPayment({ paymentId, intervalMs: 3000 });

// Live state, readable at any time:
watcher.state; // { status, payment, error, attempts, isPolling, isFinal, ... }

// Subscriptions (each returns an unsubscribe function):
watcher.onChange((state) => render(state.status)); // any state change
watcher.onUpdate((payment) => {});                 // every successful poll
watcher.onPaid((payment) => {});                   // customer paid (not yet on-chain)
watcher.onSettled((payment) => {});                // reached a final status
watcher.onError((err) => {});                      // a poll failed

// Or just await the outcome:
const finalPayment = await watcher.done();

watcher.stop(); // stop early
```

{% hint style="info" %}
**`paid` vs `cleared`.** `paid` means the customer has paid, which is the moment a cashier usually cares about. `cleared` is the later on-chain confirmation.&#x20;

By default the poller keeps running until a final status and `done()` resolves there. To stop as soon as the customer pays, pass `until: ["paid"]`, or react to `onPaid` while polling continues. See Payment Lifecycle for what each status means.
{% endhint %}

### Webhooks

Register a webhook URL in the merchant dashboard to receive `payment.status.updated` events instead of (or in addition to) polling. The handler verifies the `X-GoBTCPay-Signature` header, enforces a replay window, and de-duplicates on `eventId`.&#x20;

```ts
const webhooks = btcPay.webhooks({ signingSecret: process.env.POS_WEBHOOK_SECRET });

webhooks.on("payment.status.updated", (event) => {
  // event.data has the same shape as getPayment()
  console.log(event.data.paymentId, event.data.status);
});
```

Wire the handler to your HTTP framework. Pass the **raw** request body, not a re-serialized object, or the signature will not match.

```ts
// Express example
app.post("/webhooks/gobtcpay", express.raw({ type: "*/*" }), async (req, res) => {
  try {
    await webhooks.handle(req.body.toString("utf8"), req.header("X-GoBTCPay-Signature"));
    res.sendStatus(200); // any 2xx acknowledges; a non-2xx is retried
  } catch (err) {
    res.sendStatus(400);
  }
});
```

* `handle()` returns the parsed event, or `null` if it was a duplicate.
* `constructEvent()` verifies and parses without dispatching, if you want to handle routing yourself.

### Examples

#### Server (Node.js / Bun / Deno)

```ts
import { GoBTCPay } from "@gomining/pos-api-sdk";

const btcPay = new GoBTCPay({
  apiKey: process.env.POS_API_KEY,
  posTerminalId: process.env.POS_TERMINAL_ID,
});

// Create a payment and show the QR to the customer.
const payment = await btcPay.createPayment({
  amount: 10,
  currency: "USD",
  description: "Order #1024",
});
console.log(payment.paymentId, payment.qrString);

// Wait for the outcome.
const final = await btcPay.watchPayment({ paymentId: payment.paymentId }).done();
console.log(final.status);
```

A common pattern is to keep the secret on your server and expose thin endpoints (`POST /payments`, `GET /payments/:id`) that the browser calls.

#### Browser (with a bundler: Vite, webpack, Next.js)

```ts
import { GoBTCPay } from "@gomining/pos-api-sdk";

const btcPay = new GoBTCPay({ apiKey, posTerminalId });

const payment = await btcPay.createPayment({ amount: 10, currency: "USD" });

// Watch for the result and update the UI live.
const watcher = btcPay.watchPayment({ paymentId: payment.paymentId });
watcher.onChange((s) => (statusEl.textContent = s.status));
watcher.onPaid(() => showPaidScreen());
```

#### Plain HTML (no build step)

Load the ESM build from a CDN inside `<script type="module">`. Use this only on a test or controlled device, because the key is a secret.

```html
<!doctype html>
<html>
  <body>
    <pre id="out">creating...</pre>
    <script type="module">
      import { GoBTCPay } from "https://esm.sh/@gomining/pos-api-sdk";

      const btcPay = new GoBTCPay({
        apiKey: "YOUR_TERMINAL_KEY", // secret: test or controlled device only
        posTerminalId: "YOUR_TERMINAL_ID",
      });

      const out = document.getElementById("out");
      try {
        const payment = await btcPay.createPayment({ amount: 1, currency: "USD" });
        out.textContent = `paymentId: ${payment.paymentId}\nqr: ${payment.qrString}`;

        const watcher = btcPay.watchPayment({ paymentId: payment.paymentId });
        watcher.onChange((s) => (out.textContent += `\nstatus: ${s.status}`));
      } catch (err) {
        out.textContent = "error: " + err.message;
      }
    </script>
  </body>
</html>
```

{% hint style="info" %}
The browser must be allowed to reach the API origin (CORS). If you hit a `Failed to fetch` or CORS error, proxy the requests through your backend and point `baseUrl` at that proxy.
{% endhint %}

### Versioning

The package version tracks the API version via semver:

| API version     | SDK version   |
| --------------- | ------------- |
| `v1.x`          | `0.x` / `1.x` |
| `v2` (breaking) | `2.x`         |

* Non-breaking API changes (`v1.1` to `v1.2`) ship as a **minor** SDK release.
* A breaking API version (`v2`) ships as a **new major** SDK release that points at the new base URL internally.


---

# 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.gobtcpay.com/sdk-reference/pos-api-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.
