API Reference

Route-by-route public reference for the SparkGlim white-label tenant API.

Search Endpoints

Find routes by endpoint path, section, method, parameter, or integration keyword.

Showing 9 of 9 endpoints

Authentication

Signature model, header contract, key scopes, and request verification.

GET
Authentication
v1

Get Tenant Context

Validate Authentication And Load Tenant Context

Base URL

https://api.sparkglim.net

Endpoint

GET /api/white-label/v1/context

Overview

Use this endpoint as your integration health check. It verifies your signed request and returns account identity, branding, domains, settings, and provider summary.

How It Works

  1. Client computes HMAC signature using tenant secret and canonical request string.
  2. Backend verifies key status, scope, timestamp window, and signature integrity.
  3. If valid, backend assembles account, domain, settings, and provider snapshots into one response.
  4. Response includes requestId for logging and support tracing.

Authentication

  • Requires signed headers (`x-white-label-key-id`, `x-white-label-timestamp`, `x-white-label-signature`).
  • API key must include `settings:read` scope.

Security Notes

  • Never expose white-label API secrets in frontend or mobile clients.
  • Rotate key pairs regularly from the admin dashboard and revoke old keys immediately.
  • Store requestId values for incident response and support correlation.

Request Parameters

x-white-label-key-id

header
string
required

Tenant-issued API key identifier.

x-white-label-timestamp

header
string (unix milliseconds)
required

Request timestamp used for replay protection.

x-white-label-signature

header
string (hex HMAC-SHA256)
required

Signature over `${timestamp}.${METHOD}.${path}.${body}`.

content-type

header
application/json
required

JSON payload transport contract.

Response Format

200 Success

Tenant context returned successfully.

{
  "success": true,
  "data": {
    "account": {
      "id": "acc_5f0efc7",
      "accountSlug": "acme-events",
      "platformName": "Acme Events"
    },
    "branding": {
      "platformName": "Acme Events",
      "primaryDomain": "events.acme.com"
    },
    "domains": [
      {
        "hostname": "events.acme.com",
        "isPrimary": true,
        "sslStatus": "active"
      }
    ],
    "settings": {
      "payments": {},
      "notifications": {}
    },
    "providerSummary": []
  },
  "requestId": "wlapi_d2f2ac17"
}

Error Responses

400 Validation Error

Payload or query validation failed while trying to load tenant context.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

401 Authentication Error

Missing headers, stale timestamp, or invalid HMAC signature.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

403 Scope Denied

API key does not include the required scope for this endpoint.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

429 Rate Limit Error

Too many requests in a short time window.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

Status Codes

200 - Context response generated.
400 - Validation or malformed payload.
401 - Missing/invalid authentication or signature mismatch.
403 - Authenticated but scope or account status denies access.
429 - Rate limit exceeded.
500 - Unexpected server failure.

Code Examples

JavaScript (fetch + Node crypto)

import crypto from 'crypto'

const baseUrl = 'https://api.sparkglim.net'
const keyId = process.env.WHITE_LABEL_KEY_ID
const secret = process.env.WHITE_LABEL_SECRET

const timestamp = Date.now().toString()
const method = 'GET'
const path = '/api/white-label/v1/context'
const body = {}

const serializedBody = method === 'GET' || method === 'HEAD' ? '{}' : JSON.stringify(body)
const canonical = `${timestamp}.${method}.${path}.${serializedBody}`
const signature = crypto.createHmac('sha256', secret).update(canonical).digest('hex')

const response = await fetch(`${baseUrl}${path}`, {
  method,
  headers: {
    'content-type': 'application/json',
    'x-white-label-key-id': keyId,
    'x-white-label-timestamp': timestamp,
    'x-white-label-signature': signature,
  },
  body: method === 'GET' || method === 'HEAD' ? undefined : serializedBody,
})

const payload = await response.json()
console.log(payload)

Error Handling

  • Always parse `{ success, error, requestId }` on non-2xx responses.
  • Treat 400 as validation failure, 401 as auth/signature mismatch, 403 as scope denial, and 429 as throttling.
  • Log requestId and endpoint for every failed request before retry or escalation.

Rate Limits And Abuse Protection

  • White-label API applies per-account and per-IP in-memory throttling in the backend service.
  • Burst traffic can trigger HTTP 429; apply exponential backoff and retry with jitter.
  • Repeated signature failures can be treated as abuse and temporarily blocked.

Campaigns

Campaign management and campaign-driven payment initialization flows.

POST
Campaigns
v1

Create Campaign

Create A Tenant Campaign In The White-Label Scope

Base URL

https://api.sparkglim.net

Endpoint

POST /api/white-label/v1/campaigns

Overview

Creates a campaign under the authenticated white-label account and mirrors operational records into SparkGlim-owned public tables.

How It Works

  1. Backend validates payload schema, required fields, and campaign status/type combinations.
  2. Campaign is written in public operational tables with account ownership metadata.
  3. White-label mirror tables are updated for tenant-specific operations and sync observability.
  4. Response returns created record and requestId.

