Source: https://fincobra.com/docs/checkout/sdk.html


# TypeScript SDK

Use the FinCobra TypeScript SDK when you want a typed server-side client for the Checkout API.

The SDK covers the standard hosted checkout integration:

- Create checkout sessions and invoices
- Fetch invoice detail and payment status
- Verify webhook signatures
- Use exported TypeScript types for invoices, payment status, and webhook events

Install from GitHub until the package is published to npm:

```bash
npm install github:dexstandard/fincobra-sdk
```

Source: [dexstandard/fincobra-sdk](https://github.com/dexstandard/fincobra-sdk)

## Client setup

Create the client on your server. Never expose the FinCobra API key or webhook signing secret in browser code.

```ts
import { createFinCobraClient } from '@fincobra/sdk';

const fincobra = createFinCobraClient({
  apiKey: process.env.FINCOBRA_API_KEY,
});
```

The SDK defaults to `https://fincobra.com`.

## Create checkout

`checkoutSessions.create` creates a hosted checkout invoice and returns `paymentUrl`.

```ts
const session = await fincobra.checkoutSessions.create({
  amountUsd: 49.99,
  productName: 'Pro Plan - Monthly',
  merchantReference: 'order_123',
  customerEmail: 'buyer@example.com',
  redirectUrl: 'https://example.com/account/billing',
  metadata: {
    orderId: 'order_123',
  },
});

return Response.redirect(session.paymentUrl);
```

## Create invoice

```ts
const invoice = await fincobra.invoices.create({
  amountUsd: 25,
  productName: 'One-time setup',
  customerEmail: 'buyer@example.com',
});
```

## Read payment status

```ts
const payment = await fincobra.payments.get(
  'a1b2c3d4-1111-4222-8333-abcdefabcdef',
);

if (payment.status === 'confirmed') {
  // fulfill the order
}
```

You can also call `fincobra.invoices.get(id)` for full invoice detail or `fincobra.invoices.getStatus(id)` for the same status payload as `payments.get(id)`.

## Next.js example

```ts
import { createFinCobraClient } from '@fincobra/sdk';
import { NextResponse } from 'next/server';

const fincobra = createFinCobraClient({
  apiKey: process.env.FINCOBRA_API_KEY,
});

export async function POST() {
  const invoice = await fincobra.checkoutSessions.create({
    amountUsd: 49.99,
    productName: 'Pro Plan - Monthly',
    merchantReference: 'order_123',
    customerEmail: 'buyer@example.com',
    redirectUrl: 'https://example.com/account/billing',
    metadata: {
      orderId: 'order_123',
    },
  });

  return NextResponse.json({
    invoiceId: invoice.id,
    paymentUrl: invoice.paymentUrl,
  });
}
```

## Express example

```ts
import express from 'express';
import { createFinCobraClient } from '@fincobra/sdk';

const app = express();
app.use(express.json());

const fincobra = createFinCobraClient({
  apiKey: process.env.FINCOBRA_API_KEY,
});

app.post('/checkout', async (req, res, next) => {
  try {
    const invoice = await fincobra.invoices.create({
      amountUsd: Number(req.body.amountUsd),
      productName: String(req.body.productName),
      merchantReference: String(req.body.orderId),
      customerEmail:
        typeof req.body.customerEmail === 'string'
          ? req.body.customerEmail
          : undefined,
      metadata: {
        orderId: String(req.body.orderId),
      },
    });

    res.status(201).json({
      invoiceId: invoice.id,
      paymentUrl: invoice.paymentUrl,
    });
  } catch (err: unknown) {
    next(err);
  }
});
```

## Webhook handler example

Configure this route with the raw request body. Verify the signature before processing the event, then fetch the latest invoice state before fulfilling an order.

```ts
import express from 'express';
import { createFinCobraClient } from '@fincobra/sdk';

const app = express();
const fincobra = createFinCobraClient({
  apiKey: process.env.FINCOBRA_API_KEY,
});

app.post(
  '/webhooks/fincobra',
  express.raw({ type: 'application/json' }),
  async (req, res, next) => {
    try {
      const event = fincobra.webhooks.verifySignature({
        body: req.body,
        signature: req.header('X-Checkout-Signature'),
        secret: process.env.FINCOBRA_WEBHOOK_SECRET ?? '',
      });

      const invoice = await fincobra.invoices.get(event.invoice.id);
      if (
        invoice.status === 'confirmed' ||
        invoice.status === 'paid_out_of_band'
      ) {
        await markOrderPaid(invoice.merchantReference, invoice.id);
      }

      res.sendStatus(204);
    } catch (err: unknown) {
      next(err);
    }
  },
);
```

## Error handling

All SDK errors extend `FinCobraError`. API responses with `{ "error": "message" }` become `FinCobraApiError` with `statusCode`, `responseBody`, and a clear `message`.

```ts
import { FinCobraApiError } from '@fincobra/sdk';

try {
  await fincobra.invoices.create({ amountUsd: 49.99 });
} catch (err: unknown) {
  if (err instanceof FinCobraApiError) {
    err.statusCode;
    err.message;
  }

  throw err;
}
```

For endpoint contracts and field definitions, see the [API Reference](./api-reference.md).
