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.