Authentication

  • Requires signed headers and `campaigns:write` scope.
  • Account must be enabled and not suspended/revoked.

Security Notes

  • Never expose white-label API secrets in frontend or mobile clients.
  • Rotate key pairs regularly from the admin dashboard and revoke old keys immediately.
  • Store requestId values for incident response and support correlation.

Request Parameters

x-white-label-key-id

header
string
required

Tenant-issued API key identifier.

x-white-label-timestamp

header
string (unix milliseconds)
required

Request timestamp used for replay protection.

x-white-label-signature

header
string (hex HMAC-SHA256)
required

Signature over `${timestamp}.${METHOD}.${path}.${body}`.

content-type

header
application/json
required

JSON payload transport contract.

title

body
string
required

Campaign display title.

description

body
string
required

Campaign narrative copy.

campaign_type

body
voting | donation | ticketing
required

Campaign mode.

status

body
draft | pending_approval | approved | rejected | archived
optional

Initial moderation state.

start_date

body
ISO datetime
required

Campaign start timestamp.

end_date

body
ISO datetime
required

Campaign end timestamp.

metadata

body
object
optional

External IDs and custom integration metadata.

Request Example

{
  "title": "Acme Awards 2026",
  "description": "Annual awards voting campaign for the Acme community.",
  "slug": "acme-awards-2026",
  "campaign_type": "voting",
  "status": "draft",
  "start_date": "2026-05-01T00:00:00.000Z",
  "end_date": "2026-06-01T00:00:00.000Z",
  "vote_price": 2,
  "verification_required": true,
  "metadata": {
    "externalCampaignId": "CAM-001"
  }
}

Response Format

201 Created

Campaign created and mirrored successfully.

{
  "success": true,
  "data": {
    "id": "a0713b34-5fda-4685-9fbe-165d6479d5c9",
    "title": "Acme Awards 2026",
    "campaign_type": "voting",
    "status": "draft"
  },
  "requestId": "wlapi_d2f2ac17"
}

Error Responses

400 Validation Error

Payload or query validation failed while trying to create campaign.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

401 Authentication Error

Missing headers, stale timestamp, or invalid HMAC signature.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

403 Scope Denied

API key does not include the required scope for this endpoint.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

429 Rate Limit Error

Too many requests in a short time window.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

Status Codes

201 - Campaign created.
400 - Validation or malformed payload.
401 - Missing/invalid authentication or signature mismatch.
403 - Authenticated but scope or account status denies access.
429 - Rate limit exceeded.
500 - Unexpected server failure.

Code Examples

JavaScript (fetch + Node crypto)

import crypto from 'crypto'

const baseUrl = 'https://api.sparkglim.net'
const keyId = process.env.WHITE_LABEL_KEY_ID
const secret = process.env.WHITE_LABEL_SECRET

const timestamp = Date.now().toString()
const method = 'POST'
const path = '/api/white-label/v1/campaigns'
const body = {
  "title": "Acme Awards 2026",
  "description": "Annual awards voting campaign for the Acme community.",
  "slug": "acme-awards-2026",
  "campaign_type": "voting",
  "status": "draft",
  "start_date": "2026-05-01T00:00:00.000Z",
  "end_date": "2026-06-01T00:00:00.000Z"
}

const serializedBody = method === 'GET' || method === 'HEAD' ? '{}' : JSON.stringify(body)
const canonical = `${timestamp}.${method}.${path}.${serializedBody}`
const signature = crypto.createHmac('sha256', secret).update(canonical).digest('hex')

const response = await fetch(`${baseUrl}${path}`, {
  method,
  headers: {
    'content-type': 'application/json',
    'x-white-label-key-id': keyId,
    'x-white-label-timestamp': timestamp,
    'x-white-label-signature': signature,
  },
  body: method === 'GET' || method === 'HEAD' ? undefined : serializedBody,
})

const payload = await response.json()
console.log(payload)

Error Handling

  • Always parse `{ success, error, requestId }` on non-2xx responses.
  • Treat 400 as validation failure, 401 as auth/signature mismatch, 403 as scope denial, and 429 as throttling.
  • Log requestId and endpoint for every failed request before retry or escalation.

Rate Limits And Abuse Protection

  • White-label API applies per-account and per-IP in-memory throttling in the backend service.
  • Burst traffic can trigger HTTP 429; apply exponential backoff and retry with jitter.
  • Repeated signature failures can be treated as abuse and temporarily blocked.
GET
Campaigns
v1

List Campaigns

List Tenant Campaigns With Search And Status Filters

Base URL

https://api.sparkglim.net

Endpoint

GET /api/white-label/v1/campaigns?search=awards&status=approved

Overview

Returns white-label account campaigns from the synchronized campaign store and supports simple search/status filtering.

How It Works

  1. Backend validates optional query parameters.
  2. Query is scoped to authenticated account only.
  3. Paginated campaign records are returned with requestId for traceability.

Authentication

  • Requires signed headers and `campaigns:read` scope.
  • Query is automatically account-scoped; cross-account access is blocked.

