@oaknetwork/payments-sdk
v1.1.0
Published
A fully-typed TypeScript SDK for the Oak Network payment API.
Readme
Oak Payments SDK
A fully-typed TypeScript SDK for the Oak Network Payments API. Drop-in authentication, automatic retries, and zero boilerplate, production-ready from day one.
Full documentation - oaknetwork.org/docs/sdk/overview
Getting credentials
To use the SDK you need a Client ID and Client Secret. Contact [email protected] to get your sandbox credentials.
Create a .env file in your project root:
CLIENT_ID=your-client-id
CLIENT_SECRET=your-client-secretInstall dotenv to load these automatically: pnpm add dotenv, then add import 'dotenv/config' at the top of your entry file.
| Variable | Required | Description |
| --------------- | -------- | --------------------------- |
| CLIENT_ID | Yes | Your merchant client ID |
| CLIENT_SECRET | Yes | Your merchant client secret |
Use different credentials for sandbox and production. Never commit
.envfiles or log secrets.
Quick start
Installation
pnpm add @oaknetwork/payments-sdk
# or
npm install @oaknetwork/payments-sdk
# or
yarn add @oaknetwork/payments-sdkRequirements: Node.js 18+, TypeScript 5.x recommended.
Basic usage
import "dotenv/config";
import {
createOakClient,
createCustomerService,
} from "@oaknetwork/payments-sdk";
const client = createOakClient({
environment: "sandbox",
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
});
const customers = createCustomerService(client);
const result = await customers.list();
if (result.ok) {
console.log(result.value.data);
} else {
console.error(result.error.message);
}See the full Quickstart guide for a step-by-step walkthrough.
Services
The SDK ships 10 service modules. Import the factory function for each service you need.
| Service | Factory | What it does |
| ---------------------------------------------------------------------- | ------------------------------------ | --------------------------------------------------- |
| Customers | createCustomerService(client) | Create, get, list, update, sync, and check balances |
| Payments | createPaymentService(client) | Create, confirm, cancel payments |
| Payment Methods | createPaymentMethodService(client) | Add, list, get, delete payment methods |
| Webhooks | createWebhookService(client) | Register, manage, and monitor webhooks |
| Transactions | createTransactionService(client) | List, get, and settle transactions |
| Transfers | createTransferService(client) | Create provider transfers (Stripe, PagarMe, BRLA) |
| Plans | createPlanService(client) | CRUD subscription plans |
| Refunds | createRefundService(client) | Refund a payment (full or partial) |
| Buy | createBuyService(client) | Crypto on-ramp via Bridge |
| Sell | createSellService(client) | Crypto off-ramp via Avenia |
Usage examples
Customers
import { createCustomerService } from "@oaknetwork/payments-sdk";
const customers = createCustomerService(client);
// Create
const result = await customers.create({
email: "[email protected]",
first_name: "John",
last_name: "Doe",
country_code: "US",
});
// List
await customers.list({ limit: 10, offset: 0 });
// Get
await customers.get("customer_id");
// Update
await customers.update("customer_id", { email: "[email protected]" });Providers
import { createProviderService } from "@oaknetwork/payments-sdk";
const providers = createProviderService(client);
// Register as Stripe customer (buyer)
await providers.submitRegistration(customerId, {
provider: "stripe",
target_role: "customer",
});
// Register as Stripe connected account (seller)
await providers.submitRegistration(customerId, {
provider: "stripe",
target_role: "connected_account",
provider_data: {
account_type: "express",
transfers_requested: true,
card_payments_requested: true,
tax_reporting_us_1099_k_requested: false,
payouts_debit_negative_balances: false,
external_account_collection_requested: false,
},
});
// Check registration status
const status = await providers.getRegistrationStatus(customerId);Payments
import { createPaymentService } from "@oaknetwork/payments-sdk";
const payments = createPaymentService(client);
// Create and capture a payment
const result = await payments.create({
provider: "stripe",
source: {
amount: 5000,
currency: "usd",
customer: { id: customerId },
payment_method: { type: "card", id: paymentMethodId },
capture_method: "automatic",
},
confirm: true,
});
// Confirm / cancel
await payments.confirm("payment_id");
await payments.cancel("payment_id");Payment methods
import { createPaymentMethodService } from "@oaknetwork/payments-sdk";
const paymentMethods = createPaymentMethodService(client);
// Add a card
await paymentMethods.add(customerId, {
type: "card",
provider: "stripe",
});
// Add a bank account
await paymentMethods.add(customerId, {
type: "bank",
provider: "stripe",
currency: "usd",
bank_name: "Chase",
bank_account_number: "000123456789",
bank_routing_number: "021000021",
bank_account_type: "checking",
bank_account_name: "John Doe",
});
// List / get / delete
await paymentMethods.list(customerId);
await paymentMethods.get(customerId, "pm_id");
await paymentMethods.delete(customerId, "pm_id");Transfers
import { createTransferService } from "@oaknetwork/payments-sdk";
const transfers = createTransferService(client);
await transfers.create({
provider: "stripe",
source: {
amount: 1000,
currency: "usd",
customer: { id: customerId },
},
destination: {
customer: { id: customerId },
payment_method: { type: "bank", id: bankPmId },
},
});Refunds
import { createRefundService } from "@oaknetwork/payments-sdk";
const refunds = createRefundService(client);
// Full refund
await refunds.create(paymentId, {});
// Partial refund
await refunds.create(paymentId, { amount: 500 });Plans
import { createPlanService } from "@oaknetwork/payments-sdk";
const plans = createPlanService(client);
await plans.create({
name: "Pro Plan",
description: "Monthly pro subscription",
price: 2999,
currency: "USD",
frequency: 30,
start_date: "2026-03-01",
is_auto_renewable: true,
allow_amount_override: false,
created_by: customerId,
});
await plans.list();
await plans.details("plan_id");Transactions
import { createTransactionService } from "@oaknetwork/payments-sdk";
const transactions = createTransactionService(client);
await transactions.list({ limit: 20 });
await transactions.get("txn_id");Webhooks
Register endpoints to receive real-time event notifications, and verify incoming payloads with HMAC-SHA256 signature verification.
import {
createWebhookService,
verifyWebhookSignature,
parseWebhookPayload,
} from "@oaknetwork/payments-sdk";
const webhooks = createWebhookService(client);
// Register
const wh = await webhooks.register({
url: "https://your-server.com/webhooks/oak",
description: "Payment events",
});
if (wh.ok) {
console.log("Secret:", wh.value.data.secret); // store securely
}
// List / update / delete
await webhooks.list();
await webhooks.update("webhook_id", { url: "https://new-url.com/webhooks" });
await webhooks.toggle("webhook_id");
await webhooks.delete("webhook_id");Verify and parse incoming events
import { parseWebhookPayload } from "@oaknetwork/payments-sdk";
import express from "express";
const app = express();
app.post(
"/webhooks/oak",
express.raw({ type: "application/json" }),
(req, res) => {
const result = parseWebhookPayload(
req.body.toString(),
req.headers["x-oak-signature"] as string,
process.env.WEBHOOK_SECRET!,
);
if (!result.ok) {
return res.status(401).json({ error: "Invalid signature" });
}
switch (result.value.event) {
case "payment.succeeded":
break;
case "payment.failed":
break;
case "provider_registration.approved":
break;
}
res.json({ received: true });
},
);Full webhook reference — oaknetwork.org/docs/sdk/webhooks
Error handling
Every method returns Result<T, OakError> — no uncaught exceptions. Check result.ok to branch on success or failure.
const result = await customers.create({
email: "[email protected]",
first_name: "John",
});
if (result.ok) {
const customer = result.value.data;
console.log("Created:", customer.id);
} else {
console.error("Failed:", result.error.message);
console.error("Status:", result.error.statusCode);
console.error("Code:", result.error.code);
}| Error type | Description |
| --------------------------- | ---------------------------------------- |
| ApiError | HTTP errors from the API (4xx, 5xx) |
| NetworkError | Network failures, timeouts |
| ParseError | Invalid JSON responses |
| AbortError | Request aborted |
| EnvironmentViolationError | Sandbox-only method called in production |
Full error handling guide — oaknetwork.org/docs/sdk/error-handling
Configuration
Environments
| Environment | API Base URL | Description |
| ------------ | ----------------------------------- | -------------------------------- |
| sandbox | https://api-stage.usecrowdpay.xyz | Testing — all operations allowed |
| production | https://app.usecrowdpay.xyz | Live — test operations blocked |
const client = createOakClient({
environment: "sandbox",
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
// Optional: point to a custom API server
customUrl: "https://my-dev-server.example.com",
});Retry configuration
The SDK automatically retries failed requests with exponential backoff and jitter.
const client = createOakClient({
environment: "sandbox",
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
retryOptions: {
maxNumberOfRetries: 3,
delay: 1000,
backoffFactor: 2,
maxDelay: 30000,
},
});Retried status codes: 408, 429, 500, 502, 503, 504.
TypeScript support
The SDK ships full type declarations. All service methods, request payloads, and responses are typed.
import type { Result } from "@oaknetwork/payments-sdk";Development
Package manager
This project uses pnpm exclusively:
pnpm install # Install dependencies
pnpm build # Build all packages
pnpm test # Run tests
pnpm lint # Lint codeDo not use npm or yarn. The repository enforces pnpm >= 10.0.0.
Running tests
pnpm test:unit # Unit tests
pnpm test:integration # Integration tests (requires credentials)
pnpm test:all # All tests with coverage
pnpm test:watch # Watch modeChangesets workflow
We use Changesets to manage versions and changelogs:
- After making changes, run
pnpm changeset - Select impact (Major / Minor / Patch) for affected packages
- Commit the generated file in
.changeset/ - CI automatically calculates versions, generates changelogs, and creates a release PR
Code coverage
Coverage is reported to Codecov after each successful CI run.
Development guidelines
See CLAUDE.md for coding standards including architecture principles, security rules, testing requirements, and anti-patterns.
Code review checklist
- [ ]
pnpm buildsucceeds - [ ]
pnpm testpasses with >90% coverage - [ ]
pnpm linthas no errors - [ ] Changeset created with
pnpm changeset - [ ] Documentation updated if needed
Documentation
- Full docs — oaknetwork.org/docs/sdk/overview
- Quickstart — oaknetwork.org/docs/sdk/quickstart
- Monorepo README — README.md
- Changelog — CHANGELOG.md
License
Security
Links
Questions? Open an issue or contact [email protected]
