Skip to main content

Official Python client for the CostClaw freight-invoice audit API.

Project description

costclaw — Python client for CostClaw

PyPI Python versions License: MIT

Official Python client for the CostClaw freight-invoice audit API. Upload quotes and invoices, and CostClaw converts them, matches invoice ↔ booking ↔ quote, flags overcharges, and drafts disputes — this library lets you drive all of it from Python with an API key.

The API is the only thing this library touches: your data stays in your CostClaw project, reached with a per-project API key. Nothing about the CostClaw internals is required or exposed.

Install

pip install costclaw

Requires Python 3.9+. The only dependency is httpx.

Authenticate

Create an API key in the app under Settings → Developer → API keys. The key's role decides what it can do:

Role Can
read_only list/read documents, issues, disputes; download PDFs
read_write the above + upload documents
admin the above + delete / clear documents

Keep keys out of source — read them from the environment:

import os
from costclaw import CostClawClient

client = CostClawClient(os.environ["COSTCLAW_API_KEY"])

By default the client talks to the CostClaw staging API. Point it elsewhere with base_url= or the COSTCLAW_BASE_URL environment variable:

client = CostClawClient(api_key, base_url="https://api.costclaw.ai")

Quick start

from costclaw import CostClawClient

with CostClawClient("ck_...") as cc:
    # upload a PDF — kicks off classify → extract → match → audit
    result = cc.upload_document("invoice-4471.pdf")
    print(result.status)          # "accepted" | "duplicate" | "rejected"

    # what's in the project?
    for doc in cc.list_documents():
        print(doc.kind, doc.status, doc.original_filename)

    # invoices we couldn't confidently match to a quote yet
    for issue in cc.list_issues():
        print(issue.original_filename, "→", issue.reason)

    # overcharges we found, with the disputed amount
    for d in cc.list_disputes():
        print(d.id, d.state, d.disputed_amount, d.currency)
        cc.download_dispute(d.id, dest=f"dispute-{d.id[:8]}.pdf")

with ... closes the underlying HTTP connection for you; without it, call client.close() when done.

API reference

Every call runs against the single project your API key is scoped to.

Documents

cc.list_documents() -> list[Document]
cc.get_document(document_id) -> Document
cc.upload_document(file, *, filename=None) -> UploadResult      # read_write
cc.upload_documents([file, ...]) -> list[UploadResult]          # read_write
cc.download_document(document_id, dest=None) -> bytes
cc.delete_document(document_id) -> None                          # admin
cc.clear_documents() -> int                                      # admin, returns count

file may be a path (str/Path), raw bytes (pass filename=), or an open binary file. Re-uploading identical content returns status="duplicate" (dedup by content hash), so retries are safe.

Reconciliation

cc.list_quotes() -> list[Quote]
cc.invoices_for_quote(quote_id) -> list[QuoteInvoice]   # invoices billed against a quote

Issues

cc.list_issues(status="open") -> list[Issue]            # "open" | "resolved" | "dismissed"

An Issue is an invoice that couldn't be matched to a quote with high confidence — usually because the quote hasn't been uploaded yet, or the match needs a human to confirm.

Disputes

cc.list_disputes() -> list[Dispute]
cc.get_dispute(dispute_id) -> Dispute
cc.download_dispute(dispute_id, dest=None) -> bytes     # PDF: evidence + draft email

Dispute.disputed_amount gives the amount in major units (e.g. dollars); Dispute.disputed_minor_units is the exact integer (cents). Full server detail — findings and the draft vendor email — is always on .raw.

Models

Each model exposes common fields as attributes and keeps the full JSON payload on .raw, so new API fields are reachable even before this library names them:

doc = cc.list_documents()[0]
doc.kind, doc.status, doc.original_filename   # typed attributes
doc.raw                                        # the complete server dict

Errors

All errors derive from CostClawError. HTTP failures raise a subclass with .status_code and .detail:

from costclaw import AuthenticationError, PermissionDeniedError, NotFoundError, APIError

try:
    cc.clear_documents()
except PermissionDeniedError:
    print("this key isn't an admin key")
except AuthenticationError:
    print("bad or revoked API key")
Exception HTTP
AuthenticationError 401
PermissionDeniedError 403
NotFoundError 404
APIError other 4xx/5xx

Examples

Runnable scripts in examples/:

  • quickstart.py — upload a file and print documents/issues/disputes.
  • audit_folder.py — upload a whole folder and save every dispute PDF.

Prefer an AI agent?

CostClaw also exposes these same actions over the Model Context Protocol — add the MCP server to Claude Code or Cursor and drive uploads/audits in plain language. See the Developer tab in the app.

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

costclaw-0.1.0.tar.gz (12.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

costclaw-0.1.0-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file costclaw-0.1.0.tar.gz.

File metadata

  • Download URL: costclaw-0.1.0.tar.gz
  • Upload date:
  • Size: 12.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for costclaw-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3cc03ed365c5a451679023f9c3c3fd6e8d84b254e41b75dc08907c221fa8c67c
MD5 fe5a38f11e156a90bcb470f44f2fe3bb
BLAKE2b-256 b15a05dd719b6eb0265364222f7930bfac383d37adae34b8c76bb542b04d6736

See more details on using hashes here.

Provenance

The following attestation bundles were made for costclaw-0.1.0.tar.gz:

Publisher: publish.yml on costclaw-ai/costclaw-lib

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file costclaw-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: costclaw-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for costclaw-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f4d5414644f22368265e233a8475094d5254800bdec227c6dc878540743b6198
MD5 20f5bb2c604bdbcf464c701ca212e06c
BLAKE2b-256 18354714b58c383ebcb0ef457da39f157ae0485e6e940f14b71a0661ec81d7d5

See more details on using hashes here.

Provenance

The following attestation bundles were made for costclaw-0.1.0-py3-none-any.whl:

Publisher: publish.yml on costclaw-ai/costclaw-lib

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page