Security Notes

  • Never expose white-label API secrets in frontend or mobile clients.
  • Rotate key pairs regularly from the admin dashboard and revoke old keys immediately.
  • Store requestId values for incident response and support correlation.

Request Parameters

x-white-label-key-id

header
string
required

Tenant-issued API key identifier.

x-white-label-timestamp

header
string (unix milliseconds)
required

Request timestamp used for replay protection.

x-white-label-signature

header
string (hex HMAC-SHA256)
required

Signature over `${timestamp}.${METHOD}.${path}.${body}`.

content-type

header
application/json
required

JSON payload transport contract.

search

query
string
optional

Case-insensitive title/slug search.

status

query
string
optional

Campaign status filter.

Response Format

200 Success

Filtered campaigns returned.

{
  "success": true,
  "data": [
    {
      "id": "a0713b34-5fda-4685-9fbe-165d6479d5c9",
      "title": "Acme Awards 2026",
      "campaign_type": "voting",
      "status": "approved"
    }
  ],
  "requestId": "wlapi_d2f2ac17"
}

Error Responses

400 Validation Error

Payload or query validation failed while trying to list campaigns.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

401 Authentication Error

Missing headers, stale timestamp, or invalid HMAC signature.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

403 Scope Denied

API key does not include the required scope for this endpoint.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

429 Rate Limit Error

Too many requests in a short time window.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

Status Codes

200 - Campaign list returned.
400 - Validation or malformed payload.
401 - Missing/invalid authentication or signature mismatch.
403 - Authenticated but scope or account status denies access.
429 - Rate limit exceeded.
500 - Unexpected server failure.

Code Examples

JavaScript (fetch + Node crypto)

import crypto from 'crypto'

const baseUrl = 'https://api.sparkglim.net'
const keyId = process.env.WHITE_LABEL_KEY_ID
const secret = process.env.WHITE_LABEL_SECRET

const timestamp = Date.now().toString()
const method = 'GET'
const path = '/api/white-label/v1/campaigns?search=awards&status=approved'
const body = {}

const serializedBody = method === 'GET' || method === 'HEAD' ? '{}' : JSON.stringify(body)
const canonical = `${timestamp}.${method}.${path}.${serializedBody}`
const signature = crypto.createHmac('sha256', secret).update(canonical).digest('hex')

const response = await fetch(`${baseUrl}${path}`, {
  method,
  headers: {
    'content-type': 'application/json',
    'x-white-label-key-id': keyId,
    'x-white-label-timestamp': timestamp,
    'x-white-label-signature': signature,
  },
  body: method === 'GET' || method === 'HEAD' ? undefined : serializedBody,
})

const payload = await response.json()
console.log(payload)

Error Handling

  • Always parse `{ success, error, requestId }` on non-2xx responses.
  • Treat 400 as validation failure, 401 as auth/signature mismatch, 403 as scope denial, and 429 as throttling.
  • Log requestId and endpoint for every failed request before retry or escalation.

Rate Limits And Abuse Protection

  • White-label API applies per-account and per-IP in-memory throttling in the backend service.
  • Burst traffic can trigger HTTP 429; apply exponential backoff and retry with jitter.
  • Repeated signature failures can be treated as abuse and temporarily blocked.

Ticketing

Ticket type management and event gate verification/check-in flows.

POST
Ticketing
v1

Create Ticket Type

Create A Ticket Type For A Tenant Campaign

Base URL

https://api.sparkglim.net

Endpoint

POST /api/white-label/v1/ticket-types

Overview

Creates a ticket type record under a campaign and synchronizes that ticket type with white-label mirror tables for verification and channel operations.

How It Works

  1. Backend validates campaign ownership and ticket schema.
  2. Ticket type is inserted with quantity, pricing, attendee requirements, and status metadata.
  3. Mirror table sync metadata is written for reconciliation and analytics.

Authentication

  • Requires signed headers and `tickets:write` scope.
  • Campaign referenced by `campaignId` must belong to the authenticated account.

Security Notes

  • Never expose white-label API secrets in frontend or mobile clients.
  • Rotate key pairs regularly from the admin dashboard and revoke old keys immediately.
  • Store requestId values for incident response and support correlation.

Request Parameters

x-white-label-key-id

header
string
required

Tenant-issued API key identifier.

x-white-label-timestamp

header
string (unix milliseconds)
required

Request timestamp used for replay protection.

x-white-label-signature

header
string (hex HMAC-SHA256)
required

Signature over `${timestamp}.${METHOD}.${path}.${body}`.

content-type

header
application/json
required

JSON payload transport contract.

campaignId

body
uuid
required

Campaign target for ticket type.

name

body
string
required

Ticket display name.

ticket_type

body
paid | free | early_bird | vip | student | group
optional

Ticket category.

price

body
number
required

Unit amount in GHS.

quantity_available

body
integer
required

Sellable inventory.

required_attendee_fields

body
array<object>
optional

Structured attendee field definitions.

Request Example

