Skip to content

About

Professional, type-safe Python SDK for parsing and extracting structured data from Ethiopian bank transaction receipts

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

Repository files navigation

Ethio Receipt SDK

A professional, type-safe Python SDK for parsing Ethiopian bank transaction receipts

PyPI Python License CI Type Checked


Why This SDK?

Feature Description
Auto-Detection Automatically identifies the bank from any receipt URL
Type-Safe Full Pydantic models with validation — no more raw dicts
Unified Output Same Receipt model regardless of bank
REST API Built-in FastAPI server for microservice deployment
Retry Logic Exponential backoff with configurable retries
Batch Processing Parse multiple receipts in one call
Export Formats JSON, CSV, and dict export built-in
Beautiful CLI Rich terminal output with colored tables
Plugin Architecture Easy to add new banks without modifying core code

Supported Banks

Bank ID Receipt Type Auto-Detect
Commercial Bank of Ethiopia cbe PDF Yes
Dashen Bank dashen PDF Yes
Awash Bank awash HTML Yes
Bank of Abyssinia boa HTML (JS) Yes
Zemen Bank zemen PDF Yes
Telebirr (Ethio Telecom) telebirr HTML Yes

Installation

# Core SDK
pip install ethio-receipt-sdk

# With REST API support
pip install ethio-receipt-sdk[api]

# With Selenium (needed for BOA)
pip install ethio-receipt-sdk[selenium]

# Everything
pip install ethio-receipt-sdk[all]

Quick Start

Parse a Receipt (3 lines)

from ethio_receipt_sdk import ReceiptParser

parser = ReceiptParser()
receipt = parser.parse("https://apps.cbe.com.et:100/?id=FT25211G11JQ21827223")

print(receipt.sender.name)       # "JOHN DOE"
print(receipt.amount)            # ETB 1,250.75
print(receipt.reference)         # "FT25211G11JQ"
print(receipt.status)            # TransactionStatus.SUCCESS

Auto-Detection (No Bank Specified)

from ethio_receipt_sdk import ReceiptParser

parser = ReceiptParser()

# SDK automatically detects the bank from the URL
receipt = parser.parse("https://receipt.dashensuperapp.com/receipt/387ETAP2522000WK")
print(receipt.bank)  # BankType.DASHEN

receipt = parser.parse("https://awashpay.awashbank.com:8225/-E41AE0D86FFA-21XYYW")
print(receipt.bank)  # BankType.AWASH

# Even works with just a reference ID
receipt = parser.parse("CHQ0FJ403O")  # Auto-detects Telebirr

Telebirr (by ID or URL)

from ethio_receipt_sdk import ReceiptParser

parser = ReceiptParser()

# Just the transaction ID
receipt = parser.parse("CHQ0FJ403O", bank="telebirr")

# Or full URL
receipt = parser.parse("https://transactioninfo.ethiotelecom.et/receipt/CHQ0FJ403O")

CBE with FT Number + Account

from ethio_receipt_sdk.parsers.cbe import parse_cbe_from_ft

receipt = parse_cbe_from_ft("FT25211G11JQ", "21827223")
print(receipt.sender.name)
print(receipt.amount)

Batch Processing

from ethio_receipt_sdk import ReceiptParser

urls = [
    "https://apps.cbe.com.et:100/?id=FT25211G11JQ21827223",
    "https://receipt.dashensuperapp.com/receipt/387ETAP2522000WK",
    "https://awashpay.awashbank.com:8225/-E41AE0D86FFA-21XYYW",
]

with ReceiptParser() as parser:
    receipts = parser.parse_batch(urls, ignore_errors=True)

    for r in receipts:
        if isinstance(r, dict):  # Error case
            print(f"Failed: {r['error']}")
        else:
            print(f"{r.bank.value}: {r.amount}")

Export Formats

JSON

parser = ReceiptParser()
receipt = parser.parse(url)

