Python SDK for Ebarimt POS API 3.0
Project description
ebarimt-pos-sdk
A modern, async-first Python SDK for the Ebarimt POS API 3.0 — Mongolia's electronic receipting (e-баримт) platform. It wraps both the public OAuth2 API and the local REST API exposed by POS devices behind a single, typed, ergonomic interface.
📖 Full documentation: https://ebarimt-pos-sdk.readthedocs.io/mn/latest/ 📘 Ebarimt POS API 3.0 reference: https://developer.itc.gov.mn/docs/ebarimt-api/inbishdm2zj3x-pos-api-3-0-sistemijn-api-holbolt-zaavruud 🇲🇳 Mongolian version of this README: README_MN.md
Features
- Async-first — every operation exposes both a synchronous and an
asyncvariant (method()/amethod()), built onhttpx. - Strictly typed — Pydantic v2 models with camelCase ↔ snake_case aliasing; full
mypy --strictcompliance. - Two focused clients —
EbarimtApiClientfor the public OAuth2 API,EbarimtRestClientfor the local POS REST API. - Managed OAuth2 — built-in password-grant flow with automatic token refresh and proactive expiry handling.
- Resilient transport — configurable retry with exponential backoff on 5xx and network errors, per-request timeouts, and TLS verification.
- Structured errors — a clear exception hierarchy distinguishing transport, HTTP, decode, validation, and business failures. Sensitive headers and tokens are automatically redacted from error output.
- Environment presets — one-line switch between
STAGINGandPRODUCTIONendpoints viacreate_api_settings.
Installation
pip install ebarimt-pos-sdk
Or with uv:
uv add ebarimt-pos-sdk
Requires Python 3.10 or newer.
Quick Start
Local REST client — issue a receipt
from ebarimt_pos_sdk import EbarimtRestClient, RestClientSettings
settings = RestClientSettings(base_url="http://localhost:1234")
with EbarimtRestClient(settings) as client:
receipt = client.receipt.create({
"branch_no": "001",
"total_amount": 10000,
"merchant_tin": "1234567890",
"pos_no": "POS001",
"type": "B2C_RECEIPT",
"bill_id_suffix": "A",
"receipts": [{
"total_amount": 10000,
"tax_type": "VAT_ABLE",
"merchant_tin": "1234567890",
"items": [{
"name": "Product",
"measure_unit": "ш",
"qty": 1,
"unit_price": 10000,
"total_amount": 10000,
}],
}],
})
print(receipt.id, receipt.qr_data)
Async variant: swap with for async with and call await client.receipt.acreate(...).
import asyncio
from ebarimt_pos_sdk import EbarimtRestClient, RestClientSettings
async def main() -> None:
async with EbarimtRestClient(RestClientSettings(base_url="http://localhost:1234")) as client:
receipt = await client.receipt.acreate(payload)
print(receipt.id)
asyncio.run(main())
Public API client — look up a TIN
Use the factory to target a specific environment without hard-coding URLs:
from ebarimt_pos_sdk import (
EbarimtApiClient,
Environment,
create_api_settings,
)
settings = create_api_settings(
Environment.PRODUCTION, # or Environment.STAGING
client_id="your_client_id",
username="your_username",
password="your_password",
)
with EbarimtApiClient(settings=settings) as client:
info = client.tin_info.read("1234567890")
print(info.data)
Clients at a glance
| Client | Authentication | Available resources |
|---|---|---|
EbarimtRestClient |
None (local network) | receipt, info, send_data, bank_accounts |
EbarimtApiClient |
OAuth2 password grant | district_code, tin_info, merchant_info, product_tax_code |
Both clients support synchronous and asynchronous context managers, share a common settings base (timeouts, TLS, headers, retry policy), and reuse the same error hierarchy.
Error handling
The SDK surfaces failures through a focused exception hierarchy, so you can react at the level of abstraction that matters to your code:
PosApiError
├── PosApiTransportError # network / timeout / DNS / TLS
├── PosApiDecodeError # response body was not valid JSON
├── PosApiHttpError # non-2xx response from server
├── PosApiBusinessError # 2xx, but domain-level failure in payload
└── PosApiValidationError # Pydantic validation of request or response
from ebarimt_pos_sdk import (
PosApiBusinessError,
PosApiHttpError,
PosApiTransportError,
PosApiValidationError,
)
try:
receipt = client.receipt.create(payload)
except PosApiValidationError as e:
# Bad shape — fix the request before resending
for err in e.errors:
print(err["loc"], err["msg"])
except PosApiBusinessError as e:
# Server accepted the request but rejected it on business grounds
print(e.status, e.code, e.message)
except PosApiHttpError as e:
# 4xx / 5xx — includes safe, redacted request/response context
print(e)
except PosApiTransportError:
# Network layer — safe to retry later
raise
Authorization headers and token-bearing query parameters are redacted automatically in every error's string
representation.
Configuration
All settings are immutable dataclasses — construct once and pass to the client. Timeouts, TLS verification, custom
headers, and retry behaviour are shared across both clients via BaseSettings.
from ebarimt_pos_sdk import RestClientSettings
from ebarimt_pos_sdk.settings import RetrySettings
settings = RestClientSettings(
base_url="http://localhost:1234",
timeout_s=5.0,
verify_tls=True,
headers={"X-Request-Source": "pos-42"},
retry=RetrySettings(
max_retries=3,
backoff_base_seconds=1.0,
retryable_statuses=frozenset({500, 502, 503, 504}),
),
)
The default retry policy — 3 attempts with exponential backoff on 5xx and network errors — is suitable for most deployments.
Validation philosophy
The SDK validates structure, not policy:
- ✅ Field shapes, regex for stable identifiers (TIN, branch codes), enums, and basic numeric constraints (
>= 0). - ❌ Business rules, cross-field dependencies, reference-table lookups, or any government policy that changes out of band.
This boundary is intentional. The server owns business rules; the SDK owns shape correctness. That keeps the SDK stable when rules change.
Development
# Install all dependencies, including dev extras
uv sync --dev
# Run the unit test suite
uv run pytest -m "not integration"
# Run with coverage
uv run pytest -m "not integration" --cov
# Lint and format
uv run ruff check
uv run ruff format
# Type check (strict)
uv run mypy src
Integration tests (marked @pytest.mark.integration) require a live PosAPI server and credentials; they are excluded
from CI by default.
See CONTRIBUTING.md for contribution guidelines and CHANGELOG.md for release notes.
License
Released under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ebarimt_pos_sdk-0.2.10.tar.gz.
File metadata
- Download URL: ebarimt_pos_sdk-0.2.10.tar.gz
- Upload date:
- Size: 18.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d3dfc33704513e65f2748ce3007087b1a7838ee78590859e2d17640070aff2e
|
|
| MD5 |
6d6091977f75257e7235954d01b31f5b
|
|
| BLAKE2b-256 |
0ac4646408a77e34bbfd088ab69d156a4c96a2448991643d23e945618d45a449
|
Provenance
The following attestation bundles were made for ebarimt_pos_sdk-0.2.10.tar.gz:
Publisher:
release.yaml on Amraa1/ebarimt-pos-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ebarimt_pos_sdk-0.2.10.tar.gz -
Subject digest:
7d3dfc33704513e65f2748ce3007087b1a7838ee78590859e2d17640070aff2e - Sigstore transparency entry: 1367495297
- Sigstore integration time:
-
Permalink:
Amraa1/ebarimt-pos-sdk@05614997c7d68fdd59dbcaa6fc5203bbf67bee10 -
Branch / Tag:
refs/tags/v0.2.10 - Owner: https://github.com/Amraa1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@05614997c7d68fdd59dbcaa6fc5203bbf67bee10 -
Trigger Event:
release
-
Statement type:
File details
Details for the file ebarimt_pos_sdk-0.2.10-py3-none-any.whl.
File metadata
- Download URL: ebarimt_pos_sdk-0.2.10-py3-none-any.whl
- Upload date:
- Size: 33.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de39c792d89c67dd720e74caf30d629d88d0a7086bfb26d0f250dca3630aca0f
|
|
| MD5 |
1f635a284736e9d14c44b01af10f8e50
|
|
| BLAKE2b-256 |
c8a6add208ff501e0772139eae76573d434e27320c71288d667297f6b6f20100
|
Provenance
The following attestation bundles were made for ebarimt_pos_sdk-0.2.10-py3-none-any.whl:
Publisher:
release.yaml on Amraa1/ebarimt-pos-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ebarimt_pos_sdk-0.2.10-py3-none-any.whl -
Subject digest:
de39c792d89c67dd720e74caf30d629d88d0a7086bfb26d0f250dca3630aca0f - Sigstore transparency entry: 1367495301
- Sigstore integration time:
-
Permalink:
Amraa1/ebarimt-pos-sdk@05614997c7d68fdd59dbcaa6fc5203bbf67bee10 -
Branch / Tag:
refs/tags/v0.2.10 - Owner: https://github.com/Amraa1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@05614997c7d68fdd59dbcaa6fc5203bbf67bee10 -
Trigger Event:
release
-
Statement type: