Home / Docs / Partner SDK Integration

Partner SDK integration guide.

Drop the Gbemidebe SDK into your checkout to turn every transaction into a chance to win. This guide walks you from npm install to a live rewards engine in your product.

GBEMIDEBE-SDK-001 · v1.2 Web · React Native · Flutter Last updated · May 2026
Bundle size
< 40 KB gzipped
Time to live
3–7 days
Reward latency
< 400 ms end-to-end

1. Quick start #

If you already have a checkout page with a payment button, you can be running in sandbox in under five minutes. The SDK auto-mounts a widget, handles the opt-in toggle, fee display and entry recording — you keep your existing payment gateway.

checkout.htmlhtml
<script src="https://cdn.gbemidebe.ng/sdk/v1/gbemidebe-sdk.min.js"></script>
<script>
  const gbemidebe = Gbemidebe.init({
    partnerId: "PSP-123",
    apiKey:    "gbemidebe_test_...",
    environment: "sandbox",
    checkout: {
      summaryContainer: "#order-summary",
      totalAmount:      "#total-amount",
      payButton:        "#pay-button"
    },
    purchaseAmount: 500000, // 5,000 NGN in kobo
    country:  "NG",
    currency: "NGN"
  });
</script>
i

Need a sandbox key? Email partnerships@gbemidebe.ng and we’ll issue one within a business day.

2. Installation #

Pick the channel that fits your build pipeline. The CDN is recommended for the fastest start; npm is recommended if you bundle JS through Webpack, Vite, esbuild or similar.

index.htmlhtml
<script src="https://cdn.gbemidebe.ng/sdk/v1/gbemidebe-sdk.min.js" defer></script>
terminalshell
npm install @gbemidebe/web
terminalshell
yarn add @gbemidebe/web
terminalshell
pnpm add @gbemidebe/web

CDN versioning

Pin to a major version (/sdk/v1/) to receive patch and minor updates automatically. To pin to an exact version (e.g. for compliance audits), use the immutable path:

versioned.html
<script src="https://cdn.gbemidebe.ng/sdk/v1.2.0/gbemidebe-sdk.min.js"></script>

3. Initialization #

Call Gbemidebe.init() once per page load, after the DOM containing your checkout selectors is available.

init.jsjavascript
import { init } from "@gbemidebe/web";

const gbemidebe = init({
  partnerId:   "PSP-123",
  apiKey:      "gbemidebe_live_...",
  environment: "production",
  language:    "auto",         // "auto" | "en" | "fr" | "es"
  flowType:    "non_psp_customer", // or "psp_customer"

  checkout: {
    summaryContainer: "#order-summary",
    totalAmount:      "#total-amount",
    payButton:        "#pay-button"
  },

  purchaseAmount: 500000,
  country:  "NG",
  currency: "NGN",

  onReady:  () => console.log("Gbemidebe ready"),
  onOptIn:  (data) => console.log("Opted in", data),
  onOptOut: () => console.log("Opted out"),
  onError:  (err) => console.error(err)
});

Parameters #

FieldRequiredDescription
partnerIdYesPSP identifier assigned by Gbemidebe during onboarding.
apiKeyYesPublic, domain-locked API key. Use the gbemidebe_test_ prefix in sandbox, gbemidebe_live_ in production.
environmentYes"sandbox" or "production".
countryYesISO 3166-1 alpha-2. Drives cycle resolution (Global → Market → PSP-in-Market).
currencyYesISO 4217 currency code.
purchaseAmountYesAmount in minor units (kobo, cents, pence…).
checkoutYesCSS selectors for your summary container, total element and pay button.
flowTypeNo"psp_customer" (logged-in PSP user) or "non_psp_customer" (guest, requires phone/email). Default: non_psp_customer.
languageNo"auto" (default), "en", "fr" or "es".
debugNoSet to true to enable verbose logging.

Environments #

Sandbox is fully isolated — no live money moves, draws are deterministic, and you can replay any pot. Production keys are issued after merchant KYC is approved.

EnvironmentAPI hostCDNFunds
Sandboxapi.sandbox.gbemidebe.ngcdn.gbemidebe.ng/sdk/v1/Test only
Productionapi.gbemidebe.ngcdn.gbemidebe.ng/sdk/v1/Live

4. Auto-integration mode #

The simplest integration. Provide selectors for your summary, total and pay button — the SDK does the rest. It injects the opt-in widget, updates the displayed total when the user opts in, intercepts the pay button click to record the entry, and dispatches a custom event once the entry is confirmed.