{
  "campaignId": "20d7f99a-4308-4f9f-b7bb-57148850d06e",
  "name": "VIP Pass",
  "description": "Priority seating and fast-lane access",
  "ticket_type": "vip",
  "price": 150,
  "quantity_available": 200,
  "status": "active",
  "is_free": false,
  "max_per_person": 4,
  "required_attendee_fields": [
    { "key": "full_name", "label": "Full name", "type": "text", "required": true },
    { "key": "email", "label": "Email", "type": "email", "required": true }
  ]
}

Response Format

201 Created

Ticket type created successfully.

{
  "success": true,
  "data": {
    "id": "f8f32744-ec0e-4d31-a4f7-0ad90a8e6996",
    "name": "VIP Pass",
    "ticket_type": "vip",
    "price": 150,
    "quantity_available": 200
  },
  "requestId": "wlapi_d2f2ac17"
}

Error Responses

400 Validation Error

Payload or query validation failed while trying to create ticket type.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

401 Authentication Error

Missing headers, stale timestamp, or invalid HMAC signature.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

403 Scope Denied

API key does not include the required scope for this endpoint.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

429 Rate Limit Error

Too many requests in a short time window.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

Status Codes

201 - Ticket type created.
400 - Validation or malformed payload.
401 - Missing/invalid authentication or signature mismatch.
403 - Authenticated but scope or account status denies access.
429 - Rate limit exceeded.
500 - Unexpected server failure.

Code Examples

JavaScript (fetch + Node crypto)

import crypto from 'crypto'

const baseUrl = 'https://api.sparkglim.net'
const keyId = process.env.WHITE_LABEL_KEY_ID
const secret = process.env.WHITE_LABEL_SECRET

const timestamp = Date.now().toString()
const method = 'POST'
const path = '/api/white-label/v1/ticket-types'
const body = {
  "campaignId": "20d7f99a-4308-4f9f-b7bb-57148850d06e",
  "name": "VIP Pass",
  "ticket_type": "vip",
  "price": 150,
  "quantity_available": 200,
  "status": "active"
}

const serializedBody = method === 'GET' || method === 'HEAD' ? '{}' : JSON.stringify(body)
const canonical = `${timestamp}.${method}.${path}.${serializedBody}`
const signature = crypto.createHmac('sha256', secret).update(canonical).digest('hex')

const response = await fetch(`${baseUrl}${path}`, {
  method,
  headers: {
    'content-type': 'application/json',
    'x-white-label-key-id': keyId,
    'x-white-label-timestamp': timestamp,
    'x-white-label-signature': signature,
  },
  body: method === 'GET' || method === 'HEAD' ? undefined : serializedBody,
})

const payload = await response.json()
console.log(payload)

Error Handling

  • Always parse `{ success, error, requestId }` on non-2xx responses.
  • Treat 400 as validation failure, 401 as auth/signature mismatch, 403 as scope denial, and 429 as throttling.
  • Log requestId and endpoint for every failed request before retry or escalation.

Rate Limits And Abuse Protection

  • White-label API applies per-account and per-IP in-memory throttling in the backend service.
  • Burst traffic can trigger HTTP 429; apply exponential backoff and retry with jitter.
  • Repeated signature failures can be treated as abuse and temporarily blocked.
POST
Ticketing
v1

Verify Ticket

Verify Ticket Code And Optionally Auto-Check-In

Base URL

https://api.sparkglim.net

Endpoint

POST /api/white-label/v1/tickets/verify

Overview

Validates ticket ownership and check-in status for gate operations. Use this endpoint for scanning devices and controlled check-in flows.

How It Works

  1. Scanner or gate backend submits `ticketCode`.
  2. Backend resolves account-scoped ticket and current check-in state.
  3. If `autoVerify` is true and scope allows write actions, check-in is applied atomically.
  4. Verification response returns status and normalized attendee context.

Authentication

  • Requires signed headers and `tickets:read` scope.
  • For state mutation, pair with `tickets:write` and explicit check-in endpoint where required.

Security Notes

  • Never expose white-label API secrets in frontend or mobile clients.
  • Rotate key pairs regularly from the admin dashboard and revoke old keys immediately.
  • Store requestId values for incident response and support correlation.

Request Parameters

x-white-label-key-id

header
string
required

Tenant-issued API key identifier.

x-white-label-timestamp

header
string (unix milliseconds)
required

Request timestamp used for replay protection.

x-white-label-signature

header
string (hex HMAC-SHA256)
required

Signature over `${timestamp}.${METHOD}.${path}.${body}`.

content-type

header
application/json
required

JSON payload transport contract.

ticketCode

body
string
required

Ticket code or QR token value.

autoVerify

body
boolean
optional

When true, automatically verify/check-in when policy permits.

checkedInBy

body
string
optional

Gate agent identifier for audit trails.

Request Example

{
  "ticketCode": "WL-ABC123",
  "autoVerify": false,
  "checkedInBy": "gate-agent-01"
}

Response Format

200 Success

Ticket verification data returned.

