pyquestblue
A modern, typed Python SDK for the QuestBlue telecommunications API. It supports synchronous and asynchronous applications and provides resource-oriented access to the full documented QuestBlue 2.3.2 surface: accounts, voice and international DIDs, SIP trunks, SMS/MMS, 10DLC, Fax.Pro, iFax Enterprise, reports, number portability, and VoIP servers.
Status: stable 1.1. All 103 pinned QuestBlue 2.3.2 operations have typed sync/async coverage; production contract verification remains explicitly credential-gated.
Versioned, searchable documentation is published at schapman1974.github.io/pyquestblue.
Install
pip install pyquestblue
For local development:
git clone https://github.com/schapman1974/pyquestblue.git
cd pyquestblue
python -m venv .venv
source .venv/bin/activate
python -m pip install -e '.[dev]'
pytest
Quick start
QuestBlue uses HTTP Basic authentication plus a Security-Key header. Credentials can be passed
directly or loaded from QUESTBLUE_USERNAME, QUESTBLUE_PASSWORD, and
QUESTBLUE_SECURITY_KEY.
For common tasks, the additive simple facade needs no request-model imports:
from questblue import SimpleQuestBlue
with SimpleQuestBlue() as qb:
balance = qb.account.balance()
numbers = qb.numbers.search(zip_code="27513", limit=5)
Use the typed client below for exact provider control, .raw to drop down from a simple service,
and qb.workflows for inspectable, journaled multi-step provisioning.
from questblue import DIDAvailabilityRequest, DIDType, QuestBlue
with QuestBlue("username", "password", "security-key") as qb:
balance = qb.account.balance()
available = qb.dids.available(
DIDAvailabilityRequest(did_type=DIDType.LOCAL, zip=27513, total_list=10)
)
trunks = qb.sip_trunks.list(per_page=100)
Send an SMS/MMS:
result = qb.sms.send(
did=15551234567,
did_to=15557654321,
msg="Hello from pyquestblue",
file_url=["https://example.com/image.png"],
)
Retrieve typed call history:
from questblue import CallHistoryRequest, Period
calls = qb.reports.call_history(
CallHistoryRequest(
period=Period.THIS_MONTH,
trunk=["primary", "backup"],
timezone="America/New_York",
per_page=5000,
)
)
Async applications use the same resource layout:
from questblue import AsyncQuestBlue, DIDListRequest
async with AsyncQuestBlue() as qb:
inventory = await qb.dids.list(DIDListRequest(per_page=200))
Typed models preserve new upstream fields instead of dropping them, and paginators offer both item iteration and raw page access:
from questblue import QuestBlueModel, model_parser
class CallRecord(QuestBlueModel):
call_id: str
records = qb.paginate(
"/callhistory",
params={"period": "today", "per_page": 500},
item_parser=model_parser(CallRecord),
)
for record in records:
print(record.call_id)
See docs/modeling.md for validation, forward compatibility, raw payloads, and
custom pagination selectors.
See docs/transport.md for retry safety, per-request controls, raw responses,
transport errors, structured logging, and OpenTelemetry hooks.
See docs/account.md for typed balance, rates, refill, alert, and callback
operations, including explicit safeguards around billable balance changes.
See docs/dids.md for typed Voice DID discovery, ordering, E911/DLDA configuration,
pagination, fraud validation, and destructive-operation safeguards.
See docs/international-dids.md for country/city discovery,
international inventory pagination, ordering, routing updates, and release safeguards.
See docs/sip-trunks.md for registration/static trunks, routing controls,
status troubleshooting, channel options, and blocked callers.
See docs/sms.md for SMS/MMS sending, inbound settings, delivery and history,
off-net service, carrier lookup, PII-safe diagnostics, and compliance safeguards.
See docs/dlc.md for 10DLC brand and campaign registration, lifecycle states,
upstream rejection detail, protected registration data, and compliance safeguards.
See docs/fax.md for Fax.Pro discovery, inventory lifecycle, validated document
sending, email permissions, migration safeguards, and executable examples.
See docs/enterprise-fax.md for typed iFax Enterprise account, group,
user, permission, upload, multi-file send, and lifecycle workflows.
See docs/reports.md for typed voice and fax history, large-result iteration,
incremental fax downloads, and CSV/pandas-friendly exports.
See docs/lnp.md for typed portability checks, LNP lifecycle operations, validated
bill uploads, sensitive-data handling, and production-only safeguards.
See docs/servers.md for typed server provisioning, IP allowlists, upgrades,
backup schedules, restoration, and destructive/billable safeguards.
See docs/contract-testing.md for sanitized recorded fixtures,
production risk classes, explicit live-test gates, and the verification matrix.
See docs/integrations.md for inbound messaging webhooks, FastAPI and
Django adapters, safe observability, and white-label integration boundaries.
See docs/compatibility.md, SUPPORT.md, and
SECURITY.md for supported platforms, SemVer and deprecation guarantees, the release
process, support boundaries, and private vulnerability reporting.
Every resource method accepts the parameter names from QuestBlue's API documentation. List values are serialized as comma-separated values, matching QuestBlue's generated Node client. For an API addition that has not yet received a convenience method, the authenticated transport remains usable:
result = qb.request("GET", "/new-endpoint", params={"example": "value"})
Resource map
| SDK resource | QuestBlue areas |
|---|---|
qb.account |
balance, details, rates, refill, alerts, callbacks |
qb.dids |
inventory, availability, ordering, configuration, fraud validation |
qb.international_dids |
countries, cities, inventory, ordering |
qb.sip_trunks |
trunks, registration status, blocked callers |
qb.sms |
SMS/MMS, settings, history, delivery, off-net orders, carrier checks |
qb.dlc |
10DLC brands and campaigns |
qb.fax |
Fax.Pro inventory, sending, email permissions |
qb.enterprise_fax |
iFax Enterprise accounts, groups, users, permissions, files |
qb.reports |
voice CDRs, fax history, fax downloads |
qb.lnp |
portability checks and LNP request lifecycle |
qb.servers |
server inventory, IPs, upgrades, backup lifecycle |
API coverage contract
The normalized QuestBlue OpenAPI 2.3.2 contract is pinned under spec/. A deterministic
coverage report under coverage/ maps every upstream HTTP operation to its SDK method,
sync/async availability, request/response model status, unit tests, and documentation. CI rejects
missing or extra operations, broken sync/async parity, or a stale report.
python scripts/api_coverage.py --check
python scripts/update_openapi.py --check # compares against the live QuestBlue contract
Errors and retries
The client retries safe reads after connection failures, HTTP 408/409/429 responses, and server
errors with bounded exponential backoff. Mutating and potentially billable requests are never
retried automatically. QuestBlue's documented HTTP 206 error responses are raised as exceptions.
Catch QuestBlueAPIError for API failures or a narrower transport class. The complete contract is
documented in docs/transport.md.
Publishing
- Every push and pull request is tested on Python 3.10 through 3.14.
- Publishing a GitHub Release triggers Publish to PyPI.
- Publishing uses a PyPI API token stored as an encrypted secret in the protected
pypiGitHub environment. Build-provenance attestations continue to use GitHub OIDC.
Before the first release, add PYPI_API_TOKEN to the pypi GitHub environment. Never place the
token in source, workflow files, command-line arguments, issue comments, or chat messages.
White-label platform direction
The SDK is intentionally UI-framework neutral so it can power a fully rebranded customer portal.
That portal should sit behind your own backend rather than exposing QuestBlue credentials in a
browser. The major platform layers will be tenant/customer mapping, roles and permissions, branded
catalog and pricing, ordering/provisioning workflows, usage and billing, audit logs, webhook/event
processing, and support tooling. The evidence-backed
white-label capability analysis,
tenant-isolation ADR, and
follow-on backlog define what belongs in the SDK, an optional
control plane, or the application. See ROADMAP.md for the staged build-out.
Security
Never expose QuestBlue credentials to frontend code or commit them to source control. Use scoped secrets in a backend service and rotate them if they are disclosed. Please report SDK security issues privately to the repository owner.
License
MIT
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 pyquestblue-1.1.0.tar.gz.
File metadata
- Download URL: pyquestblue-1.1.0.tar.gz
- Upload date:
- Size: 294.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a6769f6447f1132989410f2d5c9e642d416200509a92cd72a530a55e36572e9d
|
|
| MD5 |
1cb15923d457095939c6d94f93164aa0
|
|
| BLAKE2b-256 |
4abb818cbc1d24547d50354f5dbf58cc91c3e6ab89ba64b0e70c0a040d9a8fde
|
File details
Details for the file pyquestblue-1.1.0-py3-none-any.whl.
File metadata
- Download URL: pyquestblue-1.1.0-py3-none-any.whl
- Upload date:
- Size: 77.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c4233e1c8272fca61faade2964ddbce0c6f37e1d2731532aec7c2ebd79234c8
|
|
| MD5 |
365d75fdf885b8ff91964c44a4268a23
|
|
| BLAKE2b-256 |
573d7d056760b1e98ac540fa650228bd9361a943c3592e345dba783b8a1d61b9
|