Skip to main content

cashio-client

Python client for the Cashio Client API (transactions and purchase payments).

Install in other projects with pip install cashio-client (after publishing) or from a local path / git URL.

کلاینت پایتون برای API کلاینت Cashio (تراکنش‌ها و پرداخت‌های خرید). قابل استفاده در پروژه‌های دیگر و قابل انتشار روی PyPI.

Install

pip install cashio-client

From this repo (editable):

pip install -e .

Quick start

from cashio_client import CashioClient

client = CashioClient("http://127.0.0.1:8000", token="YOUR_TOKEN")

result = client.transactions.create(
    amount=1500000,
    type="income",
    description="from rahkarmelk",
    date="1405-06-22",
)
print(result.ok, result.id)

Token comes from Cashio Settings → Client API Config. There is no session login.

If that config has a default fund (and category), you can omit fund / category.

Authentication

The token is sent with one method (default: Bearer header):

Method How
bearer (default) Authorization: Bearer <token>
token Authorization: Token <token>
x-api-token X-Api-Token: <token>
body JSON/form field "token": "<token>"
from cashio_client import AuthMethod, CashioClient, CashioSettings

settings = CashioSettings(
    "http://127.0.0.1:8000",
    token="YOUR_TOKEN",
    auth_method=AuthMethod.X_API_TOKEN,
)
client = CashioClient(settings)