{
  "success": true,
  "data": {
    "status": "valid",
    "ticketCode": "WL-ABC123",
    "checkedIn": false,
    "campaign": {
      "id": "20d7f99a-4308-4f9f-b7bb-57148850d06e",
      "title": "Acme Awards 2026"
    },
    "attendee": {
      "full_name": "Jane Guest",
      "email": "jane@example.com"
    }
  },
  "requestId": "wlapi_d2f2ac17"
}

Error Responses

400 Validation Error

Payload or query validation failed while trying to verify ticket.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

401 Authentication Error

Missing headers, stale timestamp, or invalid HMAC signature.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

403 Scope Denied

API key does not include the required scope for this endpoint.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

429 Rate Limit Error

Too many requests in a short time window.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

Status Codes

200 - Ticket verification completed.
400 - Validation or malformed payload.
401 - Missing/invalid authentication or signature mismatch.
403 - Authenticated but scope or account status denies access.
429 - Rate limit exceeded.
500 - Unexpected server failure.

Code Examples

JavaScript (fetch + Node crypto)

import crypto from 'crypto'

const baseUrl = 'https://api.sparkglim.net'
const keyId = process.env.WHITE_LABEL_KEY_ID
const secret = process.env.WHITE_LABEL_SECRET

const timestamp = Date.now().toString()
const method = 'POST'
const path = '/api/white-label/v1/tickets/verify'
const body = {
  "ticketCode": "WL-ABC123",
  "autoVerify": false
}

const serializedBody = method === 'GET' || method === 'HEAD' ? '{}' : JSON.stringify(body)
const canonical = `${timestamp}.${method}.${path}.${serializedBody}`
const signature = crypto.createHmac('sha256', secret).update(canonical).digest('hex')

const response = await fetch(`${baseUrl}${path}`, {
  method,
  headers: {
    'content-type': 'application/json',
    'x-white-label-key-id': keyId,
    'x-white-label-timestamp': timestamp,
    'x-white-label-signature': signature,
  },
  body: method === 'GET' || method === 'HEAD' ? undefined : serializedBody,
})

const payload = await response.json()
console.log(payload)

Error Handling

  • Always parse `{ success, error, requestId }` on non-2xx responses.
  • Treat 400 as validation failure, 401 as auth/signature mismatch, 403 as scope denial, and 429 as throttling.
  • Log requestId and endpoint for every failed request before retry or escalation.

Rate Limits And Abuse Protection

  • White-label API applies per-account and per-IP in-memory throttling in the backend service.
  • Burst traffic can trigger HTTP 429; apply exponential backoff and retry with jitter.
  • Repeated signature failures can be treated as abuse and temporarily blocked.

Notifications

Outbound branded delivery and inbound provider callback expectations.

POST
Notifications
v1

Dispatch Notification

Send Branded Notifications Through Tenant Providers

Base URL

https://api.sparkglim.net

Endpoint

POST /api/white-label/v1/notifications

Overview

Dispatches event-driven messages through account-configured email or SMS providers while preserving tenant branding and audit records.

How It Works

  1. Backend validates channel, recipient, and payload contract.
  2. Provider routing resolves account defaults and channel overrides.
  3. Message dispatch is queued and persisted for monitoring.
  4. Response returns asynchronous dispatch identifiers for tracking.

Authentication

  • Requires signed headers and `notifications:write` scope.
  • Provider secrets remain server-side and are never returned in responses.

Security Notes

  • Never expose white-label API secrets in frontend or mobile clients.
  • Rotate key pairs regularly from the admin dashboard and revoke old keys immediately.
  • Store requestId values for incident response and support correlation.

Request Parameters

x-white-label-key-id

header
string
required

Tenant-issued API key identifier.

x-white-label-timestamp

header
string (unix milliseconds)
required

Request timestamp used for replay protection.

x-white-label-signature

header
string (hex HMAC-SHA256)
required

Signature over `${timestamp}.${METHOD}.${path}.${body}`.

content-type

header
application/json
required

JSON payload transport contract.

channel

body
email | sms
required

Delivery medium.

eventType

body
string
required

Event label for templates and analytics.

recipient

body
string
required

Email address or phone number.

subject

body
string
optional

Email subject. Optional for SMS.

payload

body
object
optional

Template variables or direct message content.

Request Example

{
  "channel": "email",
  "eventType": "ticket.purchase.confirmed",
  "recipient": "guest@example.com",
  "subject": "Your Acme ticket is confirmed",
  "payload": {
    "title": "Ticket confirmed",
    "html": "<p>Thank you for your purchase.</p>",
    "text": "Thank you for your purchase."
  }
}

Response Format

202 Accepted

Notification accepted for processing.

{
  "success": true,
  "data": {
    "channel": "email",
    "status": "queued",
    "eventType": "ticket.purchase.confirmed"
  },
  "requestId": "wlapi_d2f2ac17"
}

Error Responses

400 Validation Error

Payload or query validation failed while trying to dispatch notification.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

401 Authentication Error

Missing headers, stale timestamp, or invalid HMAC signature.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

403 Scope Denied

API key does not include the required scope for this endpoint.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

429 Rate Limit Error

Too many requests in a short time window.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

Status Codes