# Structured JSON
json_str = parser.to_json(receipt, indent=2)
print(json_str)
{
  "bank": "cbe",
  "reference": "FT25211G11JQ",
  "status": "success",
  "timestamp": "2025-09-09T10:20:00",
  "sender": {
    "name": "JOHN DOE",
    "account": "1000223344",
    "phone": null,
    "bank": null
  },
  "receiver": {
    "name": "XYZ TRADING PLC",
    "account": "1000556677",
    "phone": null,
    "bank": null
  },
  "amount": {
    "value": "1250.75",
    "currency": "ETB"
  },
  "fees": {
    "service_charge": "5.00",
    "vat": "0.75",
    "total_fee": null,
    "calculated_total": "5.75"
  },
  "reason": "Transfer"
}

CSV (for batch exports)

csv_output = parser.to_csv(receipts)
with open("receipts.csv", "w") as f:
    f.write(csv_output)

Dictionary

data = parser.to_dict(receipt)  # Standard Python dict

CLI Usage

# Parse any receipt (auto-detects bank)
ethio-receipt parse "https://apps.cbe.com.et:100/?id=FT25211G11JQ21827223"

# Specify bank explicitly
ethio-receipt parse "CHQ0FJ403O" --bank telebirr

# Output as JSON
ethio-receipt parse "https://receipt.dashensuperapp.com/receipt/387ETAP2522000WK" --json

# List supported banks
ethio-receipt banks

# Show version
ethio-receipt version

CLI Output Example:

┌──────────────────────────────────────────────┐
│              CBE Receipt                      │
├──────────────────────┬───────────────────────┤
│ Field                │ Value                 │
├──────────────────────┼───────────────────────┤
│ Reference            │ FT25211G11JQ          │
│ Status               │ SUCCESS               │
│ Timestamp            │ 2025-09-09 10:20:00   │
│                      │                       │
│ Sender               │                       │
│   Name               │ JOHN DOE              │
│   Account            │ 1000223344            │
│                      │                       │
│ Receiver             │                       │
│   Name               │ XYZ TRADING PLC       │
│   Account            │ 1000556677            │
│                      │                       │
│ Amount               │ ETB 1,250.75          │
│ Total Debited        │ ETB 1,256.50          │
│ Service Charge       │ ETB 5.00              │
│ VAT                  │ ETB 0.75              │
└──────────────────────┴───────────────────────┘

REST API

Start the API server:

# Install with API support
pip install ethio-receipt-sdk[api]

# Run the server
python -m ethio_receipt_sdk.api

Endpoints

Method Endpoint Description
GET / Health check & info
GET /banks List supported banks
POST /parse Parse a single receipt
GET /parse?url=... Parse via query parameter
POST /parse/batch Parse multiple receipts

API Examples

Parse a receipt:

curl -X POST http://localhost:8000/parse \
  -H "Content-Type: application/json" \
  -d '{"url": "https://apps.cbe.com.et:100/?id=FT25211G11JQ21827223"}'

Parse with explicit bank:

curl -X POST http://localhost:8000/parse \
  -H "Content-Type: application/json" \
  -d '{"url": "CHQ0FJ403O", "bank": "telebirr"}'

Batch parse:

curl -X POST http://localhost:8000/parse/batch \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://apps.cbe.com.et:100/?id=FT25211G11JQ21827223",
      "https://receipt.dashensuperapp.com/receipt/387ETAP2522000WK"
    ],
    "ignore_errors": true
  }'

Quick parse via GET:

curl "http://localhost:8000/parse?url=https://apps.cbe.com.et:100/?id=FT25211G11JQ21827223"

Interactive API docs available at: http://localhost:8000/docs


Integration Guide

Flask Integration

from flask import Flask, request, jsonify
from ethio_receipt_sdk import ReceiptParser

app = Flask(__name__)
parser = ReceiptParser()

@app.route("/api/receipt", methods=["POST"])
def parse_receipt():
    data = request.json
    receipt = parser.parse(data["url"], bank=data.get("bank"))
    return jsonify(parser.to_dict(receipt))

