v1.0 — Phase 1 Partner Dashboard →

Bragg Integration Guide

Version: 1.0 — Phase 1 Sandbox: sandbox.bragglabs.com.ng Support: partners@bragglabs.com.ng

What Bragg Is

Bragg is NFC/Soft-POS infrastructure. You bring your licensed banking rails; Bragg turns any Android phone into a certified payment terminal.

Customer phone (HCE) ──tap──► Merchant phone (Bragg SDK) │ cryptogram + NFC token │ Your app (bank / fintech) │ Your own NIBSS / card scheme rails │ Settlement (your responsibility)

Bragg's job ends at returning the cryptogram and tap event. What you do with it is yours.

Quickstart — Sandbox in 60 Seconds

Use the sandbox at sandbox.bragglabs.com.ng. Pre-seeded credentials are on the portal landing page.

# 1. Get a partner token
curl -s -X POST https://sandbox.bragglabs.com.ng/auth/token \
  -H "Content-Type: application/json" \
  -d '{"partner_id":"sandboxdemo","secret":"sandboxdemo2026xx"}' | jq .token

# 2. Generate an NFC payment token (5 min expiry)
curl -s "https://sandbox.bragglabs.com.ng/v1/wallets/WALLET_ID/token?amount=5000" \
  -H "Authorization: Bearer $TOKEN" | jq .

# 3. Submit a transaction
curl -s -X POST https://sandbox.bragglabs.com.ng/v1/transactions \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"wallet_id":"WALLET_ID","merchant_id":"MERCHANT_ID","amount":5000,"currency":"NGN","pin":"1234"}' | jq .

Authentication

Partner Token

All partner API calls require a JWT. Obtain one via:

POST /auth/token
Content-Type: application/json

{
  "partner_id": "your-partner-id",
  "secret":     "your-partner-secret"
}
// Response
{
  "token":      "eyJ...",
  "partner_id": "your-partner-id",
  "expires_in": "24h"
}

Pass on every request: Authorization: Bearer eyJ...

Tokens expire after 24 hours. Refresh by calling /auth/token again.

User Token (Customer App)

For customer-facing operations (balance check, PIN set):

POST /auth/user
Content-Type: application/json

{
  "wallet_id": "0665ee59-be51-4855-b9d2-8727deac21df",
  "pin":       "1234"
}

Wallets

Create a Wallet

POST /v1/wallets
Authorization: Bearer {partner_token}

{
  "user_id":    "your-internal-user-id",
  "first_name": "Amara",
  "last_name":  "Okafor",
  "currency":   "NGN"
}
// Response
{
  "id":         "0665ee59-be51-4855-b9d2-8727deac21df",
  "user_id":    "your-internal-user-id",
  "balance":    0,
  "currency":   "NGN",
  "created_at": "2026-06-06T07:23:36Z",
  "version":    1
}

Store the id — it's the wallet identifier used in all subsequent calls.

Set Wallet PIN

The customer sets a 4–6 digit PIN before their first tap:

POST /v1/wallets/{wallet_id}/pin
Authorization: Bearer {partner_token}

{ "pin": "1234" }

Merchants

Register a Merchant

POST /v1/merchants
Authorization: Bearer {partner_token}

{
  "business_name":      "Kemi's Store",
  "owner_name":         "Kemi Adeyemi",
  "email":              "kemi@store.com",
  "phone":              "08012345678",
  "settlement_account": "0123456789",
  "bank_code":          "058",
  "address":            "12 Broad Street, Lagos Island",
  "state":              "Lagos"
}
// Response
{
  "id":          "6bd82ff7-2d1d-4af0-ac06-87d3c7eb3594",
  "status":      "PENDING",
  "terminal_id": "TID-487568-342150"
}

Merchants start as PENDING. Bragg admin approves them — or request auto-approval for your sandbox testing.

The NFC Tap Flow

The core Bragg flow in four steps:

1

Generate HCE Token (Customer App)

Called before the customer taps. Token expires in 5 minutes.

2

Customer Taps Merchant Phone

HCE transmits the token over NFC. BraggTerminal SDK reads it and surfaces token + cryptogram to your app.

3

Submit Transaction

Your app posts the tap event to POST /v1/transactions.

4

Receive tap.completed Webhook

Bragg fires the full NFC payload to your webhook. Use it to trigger your own payment processing.

Step 1 — Generate HCE Token

GET /v1/wallets/{wallet_id}/token?amount=5000
Authorization: Bearer {partner_token}

// Response
{
  "token":      "MDY2NWVlNTkt...",
  "cryptogram": "055c2f8a5ed6...",
  "expires_at": 1780734862
}

Step 3 — Submit Transaction

POST /v1/transactions
Authorization: Bearer {partner_token}

{
  "wallet_id":   "0665ee59-be51-4855-b9d2-8727deac21df",
  "merchant_id": "6bd82ff7-2d1d-4af0-ac06-87d3c7eb3594",
  "amount":      5000,
  "currency":    "NGN",
  "token":       "MDY2NWVlNTkt...",
  "cryptogram":  "055c2f8a5ed6..."
}

// Response
{
  "id":          "742b9942-f01f-4bed-84e6-faa01ac876d5",
  "status":      "APPROVED",
  "amount":      5000,
  "fraud_score": 0.02,
  "type":        "NFC_TAP"
}

Step 4 — tap.completed Webhook Payload

