Developers

TypeScript SDK and helpers

The openpromoter npm package is a typed client for the OpenPromoter REST API. It adds helpers for signups, Stripe Checkout and webhook checks.

npm install openpromoter

The SDK runs on Node 18 or newer (it uses fetch and node:crypto) and has no dependencies.

Client

import { OpenPromoter } from "openpromoter";

const op = new OpenPromoter({
  apiKey: process.env.OPENPROMOTER_API_KEY!,
  baseUrl: "https://app.openpromoter.com", // or your APP_URL when self-hosting
});

baseUrl defaults to Cloud. You can also pass your own fetch.

Resources

Resource Methods
op.programs list(), stats(programId, { days })
op.events list({ after?, limit? })
op.partners list(programId, { status, limit, before }), create(programId, { email, name, website?, country? }), get(partnerId), update(partnerId, { status?, groupId? }), createLink(partnerId, { destination, subId?, key? }), embedToken(programId, { email, name })
op.referrals list(programId, { status, limit, before })
op.clicks create({ programId, code, url?, visitorId?, ip?, userAgent? })
op.leads create({ programId, email, name?, clickId?, visitorId?, partnerCode?, customerId? })
op.conversions create({ programId, paymentId, customerId, amount, currency, interval?, email?, clickId?, partnerCode?, promoCode?, paidAt? })
op.refunds create({ programId, paymentId, refundId, refundedTotal, chargedTotal })
op.commissions list(programId, { status, partnerId, limit, before }), create(programId, { partnerId, amount, description, idempotencyKey? })
op.payouts list(programId, { status, limit, before }), prepare(programId, { partnerIds? })
op.campaigns list(programId), create(programId, { prompt, launch? })
op.autopilot list(programId), apply(programId, actionId)

op.ask(programId, question) answers a plain-language question from your data.

op.payouts.prepare() creates payouts that wait for a person to approve them in the dashboard. The SDK cannot send money.

Signups

trackSignup reads the op_ref cookie from the request and records a lead. Because it never throws, a tracking problem can never break your signup flow. Call it from your auth provider's signup hook (Better Auth, NextAuth, Clerk, Supabase):

import { trackSignup } from "openpromoter";

await trackSignup(op, {
  programId: "prg_123",
  email: user.email,
  cookieHeader: req.headers.get("cookie"),
});

Stripe Checkout

import { readReferralCookie, stripeCheckoutParams } from "openpromoter";

const session = await stripe.checkout.sessions.create({
  ...yourOptions,
  ...stripeCheckoutParams(readReferralCookie(req.headers.get("cookie"))),
});

This sets client_reference_id, metadata.op_click and subscription_data.metadata when the visitor came from a partner. It sets nothing otherwise.

Embedded dashboard

const { token } = await op.partners.embedToken("prg_123", { email: user.email, name: user.name });
// render <openpromoter-dashboard program="acme" token={token}> in your app

See Embedded dashboard.

Other billing systems

await op.conversions.create({
  programId: "prg_123",
  paymentId: "inv_1",
  customerId: "cus_1",
  amount: 4900,
  currency: "usd",
  interval: "month",
});

Webhooks

import { verifyWebhook } from "openpromoter";

const event = verifyWebhook(rawBody, req.headers.get("openpromoter-signature"), process.env.OPENPROMOTER_WEBHOOK_SECRET!);

verifyWebhook(body, header, secret, toleranceSeconds = 300) throws an OpenPromoterError if the signature is missing, wrong or too old. Otherwise it returns the parsed event. See Webhooks.

Errors

Failed requests throw OpenPromoterError with status, code and message. Validation errors also carry issues.

import { OpenPromoterError } from "openpromoter";

try {
  await op.partners.create("prg_123", { email: "maya@example.com", name: "Maya" });
} catch (err) {
  if (err instanceof OpenPromoterError && err.status === 429) {
    // back off and retry
  }
}

License

The SDK is MIT licensed. You can use it in any codebase. The OpenPromoter app itself is AGPL-3.0.

Edit this page on GitHub