202 - Notification queued/accepted.
400 - Validation or malformed payload.
401 - Missing/invalid authentication or signature mismatch.
403 - Authenticated but scope or account status denies access.
429 - Rate limit exceeded.
500 - Unexpected server failure.

Code Examples

JavaScript (fetch + Node crypto)

import crypto from 'crypto'

const baseUrl = 'https://api.sparkglim.net'
const keyId = process.env.WHITE_LABEL_KEY_ID
const secret = process.env.WHITE_LABEL_SECRET

const timestamp = Date.now().toString()
const method = 'POST'
const path = '/api/white-label/v1/notifications'
const body = {
  "channel": "email",
  "eventType": "ticket.purchase.confirmed",
  "recipient": "guest@example.com",
  "subject": "Your Acme ticket is confirmed",
  "payload": {
    "title": "Ticket confirmed",
    "text": "Thank you for your purchase."
  }
}

const serializedBody = method === 'GET' || method === 'HEAD' ? '{}' : JSON.stringify(body)
const canonical = `${timestamp}.${method}.${path}.${serializedBody}`
const signature = crypto.createHmac('sha256', secret).update(canonical).digest('hex')

const response = await fetch(`${baseUrl}${path}`, {
  method,
  headers: {
    'content-type': 'application/json',
    'x-white-label-key-id': keyId,
    'x-white-label-timestamp': timestamp,
    'x-white-label-signature': signature,
  },
  body: method === 'GET' || method === 'HEAD' ? undefined : serializedBody,
})

const payload = await response.json()
console.log(payload)

Webhook Documentation

Event Types

  • ticket.purchase.confirmed
  • vote.payment.success
  • donation.payment.success
  • campaign.status.updated

Payload Structure

{
  "eventType": "ticket.purchase.confirmed",
  "channel": "email",
  "recipient": "guest@example.com",
  "payload": {
    "title": "Ticket confirmed",
    "text": "Thank you for your purchase."
  }
}

Verification Method

For outbound dispatch there is no callback signature from this endpoint itself. For inbound provider callbacks, use `/api/white-label/webhooks/:provider` and verify provider signatures before mutation.

Error Handling

  • Always parse `{ success, error, requestId }` on non-2xx responses.
  • Treat 400 as validation failure, 401 as auth/signature mismatch, 403 as scope denial, and 429 as throttling.
  • Log requestId and endpoint for every failed request before retry or escalation.

Rate Limits And Abuse Protection

  • White-label API applies per-account and per-IP in-memory throttling in the backend service.
  • Burst traffic can trigger HTTP 429; apply exponential backoff and retry with jitter.
  • Repeated signature failures can be treated as abuse and temporarily blocked.
POST
Notifications
v1

Provider Webhook Receiver

Receive Provider Callbacks For Reconciliation

Base URL

https://api.sparkglim.net

Endpoint

POST /api/white-label/webhooks/:provider

Overview

Inbound webhook endpoint for payment providers. Use this to confirm payment state and reconcile white-label and SparkGlim records.

How It Works

  1. Provider sends callback payload to `/api/white-label/webhooks/:provider`.
  2. Backend validates provider signature/secret before mutating any state.
  3. Transaction/ticket/vote/donation records are reconciled and sync events are logged.
  4. Always return a fast 200 after durable processing handoff.

Authentication

  • No tenant API key headers are required for provider callbacks.
  • Verification uses provider-specific signatures/secrets (`paystack`, `expresspay`, `hubtel`).

Security Notes

  • Reject unsupported providers with 400 before processing body.
  • Verify signatures using raw request body where required by provider.
  • Do not log raw secrets or unmasked auth headers in webhook traces.

Request Parameters

provider

path
paystack | expresspay | hubtel
required

Provider identifier.

x-paystack-signature

header
string
optional

Paystack callback signature header when provider is paystack.

x-expresspay-signature

header
string
optional

ExpressPay signature header when provider is expresspay.

body

body
provider event payload
required

Provider-specific callback body.

Response Format

200 Success

Webhook accepted and processed.

{
  "success": true,
  "processed": true,
  "provider": "paystack",
  "requestId": "wlapi_d2f2ac17"
}

Error Responses

400 Unsupported Provider

Provider path parameter is not supported.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

401 Verification Failed

Provider signature or secret validation failed.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

Status Codes

200 - Webhook processed.
400 - Unsupported provider or invalid payload.
401 - Signature verification failed.
500 - Unexpected processing failure.

Code Examples

JavaScript test callback

await fetch('https://api.sparkglim.net/api/white-label/webhooks/paystack', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'x-paystack-signature': '<provider-signature>',
  },
  body: JSON.stringify({
    event: 'charge.success',
    data: {
      reference: 'WL-TICKET-2026-000112',
      amount: 15000,
      status: 'success'
    }
  }),
})

Webhook Documentation

Event Types

  • charge.success
  • charge.failed
  • transfer.success
  • transfer.failed

Payload Structure

{
  "event": "charge.success",
  "data": {
    "reference": "WL-TICKET-2026-000112",
    "status": "success",
    "amount": 15000,
    "customer": {
      "email": "buyer@example.com"
    }
  }
}

