@duabalabs/dps-client SDK
Single npm package every DPS-consuming app uses to talk to the platform. Add new checkout types here — every consumer benefits without re-implementing payload boilerplate.
- Source:
packages/dps-client - Tenant helpers:
packages/dps-client/src/tenant.ts
API surface
Generic clients
import {
createDpsClient, // browser — uses Parse JS SDK
createDpsServerClient, // server — uses parse/node + master key
withTenant, // wraps a client with tenant scope
type DpsClient,
type TenantClient,
type SubscriptionStatus,
} from '@duabalabs/dps-client';Both clients implement the same DpsClient interface:
| Method | Purpose |
|---|---|
createCheckout(payload) | Low-level — calls dps_checkout_create |
verifyPayment(reference) | Calls dps_checkout_verify |
getOrder(orderId) | Reads an Order |
listOrders(filter) | Lists Orders for the tenant |
checkSubscription({ email }) | Calls dps_subscriptions_check |
Tenant-bound helpers
withTenant(client, { appId, storeId, channelToken?, referencePrefix?, defaultCurrency? }) returns a TenantClient with strongly-typed methods for each checkout type:
| Method | Flow | Use case |
|---|---|---|
createDonation({ amount, customer, campaign?, ... }) | direct | One-off donation (Duabanti) |
startSubscription({ tier, planCode, amount, customer, ... }) | direct + paystackPlanCode | Recurring billing (Duabaconnect, ProxyFidelity) |
createInvoice({ reference, amount, customer, description?, ... }) | vendure if channelToken set, else direct | Ad-hoc pay-link (Duabatrade /pay) |
createProductCheckout({ lineItems, customer, ... }) | vendure | Catalog commerce (Sellub-storefront) |
verifyPayment(reference) | — | Thank-you page verification |
hasActiveSubscription({ email }) | — | Auth-gate helper |
Browser-direct pattern
For static-export Next.js sites (Duabanti, Duabaconnect, Duabatrade):
// src/lib/dps/client.ts
import Parse from 'parse';
import { createDpsClient, withTenant, type TenantClient } from '@duabalabs/dps-client';
const DPS_PARSE_URL = process.env.NEXT_PUBLIC_DPS_PARSE_URL || '';
const DPS_APP_ID = process.env.NEXT_PUBLIC_DPS_APP_ID || '';
const DPS_JS_KEY = process.env.NEXT_PUBLIC_DPS_JS_KEY || '';
let cached: TenantClient | null = null;
export function getDps(): TenantClient {
if (cached) return cached;
Parse.initialize(DPS_APP_ID, DPS_JS_KEY || undefined);
Parse.serverURL = DPS_PARSE_URL;
cached = withTenant(createDpsClient({ Parse: Parse as any }), {
appId: process.env.NEXT_PUBLIC_DPS_APP_ID_TAG || 'duabanti',
storeId: process.env.NEXT_PUBLIC_DPS_STORE_ID || 'duabanti',
referencePrefix: 'DNTI',
defaultCurrency: 'GHS',
});
return cached;
}Anonymous Parse session required.
dps_checkout_createrejects callers with no user and no master key. Before the first checkout from a public landing:if (!Parse.User.current()) { // @ts-ignore await Parse.AnonymousUtils.logIn(); }
Server-side pattern
For Next.js apps with API routes (Sellub-storefront) or Type-4 integrators (ProxyFidelity backend):
import Parse from 'parse/node';
import { createDpsServerClient, withTenant } from '@duabalabs/dps-client';
Parse.initialize(DPS_APP_ID, DPS_JS_KEY, DPS_MASTER_KEY);
Parse.serverURL = 'https://api.platform.duabalabs.com/parse';
const dps = withTenant(
createDpsServerClient({
serverUrl: 'https://api.platform.duabalabs.com/parse',
appId: DPS_APP_ID,
masterKey: DPS_MASTER_KEY,
}),
{ appId: 'sellub', storeId: 'sellub', channelToken: VENDURE_CHANNEL_TOKEN }
);
const session = await dps.createProductCheckout({ lineItems, customer });
return Response.redirect(session.checkoutUrl);Adding a new checkout type
- Add the typed helper to
packages/dps-client/src/tenant.ts. - If it needs a new server-side handler, add a cloud function under
dps-server/src/parse-server/cloud/dps-checkout/. - Bump the SDK version, publish, and update consumer apps.
This is the only place where checkout-flow domain logic should live on the client side. Per-app src/lib/dps/client.ts files should be ~30 lines: just an env-driven getDps() factory.