Project

wajub

0.0
The project is in a healthy, maintained state
Server-side Wajub payments, webhooks, and merchant API client.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

Wajub Ruby SDK

Gem Version Ruby License: MIT

Official server-side SDK for the Wajub merchant API. Accept mobile-money and card payments across Africa with a Stripe-inspired, resource-oriented client.

Use Wajub.js for embedded checkout in the browser. Use this SDK on your backend with a secret (sk_) or restricted (rk_) API key — never expose secret keys in client-side code.

Features

  • Resource-oriented API (client.payments, client.customers, …)
  • Automatic Idempotency-Key on mutating requests (override per call)
  • Typed errors per HTTP status (AuthenticationError, RateLimitError, …)
  • Automatic retries on 429 and 5xx (max 2, exponential backoff)
  • Page-based pagination with auto_paging_each and next_page
  • Webhook signature verification (HMAC-SHA256, timestamp tolerance)
  • Zero third-party runtime dependencies (stdlib only)

Requirements

Requirement Version
Ruby 3.1 or later
Dependencies Standard library only (net/http, openssl, json)

Installation

Add to your Gemfile:

gem 'wajub', '~> 1.1'

Or install directly:

gem install wajub

Quick start

Amounts are passed in the smallest currency unit (e.g. cents for EUR/USD; whole francs for XAF).

Redirect checkout

require 'wajub'

client = Wajub::Client.new(api_key: ENV['WAJUB_API_KEY'])

payment = client.payments.create(
  'amount' => 15_000,
  'currency' => 'XAF',
  'email' => 'buyer@example.com',
  'callback' => 'https://shop.example.com/order/complete'
)

puts payment.authorization_url

Inline / overlay (embed token)

embed = client.payments.create(
  'amount' => 15_000,
  'currency' => 'XAF',
  'metadata' => { 'mode' => 'embed' }
)

# Pass to Wajub.js: embed.authorization_token

create() and retrieve() return a typed Payment object — prefer method access (payment.authorization_url). List pages from list() yield plain hashes; bracket syntax (payment['…']) remains available on typed objects.

Rails

# config/initializers/wajub.rb
WajubClient = Wajub::Client.new(
  api_key: Rails.application.credentials.dig(:wajub, :api_key) || ENV['WAJUB_API_KEY'],
  webhook_secret: ENV['WAJUB_WEBHOOK_SECRET']
)

Webhook controller

Use the raw request body:

class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token

  def wajub
    event = WajubClient.webhooks.construct_event(
      request.body.read,  # raw body — not params
      request.headers['X-Wajub-Signature'],
      request.headers['X-Wajub-Timestamp']
    )

    case event['type']
    when 'payment.succeeded'
      # fulfill order
    end

    head :ok
  rescue Wajub::WebhookSignatureVerificationError
    head :bad_request
  end
end

Configuration

Variable Description
WAJUB_API_KEY Secret or restricted API key (sk_, sk_test., rk_, …)
WAJUB_WEBHOOK_SECRET Webhook signing secret (whsec_) for construct_event()

Test mode is selected by your API key prefix (sk_test.…), not by the API URL. Production calls always go to https://api.wajub.com.

Resources (merchant API)

Property Methods
client.global ping, channels, countries, currencies
client.payments create, initialize_payment, retrieve, list, cancel, process, process_split, list_refunds
client.customers create, retrieve, update, delete, list, block, unblock, activate, deactivate, list_tax_ids, create_tax_id, delete_tax_id
client.refunds create, retrieve, list
client.transfers create, retrieve, list
client.beneficiaries create, retrieve, update, delete, list
client.links create, retrieve, update, delete, list
client.invoices create, retrieve, update, delete, list, send, mark_paid, cancel
client.accounts create, retrieve, update, delete, list, regenerate_token
client.webhook_endpoints create, retrieve, update, delete, list, rotate_secret
client.balance retrieve
client.events list, retrieve, resend
client.disputes list, retrieve, submit_evidence, accept, close, send_message
client.identity resolve, validate
client.tax get_settings, update_settings, rates, calculate, reports, list_codes, retrieve_code, list_registrations, create_registration, retrieve_registration, update_registration, delete_registration, jurisdictions, thresholds, threshold_alerts
client.shield get_settings, update_settings, stats, list_blocklist, add_to_blocklist, remove_from_blocklist
client.listen config, auth
client.webhooks construct_event (local — no HTTP)

Sync (Connect)

client.payments.create(params, Wajub::RequestOptions.new(sync: 'acct_sync_ref'))

Webhooks

begin
  event = client.webhooks.construct_event(
    request.body.read,  # String — raw body bytes
    request.env['HTTP_X_WAJUB_SIGNATURE'],
    request.env['HTTP_X_WAJUB_TIMESTAMP']
  )
rescue Wajub::WebhookSignatureVerificationError
  halt 400
end

case event['type']
when 'payment.succeeded'
  # fulfill order
end

During local development, use the Wajub CLI to forward webhooks to your machine.

Pagination

page = client.payments.list('per_page' => 50)

page.auto_paging_each do |payment|
  puts "#{payment['id']} #{payment['status']}"
end

# Manual page control
first = client.payments.list
second = first.next_page if first.has_more

Idempotency

POST and PUT requests automatically receive an Idempotency-Key header. Pass your own:

client.payments.create(
  params,
  Wajub::RequestOptions.new(idempotency_key: "order-#{order_id}")
)

Error handling

begin
  client.payments.create(params)
rescue Wajub::InvalidRequestError => e
  puts e.errors   # field-level validation errors
rescue Wajub::AuthenticationError
  # 401 — bad API key
rescue Wajub::RateLimitError
  # 429 — back off and retry
end

Development

bundle install
bundle exec rake test

Documentation & support

License

MIT — see LICENSE.