When to use: standard HTML / JS checkouts where you can expose the total amount and pay button via CSS selectors.

checkout.htmlhtml
<div id="order-summary">
  <div>Subtotal: ₦5,000</div>
  <div>Total: <span id="total-amount">₦5,000</span></div>
</div>

<button id="pay-button">Pay now</button>

<script>
  const gbemidebe = Gbemidebe.init({ /* see above */ });

  // Fired once the entry is recorded & payment can proceed
  document.addEventListener("gbemidebe:entry-recorded", (e) => {
    paymentGateway.charge({
      amount:   e.detail.totalAmount, // includes Gbemidebe fee
      metadata: { gbemidebe_entry_id: e.detail.entryId }
    });
  });
</script>

5. SDK-first flow #

For full control over the payment lifecycle, drive the flow explicitly: record a pending entry, run your payment, then confirm or fail the entry based on the result. This is the recommended path for custom checkouts and multi-step flows.

custom-checkout.jsjavascript
const gbemidebe = Gbemidebe.init({ partnerId, apiKey, environment: "sandbox" });

await gbemidebe.mount("#gbemidebe-widget", {
  country:        "NG",
  currency:       "NGN",
  purchaseAmount: 500000
});

document.getElementById("pay-button").addEventListener("click", async () => {
  if (!gbemidebe.isOptedIn()) {
    return processPayment(originalAmount);
  }

  // 1. Record pending entry
  const entry = await gbemidebe.recordEntry(`TXN-` + Date.now());
  if (!entry.success) return showError("Could not enter the draw");

  try {
    // 2. Run your payment
    const result = await processPayment(totalAmount, { gbemidebe_entry_id: entry.entryId });

    // 3a. Confirm on success
    await gbemidebe.confirmPayment("success", result.transactionId);
  } catch (err) {
    // 3b. Fail on error (refund-safe)
    await gbemidebe.confirmPayment("failed", null, err.message);
  }
});

recordEntry(transactionId) #

Reserves a slot in the active pot before payment. Entries live for 30 minutes in pending state — if you don’t confirm by then, the entry is auto-expired and excluded from draws.

ReturnsDescription
successBoolean. false indicates a session or validation issue — inspect error.
entryIdServer-issued entry identifier. Forward to your PSP as transaction metadata so the entry can be matched on webhook receipt.
statusAlways "pending" on success.
transactionIdEchoes the ID you provided. Idempotency key — calling twice with the same ID is safe.

confirmPayment(status, txnId?, reason?) #

Transitions the pending entry to valid or failed. Idempotent — calling twice returns the same result, so it is safe to retry on network errors.

StatusOutcome
"success"Entry becomes valid and joins the pot. Draw is scheduled per cycle config.
"failed"Entry is excluded from draws. No fee is captured.
!

Always call confirmPayment() — even on failure. This keeps your pending-entry ledger clean and unblocks accurate redemption analytics.

6. Events #

Listen to lifecycle events to drive analytics, custom UI, or downstream services.

events.jsjavascript
gbemidebe.on("ready",       () => {});
gbemidebe.on("optin",       (d) => analytics.track("gbemidebe_optin", d));
gbemidebe.on("optout",      () => {});
gbemidebe.on("feeUpdated",  (fee) => {});
gbemidebe.on("entry",       (d) => console.log(d.entryId, d.status));
gbemidebe.on("error",       (err) => console.error(err.code, err.message));

7. Theming #

The default widget inherits sensible neutrals that match most checkouts. Override via runtime tokens or CSS classes.

Runtime tokens

theme.jsjavascript
gbemidebe.setTheme({
  colorPrimary: "#2b3a1e",
  colorAccent:  "#d4ff4a",
  colorError:   "#d32f2f",
  fontFamily:   "Inter, sans-serif",
  borderRadius: "12px",
  toggleStyle:  "switch"  // "switch" | "checkbox"
});

CSS classes

For deeper control, target the scoped classes the widget renders — they are part of the public contract.

ClassElement
.gbemidebe-widgetRoot container
.gbemidebe-toggleOpt-in switch / checkbox
.gbemidebe-fee-displayConfigured fee amount
.gbemidebe-contact-inputPhone / email fields (Scenario B)
.gbemidebe-terms-linkLocalized compliance text
.gbemidebe-errorInline validation messages

