Bank-Slip-Verifier (pip)
Zero-dependency client for the OIIO Service Slip Verify API — verify Thai bank transfer slips with pip, uv, poetry or any Python 3.10+ runtime
English - Thai
Three verification modes, one client — verify that a "paid" slip image or QR payload really moved money in the bank system:
| Mode | Endpoint | Speed |
|---|---|---|
detect_amount(img) |
POST /api/slip |
Slowest — reads the amount from the image with OCR, then verifies it |
verify_amount(img, amount) |
POST /api/slip/:amount |
Faster — you give the expected amount, OCR is skipped |
verify_qr_code(qr_code_data, amount) |
POST /api/slip/:amount/no_slip |
Fastest — QR payload only, no image |
Features
| Ability | Details |
|---|---|
| Three endpoints | OCR amount detection, image + expected amount, and QR-only verification — same typed result for all |
| Static API | from bank_slip_verifier import Client — no construction, Client.verify_amount(...) just works against the hosted deployment |
| Zero dependencies | pure standard library (urllib), no install scripts, no native binaries |
| Typed errors | SlipApiError carries the HTTP status, the documented slug (amount-not-verified, slip-not-found, ...) and the raw envelope, plus SlipTimeoutError and SlipError |
| Timeout-aware | defaults to a 35 s HTTP timeout — verification can take up to 25 s (OCR) |
| npm parity | same endpoints, payloads, error slugs and messages as the npm SDK (@byteindev/bank-slip-verifier) |
Quick Start
Install with any package manager:
pip install bank-slip-verifier
# or
uv add bank-slip-verifier
# or
poetry add bank-slip-verifier
Client is a ready-to-use static wrapper around the hosted deployment — no setup needed:
from bank_slip_verifier import Client
# 1. Verify a QR payload only, no image (fastest):
result = Client.verify_qr_code(qr_code_data="004...", amount=100)
print(result.data.ref) # bank transaction reference
# 2. Verify a slip image against a known amount (recommended — faster):
data = Client.verify_amount(img="data:image/jpeg;base64,...", amount=100).data
print(data.amount == 100) # True — the bank confirmed the transfer
# 3. Unknown amount — let OCR read it from the image (slowest):
detected = Client.detect_amount(img="data:image/jpeg;base64,...").data
print(detected.amount) # amount found by OCR, then verified
Every result has the same shape:
SlipResult(
ok=True,
message="Slip processed successfully.",
from_cache=False, # True when answered from the server cache
data=SlipData(
ref="202602032204376094",
date="2026-03-17T10:00:00.000Z",
amount=100.0,
sender_bank="004",
sender_name="John Doe",
sender_id="xxx-x-xxxxx-x",
receiver_bank="014",
receiver_name="Jane Doe",
receiver_id="xxx-x-xxxxx-x",
),
)
Extra fields come back on rich responses (verified, reference_1/2/3, sender_bank_details, receiver_bank_details).
Bring your own deployment (or configure)
from bank_slip_verifier import create_client
client = create_client() # hosted: https://slip-c.oiio.download
# or
custom = create_client(base_url="https://your-deployment.example.com")
# or configure the static client:
Client.configure(base_url="https://your-deployment.example.com")
result = custom.verify_amount(img="data:image/jpeg;base64,...", amount=100)
Base URL resolution order: base_url option > BANK_SLIP_VERIFIER_BASE_URL
environment variable > hosted deployment:
BANK_SLIP_VERIFIER_BASE_URL=https://staging.example.com python app.py
Timeout
Verification can take up to 25 seconds (OCR endpoint). The API docs require an HTTP
timeout of 30 s or more — this client defaults to 35 s and raises SlipTimeoutError
when a response does not arrive in time. Tighten it only if you know what you are doing:
client = create_client(timeout_ms=60_000) # or lower, but >= 30_000
Terms of Service
The API rejects every request unless TOS, privacy and EULA are accepted. The client sends
{"tos": True, "privacy": True, "eula": True} by default (using the service implies consent).
Override at client level or per call:
create_client(consent={"tos": True, "privacy": False, "eula": True}) # client-level
client.detect_amount(img, consent={"tos": False}) # per-call (wins)
Error handling
All errors extend SlipError. The API's failures arrive as SlipApiError with the HTTP
status, the documented error slug and the raw envelope:
from bank_slip_verifier import Client, SlipApiError, SlipTimeoutError, SlipError
try:
result = Client.verify_amount(img=img, amount=100)
except SlipApiError as err:
print(err.status, err.slug, err.message)
# 422 'amount-not-verified' '[amount-not-verified] Amount not verified'
if err.slug == "amount-not-verified":
# show the customer the expected amount again — the slip does not match
...
except SlipTimeoutError:
# verification took longer than timeout_ms — retry later
...
| HTTP | slug | Cause |
|---|---|---|
| 400 | bad-request |
malformed body / missing field |
| 400 | terms-not-accepted |
TOS/Privacy/EULA not accepted |
| 400 | invalid-image |
base64 image is invalid |
| 422 | qr-not-found |
no QR found in the image |
| 422 | invalid-qr |
QR format invalid |
| 422 | amount-not-found |
OCR could not read the amount |
| 422 | amount-not-verified |
amount read, but did not match the bank record |
| 422 | invalid-slip-data |
slip data incomplete |
| 404 | slip-not-found |
slip not found in the bank system |
SlipApiError.slug is one of these values (SLIP_ERROR_SLUGS and is_slip_error_slug
are exported for runtime checks).
Live smoke tests
The package ships live smoke tests against the real deployment (skipped by default):
LIVE=1 pytest
API
| Export | Description |
|---|---|
Client |
static wrapper around a shared instance (hosted deployment by default) |
create_client(**options) |
new SlipClient connected to hosted or custom base_url |
SlipClient |
the client class; detect_amount, verify_amount, verify_qr_code |
DEFAULT_BASE_URL |
https://slip-c.oiio.download |
ENV_BASE_URL |
BANK_SLIP_VERIFIER_BASE_URL — env-var fallback for the base URL |
SlipError / SlipApiError / SlipTimeoutError |
typed errors |
SLIP_ERROR_SLUGS, is_slip_error_slug |
error slug constants + guard |
SlipData / SlipResult |
result types |
__version__ |
package version |
Credits
Powered by the OIIO Service Slip Verify API.
License
MIT © ByteInDev
Metadata
Release files for bank-slip-verifier 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| bank_slip_verifier-1.0.0.tar.gz | 17.8 kB | Without provenance | Details for bank_slip_verifier-1.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| bank_slip_verifier-1.0.0-py3-none-any.whl | Python 3 | none | any | Details for bank_slip_verifier-1.0.0-py3-none-any.whl |
Total release size: 31.1 kB
Release files / bank_slip_verifier-1.0.0.tar.gz
| Download URL | bank_slip_verifier-1.0.0.tar.gz |
|---|---|
| Size | 17.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cd7ca6b274592895d8f9d2ae054bbbf54a26a5756590e69d9705919d3243fb06
|
|
BLAKE2b-256 checksum How to use checksums |
232abbb70e4465f8c2e62f6749068f820a8c8e8be778f9a5256237bb4917124b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / bank_slip_verifier-1.0.0-py3-none-any.whl
| Download URL | bank_slip_verifier-1.0.0-py3-none-any.whl |
|---|---|
| Size | 13.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dd70cda48b69b51465533f2340b0c61068170d6c17457de082a95f0f35ecec08
|
|
BLAKE2b-256 checksum How to use checksums |
3154693563aaa5d5ca5e2025d3823eb1a3bea9c00c317191db288d7b152b93df
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Security for bank-slip-verifier 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.