Metadata-Version: 2.4
Name: vicifast
Version: 0.1.0
Summary: The VICIfast API for Python: phone numbers, calls, billing and webhooks.
License: MIT
Project-URL: Documentation, https://vicifast.com/api-docs
Project-URL: Homepage, https://vicifast.com
Keywords: vicifast,vicidial,phone numbers,did,telephony,api,webhooks
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Communications :: Telephony
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# vicifast

The [VICIfast API](https://vicifast.com/api-docs) for Python 3.8 and later:
buy and manage phone numbers, place back-orders, read calls, recordings and
transcripts, follow your wallet, and check the webhooks we send you. Built on
the standard library only, with no dependencies.

```sh
pip install vicifast
```

## Use

```python
import os
from vicifast import Vicifast

vf = Vicifast(api_key=os.environ["VICIFAST_API_KEY"])

print(vf.get_balance()["data"]["balance_cents"])

found = vf.search_numbers(area_code="305", limit=5)
order = vf.purchase_numbers({"numbers": [found["data"][0]["number"]]})
```

Make keys under **API → Keys** in the dashboard. A `vf_test_…` key works
against the sandbox: the same calls, with nothing charged and no real numbers
touched. Use one while you build.

Each operation in the [reference](https://vicifast.com/api-docs) is a method
named after its `operationId` in snake*case. Path parameters come first,
positionally, then the request body. Query parameters are keyword arguments. A
parameter whose name is a Python keyword takes a trailing underscore:
`vf.list_calls(from*="2026-10-01")`.

## Pages

A list answers one page at a time. `paginate` walks every page for you:

```python
for number in vf.paginate("listNumbers", status="active"):
    print(number["number"], number["routing"])
```

The calls export is CSV, one file per page:

```python
with open("calls.csv", "w") as out:
    for i, csv in enumerate(vf.export_call_files(window="30d")):
        out.write(csv if i == 0 else csv.split("\n", 1)[1])
```

## Errors and retries

Anything other than a success raises `VicifastError`. It carries the HTTP
`status`, a `code` to branch on (`insufficient_funds`, `rate_limited`, …), a
`message`, the offending `param` when there is one, and a `request_id` to quote
to support.

A request that is safe to repeat is retried up to `max_retries` times (default 2) on 408, 429 and 5xx, and when the connection fails. A 429 waits for
`Retry-After`. Reads are always safe to repeat. Calls that spend or move money
(a purchase, a release, a back-order, a transcript) are safe too, because each
one is sent with an `Idempotency-Key`: the same key on every retry, so a
retried purchase still buys once. The client makes the key for you, or you can
pass your own as `idempotency_key=`.

## Webhooks

Check every request against the endpoint's signing secret before trusting it.
Pass the body exactly as it arrived:

```python
from flask import Flask, abort, request
from vicifast import parse_event

app = Flask(__name__)

@app.post("/vicifast")
def vicifast():
    try:
        event = parse_event(request.get_data(), request.headers.get("X-VICIfast-Signature"), os.environ["VICIFAST_WEBHOOK_SECRET"])
    except ValueError:
        abort(400)
    if event["type"] == "call.inbound.completed":
        ...
    return "", 200
```

`verify_signature(body, header, secret)` gives you the same check as a
boolean. A request signed more than five minutes ago is refused.

Licensed MIT. This package is generated from
[vicifast.com/api-docs/openapi.json](https://vicifast.com/api-docs/openapi.json).