Verification Method

Verify provider signatures using provider secret and raw body bytes before any business mutation. Reject unsigned or mismatched callbacks with 401.

Error Handling

  • Return 401 for failed signature verification and stop processing immediately.
  • Persist sync/reconciliation logs with provider event IDs to avoid duplicate processing.
  • Make webhook handlers idempotent by reference and provider event key.

Rate Limits And Abuse Protection

  • Webhook routes should prioritize signature verification over heavy processing.
  • Use provider event IDs to deduplicate retries from provider webhook infrastructure.

White Label

Tenant-wide configuration, routing, payments, and operational endpoints.

POST
White Label
v1

Initialize Payment

Initialize Routed Tenant Payment Across Channels

Base URL

https://api.sparkglim.net

Endpoint

POST /api/white-label/v1/payments/initialize

Overview

Starts a payment using account provider routing rules for web, USSD, Telegram, WhatsApp, and withdrawal channels.

How It Works

  1. Backend validates transaction payload and resolves account provider config.
  2. Routing honors channel-specific defaults and fallback policy.
  3. Gateway initialization is executed and mirrored transaction metadata is persisted.
  4. Response returns gateway URL/reference payload and requestId.

Authentication

  • Requires signed headers and `payments:write` scope.
  • Supported channels: `web`, `ussd`, `telegram`, `whatsapp`, `withdrawal`.

Security Notes

  • Never expose white-label API secrets in frontend or mobile clients.
  • Rotate key pairs regularly from the admin dashboard and revoke old keys immediately.
  • Store requestId values for incident response and support correlation.

Request Parameters

x-white-label-key-id

header
string
required

Tenant-issued API key identifier.

x-white-label-timestamp

header
string (unix milliseconds)
required

Request timestamp used for replay protection.

x-white-label-signature

header
string (hex HMAC-SHA256)
required

Signature over `${timestamp}.${METHOD}.${path}.${body}`.

content-type

header
application/json
required

JSON payload transport contract.

transactionType

body
vote | donation | ticket
required

Payment intent classification.

amount

body
number
required

Gross charge amount in GHS.

email

body
string
required

Payer email.

phoneNumber

body
string
required

Payer phone number.

callbackUrl

body
url
required

Return/callback URL after checkout.

channel

body
web | ussd | telegram | whatsapp | withdrawal
optional

Routing channel (default `web`).

metadata

body
object
optional

Campaign or ticket linkage metadata.

Request Example

{
  "transactionType": "ticket",
  "amount": 150,
  "email": "buyer@example.com",
  "phoneNumber": "+233200000000",
  "callbackUrl": "https://tickets.acme.com/payments/callback",
  "description": "VIP ticket checkout",
  "channel": "web",
  "metadata": {
    "campaignId": "20d7f99a-4308-4f9f-b7bb-57148850d06e",
    "ticketTypeId": "f8f32744-ec0e-4d31-a4f7-0ad90a8e6996"
  }
}

Response Format

200 Success

Gateway initialization payload returned.

{
  "success": true,
  "data": {
    "provider": "paystack",
    "authorizationUrl": "https://checkout.paystack.com/9j7w2jv6d2",
    "accessCode": "9j7w2jv6d2",
    "reference": "WL-TICKET-2026-000112",
    "gatewayMeta": {
      "payment_provider": "paystack"
    }
  },
  "requestId": "wlapi_d2f2ac17"
}

Error Responses

400 Validation Error

Payload or query validation failed while trying to initialize payment.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

401 Authentication Error

Missing headers, stale timestamp, or invalid HMAC signature.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

403 Scope Denied

API key does not include the required scope for this endpoint.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

429 Rate Limit Error

Too many requests in a short time window.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

Status Codes

200 - Payment initialized.
400 - Validation or malformed payload.
401 - Missing/invalid authentication or signature mismatch.
403 - Authenticated but scope or account status denies access.
429 - Rate limit exceeded.
500 - Unexpected server failure.

Code Examples

JavaScript (fetch + Node crypto)

import crypto from 'crypto'

const baseUrl = 'https://api.sparkglim.net'
const keyId = process.env.WHITE_LABEL_KEY_ID
const secret = process.env.WHITE_LABEL_SECRET

const timestamp = Date.now().toString()
const method = 'POST'
const path = '/api/white-label/v1/payments/initialize'
const body = {
  "transactionType": "ticket",
  "amount": 150,
  "email": "buyer@example.com",
  "phoneNumber": "+233200000000",
  "callbackUrl": "https://tickets.acme.com/payments/callback",
  "description": "VIP ticket checkout",
  "channel": "web"
}

const serializedBody = method === 'GET' || method === 'HEAD' ? '{}' : JSON.stringify(body)
const canonical = `${timestamp}.${method}.${path}.${serializedBody}`
const signature = crypto.createHmac('sha256', secret).update(canonical).digest('hex')