8. Security model #

The SDK is the only client that talks to Gbemidebe. Your PSP backend never calls the Gbemidebe API directly — it only receives signed webhooks. This narrows the trust surface and removes signing keys from your application code.

What the SDK does NOT do

Signatures & tokens

MechanismPurpose
Session tokenDomain-locked, rotating, ephemeral. Proves the request originated from a valid SDK session.
Fee signatureHMAC-SHA256 over the fee + currency + cycle. Prevents fee tampering in transit.
Metadata signatureHMAC-SHA256 over the full payload. Prevents fake opt-ins reaching the Gbemidebe webhook handler.
TimestampSignatures expire after 15 minutes. Call gbemidebe.refreshMetadata() if your checkout sits idle.
TLS 1.3 + cert pinningSDK ↔ Gbemidebe Backend channel hardened against MITM.

Webhook verification

Gbemidebe will POST a signed payload to your registered webhook URL when an entry wins. Verify the X-GBEMIDEBE-Signature header before acting on the payload.

verify.phpphp
$payload   = $request->getContent();
$signature = $request->header("X-GBEMIDEBE-Signature");
$expected  = hash_hmac("sha256", $payload, $webhookSecret);

if (!hash_equals($expected, $signature)) {
    abort(401, "Invalid signature");
}

9. Mobile SDKs #

Same API surface, native UI. Both packages wrap the shared TypeScript core, so behaviour matches the web SDK exactly.

Checkout.tsxtsx
import { GbemidebeWidget, useGbemidebe } from "@gbemidebe/react-native";

function Checkout() {
  const { metadata, isOptedIn } = useGbemidebe({
    partnerId: "PSP-123",
    apiKey:    "gbemidebe_test_...",
    country:   "NG",
    currency:  "NGN",
    amount:    5000
  });

  return (
    <View>
      <GbemidebeWidget />
      <Button title="Pay" onPress={() => handlePayment(metadata)} />
    </View>
  );
}
checkout.dartdart
import 'package:gbemidebe_sdk/gbemidebe_sdk.dart';

class CheckoutPage extends StatefulWidget {
  @override
  Widget build(BuildContext context) {
    return Column(children: [
      GbemidebeWidget(
        partnerId: "PSP-123",
        apiKey:    "gbemidebe_test_...",
        country:   "NG",
        currency:  "NGN",
        amount:    5000,
        onMetadataReady: (m) => _metadata = m
      ),
      ElevatedButton(onPressed: processPayment, child: Text("Pay"))
    ]);
  }
}

10. Error handling #

All errors surface through the onError callback and the "error" event. Codes are stable and safe to switch on.

CodeCauseResolution
SDK_INIT_FAILEDInitialization failedVerify partnerId, apiKey and network access.
INVALID_PROVIDERUnknown partnerIdConfirm with Gbemidebe onboarding.
INVALID_CURRENCYCurrency not supported in marketCheck the country × currency matrix in the dashboard.
INVALID_COUNTRYCountry not enabled for your accountRequest market activation via partnerships.
FEE_CONFIG_ERRORNo cycle configuredSet a Global / Market / PSP-in-Market cycle.
VALIDATION_ERRORPhone / email invalidDisplay the inline error — SDK already does this.
SESSION_EXPIREDSignatures older than 15 minutesCall gbemidebe.refreshMetadata() before retrying.
ENTRY_EXPIRED30 minutes since recordEntry()Call recordEntry() again with a fresh transaction ID.
NETWORK_ERRORConnection to Gbemidebe failedRetry with exponential backoff; the widget shows a disabled state.

11. Go-live checklist #

  1. Sandbox API key issued and stored in your secrets manager.
  2. SDK loaded via CDN or installed via npm; version pinned for production.
  3. partnerId, country and currency wired up correctly per market.
  4. Opt-in widget renders inside checkout flow; total updates on toggle.
  5. Pay button calls recordEntry() (SDK-first) or auto-integration is configured.
  6. confirmPayment() called for both success and failure paths.
  7. Webhook endpoint registered, verified with X-GBEMIDEBE-Signature.
  8. Error handler displays user-facing messages for SESSION_EXPIRED and NETWORK_ERROR.
  9. Sandbox transaction tested end-to-end with a deterministic Mode 1 (First-to-Fill) draw.
  10. Production key issued after merchant KYC approval.

Ready to go live?

30-minute call. Sandbox keys the same day. Live in your product next week.