base_url is the Cashio host (http://127.0.0.1:8000). A trailing /a/api is stripped if present. Requests go to {base_url}/a/api/....

Create a transaction

POST /a/api/transaction/create

result = client.transactions.create(
    amount=250000,
    transaction_type="expense",
    fund=15,
    category=3,
    description="rent",
    payment_type="full_payment",
)

Aliases from the API are accepted: type for transaction_type, fund_id for fund, category_id for category, holder_id for holder.

With files (multipart)

result = client.transactions.create(
    amount=1500000,
    type="income",
    attached_file=["/path/to/receipt.pdf", "/path/to/photo.jpg"],
)

attached_file may be a path, a file object, a (filename, fileobj) tuple, or a list of those.

Fields

Field Type Required
amount number / Decimal yes
transaction_type / type income or expense yes
fund / fund_id int if no default fund
category / category_id int no (client default)
description str no
date str Jalali YYYY-MM-DD no
reference_number str no
payment_type full_payment, part_payment, completed_parts no (API default full_payment)
holder / holder_id int no
transaction_linked int no
fee number no (creates a linked expense)
attached_file file(s) no

Constants: TransactionType.INCOME, TransactionType.EXPENSE, PaymentType.FULL_PAYMENT, …

Purchase payments

Two kinds: direct (already paid, created as completed) and indirect (accountant pays later, created as unseen). Documents are optional for both.

The payment amount is not sent: the server computes it as the sum of quantity * unit_price over lines. At least one line is required, and every line needs description, quantity, unit_price.

from cashio_client import PurchaseKind, PurchasePaymentMethod, PurchasePaymentStatus

result = client.purchases.create_direct(
    lines=[
        {"description": "A4 paper", "quantity": 2, "unit": "box", "unit_price": 750000},
        {"description": "pen", "quantity": 10, "unit_price": 5000},
    ],
    documents=["/path/to/invoice.jpg"],   # optional
    description="stationery",
    payment_date="1405-06-22",   # optional Jalali date, defaults to today
    request_id="INV-1",          # optional, unique per client
)
print(result.id, result.status)  # 11 completed

result = client.purchases.create_indirect(
    lines=[{"description": "ride", "quantity": 1, "unit_price": 300000}],
    description="taxi",
    request_id="INV-2",
)

# payment methods: cash (default), installment, transfer_order
client.purchases.create_indirect(
    lines=[{"description": "laptop", "quantity": 1, "unit_price": 30000000}],
    payment_method=PurchasePaymentMethod.INSTALLMENT,
    installment_count=3,            # required, >= 2
    installment_amount=10000000,    # required
)
client.purchases.create_indirect(
    lines=[{"description": "laptop", "quantity": 1, "unit_price": 30000000}],
    payment_method=PurchasePaymentMethod.TRANSFER_ORDER,
    transfer_due_date="1405-09-01", # required, Jalali date
    guarantee_check=7,              # optional, fund check id with purpose "guarantee"
)

# read
payment = client.purchases.get(result.id)               # by id
payment = client.purchases.get(request_id="INV-2")      # by your own reference
payments = client.purchases.list(status=PurchasePaymentStatus.IN_REVIEW, kind=PurchaseKind.INDIRECT)
payment.status, payment.amount, payment.lines, payment.documents, payment.transaction_id
payment.payment_method, payment.installment_count, payment.installment_amount
payment.transfer_due_date, payment.guarantee_check_id

# lines, documents, history (adding lines recalculates the payment amount)
client.purchases.lines(payment.id)
client.purchases.add_lines(payment.id, {"description": "stapler", "quantity": 1, "unit_price": 90000})   # one
client.purchases.add_lines(payment.id, [{"description": "a", "quantity": 1, "unit_price": 10}, ...])     # many
client.purchases.documents(payment.id)
client.purchases.add_documents(payment.id, ["/path/to/receipt.pdf"])
client.purchases.statuses(payment.id)
Method Endpoint
purchases.create_direct(...) POST /a/api/purchase/direct/create
purchases.create_indirect(...) POST /a/api/purchase/indirect/create
purchases.list(status=, kind=) GET /a/api/purchase/list
purchases.get(id) / get(request_id=) GET /a/api/purchase/<id>/status / purchase/status?request_id=
purchases.lines(id) / add_lines(id, ...) GET / POST /a/api/purchase/<id>/lines
purchases.documents(id) / add_documents(id, files) GET / POST /a/api/purchase/<id>/documents
purchases.statuses(id) GET /a/api/purchase/<id>/statuses
  • Statuses: unseen, seen, in_review, completed (PurchasePaymentStatus).
  • Payment methods: cash, installment, transfer_order (PurchasePaymentMethod). Fields of other methods are ignored by the server.
  • Line units: piece (default), kilogram, gram, liter, meter, box, pack, set, other (PurchaseLineUnit).
  • Lines and documents of a completed payment cannot be changed (CashioAPIError).
  • Money values are returned as Decimal; dates and timestamps stay strings as sent by the API.
  • Files accept the same inputs as attached_file above.

Errors

from cashio_client import (
    CashioAuthError,
    CashioNotFoundError,
    CashioValidationError,
    CashioAPIError,
)

try:
    client.transactions.create(amount=10, type="income")
except CashioAuthError as exc:
    print(exc.status_code, exc.payload)   # 401
except CashioValidationError as exc:
    print(exc.errors)                     # {"fund": ["This field is required."]}
except CashioNotFoundError as exc:
    print(exc.status_code)                # 404 (e.g. unknown purchase payment); subclass of CashioAPIError
except CashioAPIError as exc:
    print(exc.status_code, exc.payload)   # 400 detail / 405 / other

Publish to PyPI

pip install -e ".[dev]"
python -m build
twine upload dist/*

Use TestPyPI first: twine upload --repository testpypi dist/*.

License

MIT

Metadata

Release files for cashio-client 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cashio-client 0.3.0
File Size Uploaded Provenance Actions
cashio_client-0.3.0.tar.gz 25.7 kB Without provenance Details for cashio_client-0.3.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for cashio-client 0.3.0
File Interpreter ABI Platform Actions
cashio_client-0.3.0-py3-none-any.whl Python 3 none any Details for cashio_client-0.3.0-py3-none-any.whl

Total release size: 41.5 kB

Release files / cashio_client-0.3.0.tar.gz

Download URL cashio_client-0.3.0.tar.gz
Size 25.7 kB
Tags Source
SHA-256 checksum
How to use checksums
d767cdbd6da4a4bba6df3d3abe5479879d9068136e086784dd7f074d346ef295
BLAKE2b-256 checksum
How to use checksums
f3be3abca5709836b1234f26357b0c40a4752e847128fd28e48f717b1ad01cdf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / cashio_client-0.3.0-py3-none-any.whl

Download URL cashio_client-0.3.0-py3-none-any.whl
Size 15.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
211df2b8e55e7e63f7f35ba0d3cccca1fda63f2ea1cdf3ef2b37d75162433e57
BLAKE2b-256 checksum
How to use checksums
2a177323dece504c5bf4c0c9db2d7e26a94dc46d089973db2f6106415bfef28d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Security for cashio-client 0.3.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.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page