BirrJS
Providers

Vodit

Integrate v.odit.et for receipt-based payment verification with Ethiopian banks.

The @birrjs/vodit package provides receipt-based payment verification via v.odit.et — a drop-in alternative to chapa for solo devs without a merchant license.

Installation

pnpm add @birrjs/vodit

Configuration

import { vodit } from "@birrjs/vodit";

createBirr({
  provider: vodit({
    apiKey: process.env.VODIT_API_KEY!,
    channels: [
      {
        type: "telebirr",
        value: "0912345678",
        name: "Abebe", // Must match your account name exactly (first name is enough)
      },
      {
        type: "cbe",
        value: "1000200030004000",
        name: "Abebe", // Must match your account name exactly (first name is enough)
      },
    ],
  }),
});

The name field is required and must match how your name appears on your bank or mobile money account. Vodit compares it against the receipt's recipient name — if they don't match, the verification fails.your registered first name is sufficient.

Options

OptionTypeRequiredDescription
apiKeystringYesAPI key from v.odit.et
channelsVoditChannel[]YesBank accounts to display for payment

VoditChannel

FieldTypeDescription
type"telebirr" | "cbe" | "awash"The bank or mobile money provider
valuestringAccount number or phone number
namestringAccount holder name as registered at the bank — required. Used for recipient verification. First name is fine if that's how it appears on receipts.

Environment variables

VariableDescription
VODIT_API_KEYAPI key from v.odit.et

How it works

Instead of redirecting users to a checkout page, users see a list of bank accounts and pay directly from their banking app.

Subscribe flow

  1. Your app calls subscribe() → BirrJS calls provider.initializeTransaction()
  2. BirrJS returns paymentInstructions — an array of bank accounts with amounts (no checkoutUrl)
  3. Display the instructions to the user: "Send 29.00 ETB to any of these accounts"
  4. The user pays via their banking app and gets a receipt (reference)
  5. The user submits their receipt URL via client.verifyReceipt({ receiptUrl, planId })

Verify receipt flow

  1. verifyReceipt calls provider.verifyTransaction(receiptUrl)
  2. Vodit fetches the receipt from the bank's website and parses the payment details
  3. BirrJS checks: transaction completed? amount ≥ plan price? recipient account matches?
  4. If all checks pass, the subscription is activated and subscription.activated events fire

Duplicate receipts are detected and rejected automatically — each receipt URL can only be used once.

Supported channels

ChannelType valueAmount fieldStatus check
TelebirrtelebirrtotalPaidAmount or settledAmountMust be "Completed"
CBEcbetransferredAmount or totalAmountAlways accepted
Awash Bankawashamount (nested)Always accepted

Receipt verification details

Recipient verification

Vodit validates the receipt against your configured channels:

  • Last 4 digits — extracts the credited account's last 4 digits and compares against your channel values
  • Recipient name — checks the recipient name starts with the configured account holder name

If neither check matches, verification fails — preventing activation from payments sent to wrong accounts.

Amount check

Users type the amount manually at the bank, so the exact amount can vary. Vodit checks that the paid amount is ≥ the plan price (in minor units). Overpayment is allowed.

Error types

ErrorCause
SERVER_ERRORVodit API returned a 5xx error
UNAUTHORIZEDInvalid or missing API key
RATE_LIMITEDToo many requests
TIMEOUT_ERRORRequest exceeded 30s timeout
NETWORK_ERRORNetwork connectivity issue
VERIFICATION_FAILEDReceipt could not be verified

Building a checkout page? BirrJS includes ready-made UI components for receipt-based payments — bank account cards, channel selector, and receipt input.