Django Integration

# views.py
import json
from django.http import JsonResponse
from ethio_receipt_sdk import ReceiptParser

parser = ReceiptParser()

def parse_receipt(request):
    body = json.loads(request.body)
    receipt = parser.parse(body["url"])
    return JsonResponse(parser.to_dict(receipt))

Express.js / Node.js (via subprocess)

const { execSync } = require('child_process');

function parseReceipt(url) {
  const result = execSync(`ethio-receipt parse "${url}" --json`);
  return JSON.parse(result.toString());
}

As a Microservice (Docker)

FROM python:3.12-slim
WORKDIR /app
RUN pip install ethio-receipt-sdk[api]
EXPOSE 8000
CMD ["python", "-m", "ethio_receipt_sdk.api"]
docker build -t ethio-receipt-api .
docker run -p 8000:8000 ethio-receipt-api

Architecture

ethio-receipt-sdk/
├── src/ethio_receipt_sdk/
│   ├── __init__.py          # Public API exports
│   ├── client.py            # ReceiptParser (main interface)
│   ├── models.py            # Pydantic data models
│   ├── exceptions.py        # Custom exception hierarchy
│   ├── detector.py          # Auto-detect bank from URL
│   ├── http.py              # HTTP client with retry logic
│   ├── cli.py               # Rich CLI interface
│   ├── api.py               # FastAPI REST server
│   └── parsers/
│       ├── base.py          # Abstract BaseParser
│       ├── registry.py      # Plugin registry (auto-discovery)
│       ├── cbe.py           # CBE parser
│       ├── dashen.py        # Dashen parser
│       ├── awash.py         # Awash parser
│       ├── boa.py           # BOA parser (Selenium)
│       ├── zemen.py         # Zemen parser
│       └── telebirr.py      # Telebirr parser
├── tests/
├── pyproject.toml
├── README.md
└── LICENSE

Adding a Custom Bank Parser

The plugin architecture makes it easy to add new banks:

import re
from ethio_receipt_sdk.parsers.base import BaseParser
from ethio_receipt_sdk.parsers.registry import ParserRegistry
from ethio_receipt_sdk.models import BankType, Receipt

# 1. Register your parser
@ParserRegistry.register(BankType.YOUR_BANK)
class YourBankParser(BaseParser):

    def validate_url(self, url: str) -> bool:
        return "yourbank.com" in url

    def parse(self, url: str) -> Receipt:
        response = self._http.get(url)
        # ... extract data ...
        return Receipt(bank=BankType.YOUR_BANK, ...)

Error Handling

from ethio_receipt_sdk import ReceiptParser
from ethio_receipt_sdk.exceptions import (
    BankNotSupportedError,
    ParseError,
    NetworkError,
    ReceiptNotFoundError,
)

parser = ReceiptParser()

try:
    receipt = parser.parse(url)
except BankNotSupportedError as e:
    print(f"Unknown bank: {e.details}")
except NetworkError as e:
    print(f"Network issue: {e.message} (status={e.details.get('status_code')})")
except ParseError as e:
    print(f"Could not parse receipt: {e.message}")

Limitations

Issue Affected Workaround
Geo-restriction Telebirr Use Ethiopian-hosted server
JavaScript rendering BOA Install ethio-receipt-sdk[selenium]
SSL certificate issues Some banks SDK disables SSL verification by default
Rate limiting All banks Built-in retry with exponential backoff

Development

# Clone
git clone https://github.com/A1ET/ethio-receipt-sdk.git
cd ethio-receipt-sdk

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Type checking
mypy src/

# Lint
ruff check src/

License

MIT License — see LICENSE


Disclaimer

This is not an official product of any Ethiopian bank or Ethio Telecom.
Built for developer utility purposes. Use responsibly and in compliance with applicable terms of service.

About

Professional, type-safe Python SDK for parsing and extracting structured data from Ethiopian bank transaction receipts

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages