Skip to content

DIDs (caller IDs)

Generated from DialerDigital/core commit 6e9f026f0a72 — spec openapi/dialer-v1.yaml v0.36.0. Do not edit by hand; see How this reference is built. Download the OpenAPI spec.

DID registry + CDR-computed health.

Endpoints

MethodPathSummary
GET/v1/didsDID registry
POST/v1/didsRegister a tenant-owned number
GET/v1/dids/{id}Fetch one DID
PATCH/v1/dids/{id}Update metadata/status (e164 immutable)
DELETE/v1/dids/{id}Retire a DID (rows never delete)
GET/v1/dids/{id}/healthCDR-computed DID health

DID registry

http
GET /v1/dids

Parameters

NameInTypeRequiredDescription
statusqueryactive · quarantine · retiredno

Responses

200

Registry rows ordered by e164.

FieldTypeRequiredDescription
didsarray of DIDyes
dids[].idstring (uuid)no
dids[].tenant_idstring (uuid)no
dids[].e164stringnoImmutable after creation.
dids[].npastring | nullno
dids[].us_statestring | nullno
dids[].attestationA · B · C · unknownnoSTIR/SHAKEN level the carrier signs.
dids[].statusactive · quarantine · retiredno
dids[].originhouse · customernohouse rows are admin-minted platform inventory; the tenant surface only creates customer.
dids[].labelsarray of stringno
dids[].notesstring | nullno
dids[].created_atstring (date-time)no
dids[].updated_atstring (date-time)no

400 — BadRequest

Malformed request (shape/type errors, invalid filters, bad timestamps).

json
{
  "error": {
    "code": "bad_request",
    "message": "from must be RFC-3339"
  }
}

401 — Unauthorized

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature).

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

Register a tenant-owned number

http
POST /v1/dids

e164 unique per tenant → 409 conflict on duplicates; npa is derived from +1 numbers when omitted. The tenant surface can only ever create origin: customer rows — house inventory is admin-minted (POST /v1/admin/tenants/{id}/dids).

Request body (JSON, required)

FieldTypeRequiredDescription
e164stringyesE.164 (immutable after creation).
npastringno
us_statestringno
attestationA · B · C · unknownno
statusactive · quarantine · retiredno
labelsarray of stringno
notesstringno
originhouse · customernoAccepted and IGNORED FOR SAFETY: a tenant can never mint origin: house, so any value here is overridden with customer. The enum mirrors the response schema because a GET of a house DID returns house — sending that value back does not fail, it has no effect. Declared so that THIS key does not become a 400 now that unknown keys are. It does NOT make the whole rendered object round-trip: id, tenant_id, created_at and updated_at are not accepted and DO get the 400.
json
{
  "e164": "+13125550142",
  "us_state": "IL"
}

Responses

201

Registered DID.

FieldTypeRequiredDescription
didobject (DID)yes
did.idstring (uuid)no
did.tenant_idstring (uuid)no
did.e164stringnoImmutable after creation.
did.npastring | nullno
did.us_statestring | nullno
did.attestationA · B · C · unknownnoSTIR/SHAKEN level the carrier signs.
did.statusactive · quarantine · retiredno
did.originhouse · customernohouse rows are admin-minted platform inventory; the tenant surface only creates customer.
did.labelsarray of stringno
did.notesstring | nullno
did.created_atstring (date-time)no
did.updated_atstring (date-time)no

400 — BadRequest

Malformed request (shape/type errors, invalid filters, bad timestamps).

json
{
  "error": {
    "code": "bad_request",
    "message": "from must be RFC-3339"
  }
}

401 — Unauthorized

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature).

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

409 — Conflict

Invalid state transition, uniqueness conflict, or a seat that is busy/reserved.

json
{
  "error": {
    "code": "conflict",
    "message": "invalid state transition"
  }
}

Fetch one DID

http
GET /v1/dids/{id}

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Responses

200

The DID.

FieldTypeRequiredDescription
didobject (DID)yes
did.idstring (uuid)no
did.tenant_idstring (uuid)no
did.e164stringnoImmutable after creation.
did.npastring | nullno
did.us_statestring | nullno
did.attestationA · B · C · unknownnoSTIR/SHAKEN level the carrier signs.
did.statusactive · quarantine · retiredno
did.originhouse · customernohouse rows are admin-minted platform inventory; the tenant surface only creates customer.
did.labelsarray of stringno
did.notesstring | nullno
did.created_atstring (date-time)no
did.updated_atstring (date-time)no

401 — Unauthorized

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature).

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

404 — NotFound

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

Update metadata/status (e164 immutable)

http
PATCH /v1/dids/{id}

A different number is a different DID; CDR history is never re-attributed.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Request body (JSON, required)

FieldTypeRequiredDescription
npastringno
us_statestringno
attestationA · B · C · unknownno
statusactive · quarantine · retiredno
labelsarray of stringno
notesstringno
originhouse · customernoAccepted and IGNORED FOR SAFETY, same as on POST /v1/dids: origin is immutable and never cast, so any value here has no effect. Sending back the value a GET returned does not fail; the rest of the rendered object still does (id, tenant_id, e164, created_at, updated_at are a 400).
json
{
  "attestation": "A",
  "labels": [
    "postman"
  ],
  "notes": "postman smoke"
}