const response = await fetch(`${baseUrl}${path}`, {
  method,
  headers: {
    'content-type': 'application/json',
    'x-white-label-key-id': keyId,
    'x-white-label-timestamp': timestamp,
    'x-white-label-signature': signature,
  },
  body: method === 'GET' || method === 'HEAD' ? undefined : serializedBody,
})

const payload = await response.json()
console.log(payload)

Error Handling

  • Always parse `{ success, error, requestId }` on non-2xx responses.
  • Treat 400 as validation failure, 401 as auth/signature mismatch, 403 as scope denial, and 429 as throttling.
  • Log requestId and endpoint for every failed request before retry or escalation.

Rate Limits And Abuse Protection

  • White-label API applies per-account and per-IP in-memory throttling in the backend service.
  • Burst traffic can trigger HTTP 429; apply exponential backoff and retry with jitter.
  • Repeated signature failures can be treated as abuse and temporarily blocked.
PATCH
White Label
v1

Update Setting Category

Patch A Tenant Setting Category

Base URL

https://api.sparkglim.net

Endpoint

PATCH /api/white-label/v1/settings/:category

Overview

Updates a single white-label setting category (`branding`, `payments`, `notifications`, and related categories) in one operation.

How It Works

  1. Path parameter identifies category to update.
  2. Backend validates category and merges submitted config.
  3. Audit entries are created for traceable settings changes.

Authentication

  • Requires signed headers and `settings:write` scope.
  • Allowed categories include branding, permissions, payments, notifications, ussd, webhooks, analytics, security, operations.

Security Notes

  • Never expose white-label API secrets in frontend or mobile clients.
  • Rotate key pairs regularly from the admin dashboard and revoke old keys immediately.
  • Store requestId values for incident response and support correlation.

Request Parameters

x-white-label-key-id

header
string
required

Tenant-issued API key identifier.

x-white-label-timestamp

header
string (unix milliseconds)
required

Request timestamp used for replay protection.

x-white-label-signature

header
string (hex HMAC-SHA256)
required

Signature over `${timestamp}.${METHOD}.${path}.${body}`.

content-type

header
application/json
required

JSON payload transport contract.

category

path
string
required

Setting category slug.

config

body
object
required

Category config object to write.

Request Example

{
  "config": {
    "useSharedDefaults": false,
    "defaultProvider": "paystack",
    "fallbackProvider": "expresspay"
  }
}

Response Format

200 Success

Setting category updated.

{
  "success": true,
  "data": {
    "category": "payments",
    "config": {
      "useSharedDefaults": false,
      "defaultProvider": "paystack",
      "fallbackProvider": "expresspay"
    }
  },
  "requestId": "wlapi_d2f2ac17"
}

Error Responses

400 Validation Error

Payload or query validation failed while trying to update settings category.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

401 Authentication Error

Missing headers, stale timestamp, or invalid HMAC signature.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

403 Scope Denied

API key does not include the required scope for this endpoint.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

429 Rate Limit Error

Too many requests in a short time window.

{
  "success": false,
  "error": "Validation failed: campaignId is required",
  "requestId": "wlapi_d2f2ac17",
  "details": [
    {
      "field": "campaignId",
      "message": "Required"
    }
  ]
}

Status Codes

200 - Settings updated.
400 - Validation or malformed payload.
401 - Missing/invalid authentication or signature mismatch.
403 - Authenticated but scope or account status denies access.
429 - Rate limit exceeded.
500 - Unexpected server failure.

Code Examples

JavaScript (fetch + Node crypto)

import crypto from 'crypto'

const baseUrl = 'https://api.sparkglim.net'
const keyId = process.env.WHITE_LABEL_KEY_ID
const secret = process.env.WHITE_LABEL_SECRET

const timestamp = Date.now().toString()
const method = 'PATCH'
const path = '/api/white-label/v1/settings/payments'
const body = {
  "config": {
    "useSharedDefaults": false,
    "defaultProvider": "paystack"
  }
}

const serializedBody = method === 'GET' || method === 'HEAD' ? '{}' : JSON.stringify(body)
const canonical = `${timestamp}.${method}.${path}.${serializedBody}`
const signature = crypto.createHmac('sha256', secret).update(canonical).digest('hex')

const response = await fetch(`${baseUrl}${path}`, {
  method,
  headers: {
    'content-type': 'application/json',
    'x-white-label-key-id': keyId,
    'x-white-label-timestamp': timestamp,
    'x-white-label-signature': signature,
  },
  body: method === 'GET' || method === 'HEAD' ? undefined : serializedBody,
})

const payload = await response.json()
console.log(payload)

Error Handling

  • Always parse `{ success, error, requestId }` on non-2xx responses.
  • Treat 400 as validation failure, 401 as auth/signature mismatch, 403 as scope denial, and 429 as throttling.
  • Log requestId and endpoint for every failed request before retry or escalation.

Rate Limits And Abuse Protection

  • White-label API applies per-account and per-IP in-memory throttling in the backend service.
  • Burst traffic can trigger HTTP 429; apply exponential backoff and retry with jitter.
  • Repeated signature failures can be treated as abuse and temporarily blocked.