Voxplo Python SDK
Zero-dependency Python client for the Voxplo Agent Outbound-Call API. Place objective-driven AI calls, poll for results, and verify webhooks using only the Python standard library.
Requires Python 3.8+. No third-party packages needed.
Quick start
Place a call and wait for the result
from voxplo import Client
client = Client(api_key="bys_ak_YOUR_KEY")
# Place an outbound call with an objective
call = client.place_call(
to="+14155550123",
objective="Confirm the appointment for tomorrow at 2pm and ask if they need to reschedule.",
fields=[
{"name": "confirmed", "type": "boolean"},
{"name": "new_time", "type": "string"},
],
)
print("Placed:", call["callId"], "status:", call["status"])
# Poll until the call reaches a terminal status (default timeout: 180s)
result = client.wait_for_call(call["callId"], timeout=180, interval=5)
print("Final status:", result["status"])
print("Extracted fields:", result.get("extracted"))
List recent calls
calls = client.list_calls(limit=10)
for c in calls:
print(c["callId"], c["status"])
Get a specific call
call = client.get_call("call_abc123")
print(call)
Call statuses
| Status | Meaning |
|---|---|
queued |
Call accepted, waiting to be placed |
in_progress |
Call is active |
completed |
Call finished normally (terminal) |
no_answer |
Recipient did not pick up (terminal) |
voicemail |
Reached voicemail (terminal) |
declined |
Recipient declined the call (terminal) |
failed |
Call could not complete (terminal) |
wait_for_call returns once the status is one of the five terminal states.
Webhook verification
Voxplo sends a X-BYS-Signature header with each webhook delivery.
Verify it before processing the payload.
Flask example
from flask import Flask, request, abort
from voxplo import verify_webhook
app = Flask(__name__)
WEBHOOK_SECRET = "whsec_YOUR_SECRET"
@app.route("/webhook/bys", methods=["POST"])
def bys_webhook():
sig = request.headers.get("X-BYS-Signature", "")
raw_body = request.get_data(as_text=True)
if not verify_webhook(sig, raw_body, WEBHOOK_SECRET):
abort(400, "Invalid signature")
payload = request.get_json()
print("Call update:", payload["callId"], payload["status"])
return "", 200
The signature format is t=<unix_seconds>,v1=<hex> where
hex = HMAC-SHA256(secret, f"{t}.{raw_body}").
verify_webhook never raises. It returns False for invalid or expired signatures
(default tolerance: 300 seconds).
Error handling
All API errors raise ByoursideError:
from voxplo import Client, ByoursideError
client = Client(api_key="bys_ak_YOUR_KEY")
try:
client.place_call(to="+19001234567", objective="Sell something")
except ByoursideError as e:
print(e.code) # e.g. "destination_blocked"
print(e.status) # HTTP status, or 0 for network/timeout errors
print(str(e)) # Human-readable message
Common error codes:
| Code | Meaning |
|---|---|
destination_blocked |
Destination not allowed (premium, IRSF, or unsupported country) |
invalid_number |
Number must be E.164, e.g. +14155550123 |
to_required |
Missing destination number |
objective_required |
Missing call objective |
caller_id_not_owned |
Caller ID not on your account |
rate_limited |
Rate limit reached, retry shortly |
over_minute_cap |
Outbound usage limit reached |
unauthorized |
Invalid or missing API key |
not_found |
Call ID not found |
placement_failed |
Carrier or trunk issue, retry shortly |
store_error |
Temporary service error, retry shortly |
network_error |
Could not reach the API |
timeout |
wait_for_call deadline exceeded |
Development
Clone the repo. No install step needed for local use: run tests from the sdks/python/ directory so that voxplo/ is on the path automatically.
cd sdks/python
python3 -m unittest discover -s tests
Expected output: all tests pass (11 tests across errors, client, wait, and webhooks).
If your environment does not add CWD to the path automatically, use:
cd sdks/python
PYTHONPATH=. python3 -m unittest discover -s tests
Syntax check all source files:
python3 -m py_compile voxplo/errors.py voxplo/client.py voxplo/webhooks.py voxplo/__init__.py
Publishing to PyPI is deferred. Do not publish without explicit owner approval.
Metadata
Release files for voxplo 0.1.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 |
|---|---|---|---|---|
| voxplo-0.1.0.tar.gz | 9.7 kB | Without provenance | Details for voxplo-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| voxplo-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for voxplo-0.1.0-py3-none-any.whl |
Total release size: 17.1 kB
Release files / voxplo-0.1.0.tar.gz
| Download URL | voxplo-0.1.0.tar.gz |
|---|---|
| Size | 9.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
972b1c7402531ee32641e0c18aa1d89598a91a7405680e2993c98e8e8623f927
|
|
BLAKE2b-256 checksum How to use checksums |
65b01e751c77d31d1a46926923d87342071869fee036877d57dbe49f2a5a0770
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.5
|
Release files / voxplo-0.1.0-py3-none-any.whl
| Download URL | voxplo-0.1.0-py3-none-any.whl |
|---|---|
| Size | 7.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1c482af60575d144cf450f74c0ed97c9f7873af870ba76b59e5d530875188cad
|
|
BLAKE2b-256 checksum How to use checksums |
59629228cc2d2acccab1a52efce297f7312f0718e6797500ece27d44df4c7dbc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.5
|
Security for voxplo 0.1.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.