{
  "id":         "delivery-uuid",
  "event_type": "tap.completed",
  "created_at": "2026-06-06T08:29:22Z",
  "data": {
    "transaction_id": "742b9942-...",
    "wallet_token":   "MDY2NWVlNTkt...",
    "cryptogram":     "055c2f8a5ed6...",
    "wallet_id":      "0665ee59-...",
    "merchant_id":    "6bd82ff7-...",
    "terminal_id":    "6bd82ff7-...",
    "amount":         5000,
    "currency":       "NGN",
    "status":         "APPROVED",
    "fraud_score":    0.02
  }
}

Webhooks

Register an Endpoint

POST /v1/webhooks
Authorization: Bearer {partner_token}

{
  "partner_id": "your-partner-id",
  "url":        "https://your-app.com/bragg/webhook",
  "secret":     "your-webhook-secret-min-16-chars",
  "events":     ["tap.completed", "settlement.batch"]
}

Leave events as [] to receive all event types.

Verify Signatures

Every webhook includes an X-Bragg-Signature header. Always verify it before processing.

# Python
import hmac, hashlib

def verify(secret: str, payload: bytes, signature: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)
// Node.js
const crypto = require('crypto');
function verify(secret, payload, signature) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Event Types

EventWhen
tap.completedEvery NFC tap (approved or declined)
settlement.batchDaily settlement batch ready for disbursement
transaction.approvedTransaction approved
transaction.declinedTransaction declined
fraud.signalCross-partner fraud signal raised

Settlement

Bragg calculates settlement batches and sends them to you. You disburse to merchants via your own NIBSS/NIP rails.

1

Daily at 23:00 UTC

Bragg calculates unsettled approved transactions per merchant.

2

settlement.batch webhook fires

Contains net amounts, settlement account, and bank code for each merchant.

3

You disburse

Transfer net_amount to settlement_account at bank_code using nibss_reference as narration.

4

Confirm to Bragg

POST /v1/settlements/{id}/confirm with your NIP session reference.

settlement.batch Webhook

{
  "event_type":         "settlement.batch",
  "settlement_id":      "b7c67632-1353-4710-81a1-b778815bde14",
  "merchant_id":        "6bd82ff7-...",
  "gross_amount":       5000,
  "platform_fee":       25,
  "net_amount":         4975,
  "transaction_count":  1,
  "currency":           "NGN",
  "settlement_account": "0123456789",
  "bank_code":          "058",
  "nibss_reference":    "BRAGG-20260606-6BD82FF7-747340"
}

Confirm Settlement

POST /v1/settlements/{settlement_id}/confirm
Authorization: Bearer {partner_token}

{ "partner_nip_reference": "your-nip-session-id" }

// Response
{
  "id":                    "b7c67632-...",
  "status":                "COMPLETED",
  "partner_nip_reference": "your-nip-session-id",
  "settled_at":            "2026-06-06T08:18:40Z"
}
Bragg charges 0.5% (50 bps) of gross volume per batch. net_amount is already after fee deduction.

Android SDK

Customer App — BraggSDK (HCE)

// build.gradle
implementation 'ng.bragglabs:sdk:1.0.0'
BraggSDK.init(
    context   = this,
    baseUrl   = "https://bragglabs.com.ng",
    partnerId = "your-partner-id"
)

The SDK handles HCE token generation and NFC transmission automatically.

Merchant App — BraggTerminal (NFC Reader)

BraggTerminal.init(
    context    = this,
    baseUrl    = "https://bragglabs.com.ng",
    merchantId = "6bd82ff7-2d1d-4af0-ac06-87d3c7eb3594"
)

// Listen for taps
BraggTerminal.onTap { token, cryptogram, amount ->
    // Submit to your backend → POST /v1/transactions
}

BraggTerminal also supports Card-on-Phone — it falls back to EMV PPSE when a physical Verve/Visa/Mastercard contactless card taps instead of an HCE phone.

Requirements

Android8.0+ (API 26)
Merchant deviceNFC hardware required
Customer deviceHCE support (most Android phones 2018+)

API Reference

MethodEndpointDescription
POST/auth/tokenGet partner JWT
POST/auth/userGet user JWT
POST/v1/walletsCreate wallet
GET/v1/wallets/{id}Get wallet
GET/v1/partner/walletsList your wallets
POST/v1/wallets/{id}/pinSet/update PIN
GET/v1/wallets/{id}/tokenGenerate HCE payment token
POST/v1/transactionsSubmit tap transaction
GET/v1/transactions/{id}Get transaction
GET/v1/transactions?wallet_id=List transactions
POST/v1/merchantsRegister merchant
GET/v1/merchantsList merchants
GET/v1/merchants/{id}/balanceGet settlement balance
POST/v1/webhooksRegister webhook endpoint
GET/v1/settlementsList settlement batches
POST/v1/settlements/{id}/confirmConfirm disbursement
POST/v1/kyc/verify-accountNUBAN name enquiry

Error Responses

All errors: { "error": "human readable message" }

HTTP CodeMeaning
400Bad request — check your payload
401Invalid or expired token
403Forbidden — wrong partner scope
404Resource not found
409Conflict — duplicate or wrong state
422Validation error (KYC, account check)
429Rate limit exceeded
500Server error — contact support

Going Live

1

Get a production partner account

Contact partners@bragglabs.com.ng to provision credentials.

2

Update base URL

Switch from sandbox.bragglabs.com.ng to bragglabs.com.ng in your SDK init and API calls.

3

Rebuild Android APKs

Update the baseUrl in both BraggSDK and BraggTerminal init calls and publish to Play Store.

4

Configure your webhook endpoint

Must be HTTPS and respond within 10 seconds. Bragg retries up to 3 times with exponential backoff.

5

Wire up NIBSS/NIP rails

Your backend must handle settlement.batch webhooks and call the confirm endpoint after disbursement.