Responses

200

Updated DID.

FieldTypeRequiredDescription
didobject (DID)yes
did.idstring (uuid)no
did.tenant_idstring (uuid)no
did.e164stringnoImmutable after creation.
did.npastring | nullno
did.us_statestring | nullno
did.attestationA · B · C · unknownnoSTIR/SHAKEN level the carrier signs.
did.statusactive · quarantine · retiredno
did.originhouse · customernohouse rows are admin-minted platform inventory; the tenant surface only creates customer.
did.labelsarray of stringno
did.notesstring | nullno
did.created_atstring (date-time)no
did.updated_atstring (date-time)no

400 — BadRequest

Malformed request (shape/type errors, invalid filters, bad timestamps).

json
{
  "error": {
    "code": "bad_request",
    "message": "from must be RFC-3339"
  }
}

401 — Unauthorized

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature).

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

404 — NotFound

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

Retire a DID (rows never delete)

http
DELETE /v1/dids/{id}

Sets status retired, idempotent. Rows never leave the registry (DELETE is revoked in Postgres): CDR from_number provenance must keep resolving for the Defense Packet.

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.

Responses

200

The retired DID.

FieldTypeRequiredDescription
didobject (DID)yes
did.idstring (uuid)no
did.tenant_idstring (uuid)no
did.e164stringnoImmutable after creation.
did.npastring | nullno
did.us_statestring | nullno
did.attestationA · B · C · unknownnoSTIR/SHAKEN level the carrier signs.
did.statusactive · quarantine · retiredno
did.originhouse · customernohouse rows are admin-minted platform inventory; the tenant surface only creates customer.
did.labelsarray of stringno
did.notesstring | nullno
did.created_atstring (date-time)no
did.updated_atstring (date-time)no

401 — Unauthorized

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature).

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

404 — NotFound

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

CDR-computed DID health

http
GET /v1/dids/{id}/health

Health is COMPUTED from the append-only CDR at read time — every number is a row count, never a cached score. short_call_rate (answered calls ended in under 15 s / answered) is the strongest CDR-side "spam likely" signal. Rates are null when the denominator is zero. reputation.hiya/reputation.tns are explicit nulls until an external feed is contracted. A retired DID still serves health (provenance outlives rotation).

Parameters

NameInTypeRequiredDescription
idpathstring (uuid)yesResource UUID. Malformed or cross-tenant ids read as 404.
fromquerystring (date-time)noRFC 3339 lower bound (endpoint-specific field; default trailing 30 UTC days where noted).
toquerystring (date-time)noRFC 3339 upper bound.

Responses

200

Computed health for the period (default trailing 30 UTC days).

FieldTypeRequiredDescription
did_idstring (uuid)no
e164stringno
statusactive · quarantine · retiredno
periodobjectno
period.fromstring (date-time)no
period.tostring (date-time)no
dialsintegerno
answeredintegerno
answer_ratenumber | nullno
short_callsintegerno
short_call_ratenumber | nullno
short_call_secondsintegerno
dailyarray of objectno
daily[].datestring (date)no
daily[].dialsintegerno
daily[].answeredintegerno
daily[].short_callsintegerno
reputationobjectnoExplicit nulls until an external feed is contracted — render as pending, not zero.
reputation.hiyanumber | nullno
reputation.tnsnumber | nullno
reputation.notestringno
json
{
  "did_id": "4e3d2c1b-0a9f-4e8d-7c6b-5a4f3e2d1c0b",
  "e164": "+13125550184",
  "status": "active",
  "period": {
    "from": "2026-06-05T00:00:00Z",
    "to": "2026-07-05T00:00:00Z"
  },
  "dials": 412,
  "answered": 67,
  "answer_rate": 0.1626,
  "short_calls": 24,
  "short_call_rate": 0.3582,
  "short_call_seconds": 15,
  "daily": [
    {
      "date": "2026-06-01",
      "dials": 80,
      "answered": 14,
      "short_calls": 5
    }
  ],
  "reputation": {
    "hiya": null,
    "tns": null,
    "note": "external reputation feeds not integrated yet"
  }
}

400 — BadRequest

Malformed request (shape/type errors, invalid filters, bad timestamps).

json
{
  "error": {
    "code": "bad_request",
    "message": "from must be RFC-3339"
  }
}

401 — Unauthorized

Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature).

json
{
  "error": {
    "code": "unauthorized",
    "message": "invalid or revoked API key"
  }
}

404 — NotFound

Unknown id, malformed (non-UUID) id OR another tenant's id — RLS returns zero rows, so all three are indistinguishable by design (no existence leak, never a 403 for foreign ids).

json
{
  "error": {
    "code": "not_found",
    "message": "resource not found for this tenant"
  }
}

Nothing in these docs is legal advice — always confirm compliance posture with your own counsel.