Voice DID API
The Voice DID resource covers all nine operations under /did in QuestBlue API 2.3.2. Request
models validate documented constraints before network access and response models preserve unknown
fields.
Discovery and inventory
from questblue import DIDAvailabilityRequest, DIDListRequest, DIDTier, DIDType
inventory = qb.dids.list(DIDListRequest(did="*456*", per_page=50, page=1))
states = qb.dids.states()
centers = qb.dids.rate_centers("NC", DIDTier.TIER_1)
available = qb.dids.available(
DIDAvailabilityRequest(
did_type=DIDType.LOCAL,
state="NC",
ratecenter="CARY",
total_list=10,
)
)
DIDListRequest accepts did, per_page, and page. Wildcard searches must contain at least
three digits, per_page is 5–200, and pages begin at one. Iterate typed pages without losing raw DID
configuration fields:
for page in qb.dids.pages(DIDListRequest(per_page=200)):
if hasattr(page, "warning"):
break
for did, configuration in page.data.items():
print(did, configuration)
DIDAvailabilityRequest accepts did_type, tier, state, ratecenter, zip, code, mask,
and total_list. Local discovery requires a ZIP, mask, or state/rate-center pair. Toll-free
discovery requires a mask or legacy two-digit code. total_list must be positive.
Ordering and configuration
Ordering provisions inventory and may immediately incur charges:
from questblue import AccountToggle, DIDOrderRequest, DIDTier
request = DIDOrderRequest(
did=[15551234567, 15551234568],
tier=DIDTier.TIER_1,
route2trunk="primary",
cnam=AccountToggle.ON,
note="Customer main lines",
pin=1234,
lidb="Example Co",
)
# Billable: confirm pricing and account before executing.
warning = qb.dids.order(request)
DIDOrderRequest supports did, tier, route2trunk, cnam, note, pin, lidb, all E911
registration fields, and all DLDA directory-listing fields. An array of DIDs is serialized as the
comma-separated representation expected by QuestBlue. Notes are limited to 100 characters, PINs
to four–six digits, and LIDB names to 4–15 alphanumeric characters (spaces allowed).
DIDUpdateRequest requires did and supports:
- routing:
route2trunk, legacyforw2did, and nestedfailovervalues; - identity:
cnam,note,pin, andlidb; - E911:
e911,e911_call_alert,e911_name,e911_city,e911_state,e911_zip,e911_address,e911_unittype, ande911_unitnumber; - DLDA:
dlda,dlda_type,dlda_firstname,dlda_lastname,dlda_streetnum,dlda_streetname,dlda_city,dlda_state,dlda_zip,dlda_email, anddlda_phone.
The upstream schema describes E911/DLDA ZIP values inconsistently as six characters; the SDK accepts 5–10 characters to support ordinary ZIP and ZIP+4 formats without inventing a provider guarantee. QuestBlue marks direct forwarding and failover parameters as legacy in favor of trunk forwarding.
Destructive and lifecycle operations
qb.dids.update(DIDUpdateRequest(did=15551234567, route2trunk="secondary"))
qb.dids.move_to_fax(15551234567)
qb.dids.delete(15551234567)
fraud = qb.dids.validate_fraud([15557654321, 15559876543])
Ordering, updating, moving, and deleting are single-attempt operations and are never retried. A timeout can have an uncertain outcome. Re-read inventory before manually repeating an action. Moving a DID to fax changes its product role; deleting may release the number. Both should require an application-level confirmation and audit record.
Fraud validation accepts one number or up to 100 numbers and returns FraudValidationResponse.
The pinned Voice DID operations do not expose an SMS-permission parameter. SMS-capable DID
inventory and smsv2 permission/settings fields are separate upstream operations and are tracked
under QB-008; the SDK does not invent a /did parameter that QuestBlue has not documented.
Async parity
Every operation and page iterator has the same async contract:
inventory = await qb.dids.list(DIDListRequest(per_page=200))
async for page in qb.dids.pages(DIDListRequest(per_page=200)):
print(page)
Operation reference
| SDK method | HTTP operation | Request | Response |
|---|---|---|---|
qb.dids.list() |
GET /did |
DIDListRequest |
DIDInventoryResponse |
qb.dids.order() |
POST /did |
DIDOrderRequest |
empty or WarningResponse |
qb.dids.update() |
PUT /did |
DIDUpdateRequest |
empty or WarningResponse |
qb.dids.delete() |
DELETE /did |
DIDDeleteRequest |
empty |
qb.dids.states() |
GET /did/states |
— | DIDStatesResponse |
qb.dids.rate_centers() |
GET /did/ratecenters |
DIDRateCentersRequest |
DIDRateCentersResponse |
qb.dids.available() |
GET /did/available |
DIDAvailabilityRequest |
AvailableDIDsResponse |
qb.dids.move_to_fax() |
PUT /did/move2fax |
DIDMoveToFaxRequest |
empty |
qb.dids.validate_fraud() |
POST /did/fraudvalidate |
DIDFraudValidationRequest |
FraudValidationResponse |
Sandbox verification status
QuestBlue does not publish a sandbox endpoint or test-mode flag. The opt-in lifecycle test under
tests/live/ is disabled unless dedicated sandbox credentials, a base URL, and an explicit billing
acknowledgment are supplied. It must never run against ordinary production credentials. Live order,
inventory, update, and deletion verification remains pending the sandbox/subaccount work in QB-015.