Appearance
Segment filters
Generated from
DialerDigital/corecommit0fc18008b3c8— specopenapi/dialer-v1.yamlv0.134.0. Do not edit by hand; see How this reference is built. Download the OpenAPI spec.
Saved segmentation filters (the criteria of GET /v1/debts with a name), versioned append-only per tenant. Behind the debt_segmentation_enabled flag (ADR #221).
Endpoints
| Method | Path | Summary |
|---|---|---|
GET | /v1/segment-filters | The tenant's saved segmentation filters, each with its current version |
POST | /v1/segment-filters | Create a saved filter (version 1) |
GET | /v1/segment-filters/{id} | One saved filter, at its current version |
PATCH | /v1/segment-filters/{id} | Rename a filter, or edit its criteria into a NEW version |
DELETE | /v1/segment-filters/{id} | Archive a saved filter |
POST | /v1/segment-filters/{id}/to-list | Freeze what a saved filter selects NOW into a list |
POST | /v1/segment-filters/to-list | Freeze what inline criteria select NOW into a list |
The tenant's saved segmentation filters, each with its current version
http
GET /v1/segment-filtersBehind the debt_segmentation_enabled flag: with it off (the default) every /v1/segment-filters route answers 404, whatever the caller. By name, the live ones; ?include_archived=true adds the archived. Each filter comes with its CURRENT version. Capped at 2 000.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
include_archived | query | boolean | no |
Responses
200
The filters.
| Field | Type | Required | Description |
|---|---|---|---|
segment_filters | array of SegmentFilter | yes | |
segment_filters[].id | string (uuid) | yes | |
segment_filters[].tenant_id | string (uuid) | no | |
segment_filters[].name | string | yes | |
segment_filters[].archived | boolean | yes | |
segment_filters[].version | integer | yes | The current version. |
segment_filters[].criteria | any | yes | The criteria of the current version, in canonical form (lists sorted, without repeats). |
segment_filters[].version_created_at | string (date-time) | no | |
segment_filters[].created_at | string (date-time) | no | |
segment_filters[].updated_at | string (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). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.
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"
}
}Create a saved filter (version 1)
http
POST /v1/segment-filtersname is trimmed, not blank, at most 200 characters and unique among the tenant's LIVE filters (409). criteria goes through Dialer.Debts.Segment (ADR #221): a closed vocabulary, a value outside it is a 400, and phone, consumer_ref, external_ref and debtor_name are refused by name. The server stores the canonical form (lists sorted, without repeats). An empty object is valid: the whole portfolio. A tenant holds at most 500 live filters (422). Needs the tenant scope (403 for an agent token). With the flag off, 404.
Request body (JSON, required)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | |
criteria | object (SegmentCriteria) | yes | Criteria accepted by the segment-filter writes and to-list routes (Dialer.Debts.Segment, ADR #221). A closed vocabulary, combined with AND; an empty object is the whole portfolio. state, debt_type, us_state and regf_status take one value or a list (they are always returned as a sorted list without repeats). phone, consumer_ref, external_ref and debtor_name are refused by name. |
criteria.campaign_id | string (uuid) | no | |
criteria.state | open · in_collection · promise_to_pay · paid · settled · disputed · closed | array of open · in_collection · promise_to_pay · paid · settled · disputed · closed | no | |
criteria.debt_type | other · student_loan | array of other · student_loan | no | |
criteria.us_state | string | array of string | no | |
criteria.regf_status | ok · blocked_7in7 · blocked_post_contact · undecidable | array of ok · blocked_7in7 · blocked_post_contact · undecidable | no | ADR #221 criterion: current Reg F eligibility derived by the server. |
criteria.min_amount_cents | integer | no | |
criteria.max_amount_cents | integer | no | |
criteria.min_age_days | integer | no | ADR #221 criterion: delinquent for at least this many days (debts.delinquent_since against today); a debt with no delinquent_since never matches. |
criteria.max_age_days | integer | no | ADR #221 criterion: delinquent for at most this many days (debts.delinquent_since against today); a debt with no delinquent_since never matches. A min_age_days above max_age_days is refused. |
json
{
"name": "Texas student loans over 500 USD",
"criteria": {
"debt_type": [
"student_loan"
],
"us_state": [
"TX"
],
"min_amount_cents": 50000
}
}Responses
201
The filter, at version 1.
| Field | Type | Required | Description |
|---|---|---|---|
segment_filter | object (SegmentFilter) | yes | A saved filter: its header and its CURRENT version. |
segment_filter.id | string (uuid) | yes | |
segment_filter.tenant_id | string (uuid) | no | |
segment_filter.name | string | yes | |
segment_filter.archived | boolean | yes | |
segment_filter.version | integer | yes | The current version. |
segment_filter.criteria | any | yes | The criteria of the current version, in canonical form (lists sorted, without repeats). |
segment_filter.version_created_at | string (date-time) | no | |
segment_filter.created_at | string (date-time) | no | |
segment_filter.updated_at | string (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). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.
json
{
"error": {
"code": "unauthorized",
"message": "invalid or revoked API key"
}
}403 — Forbidden
The tenant is suspended. A dashboard session (ddu_) of a tenant whose login policy (ADR 227) is in mode enforce answers 403 with the code login_policy_denied on a request from an address or at an hour the policy does not allow — the same body for both; the session is not revoked and a later request inside the policy goes through. A widget token (ddw_) of a seat is held to the same policy on every request (core#2406, flag widget_login_honors_policy). A synthetic (demo) tenant answers 403 with the code synthetic_tenant on every route that would reach a third party — manual dial, external transfer or conference leg, SMS send (core#2251, ADR #280 addendum). No payment changes it.
json
{
"error": {
"code": "forbidden",
"message": "tenant is suspended"
}
}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"
}
}409 — Conflict
Invalid state transition, uniqueness conflict, or a seat that is busy/reserved.
json
{
"error": {
"code": "conflict",
"message": "invalid state transition"
}
}422 — Unprocessable
Shape is fine, semantics are not (broken domain rule).
json
{
"error": {
"code": "unprocessable",
"message": "scheduled_at is closer than the minimum notice for a callback (10 minutes unless the tenant's callback_min_notice_seconds says otherwise)"
}
}One saved filter, at its current version
http
GET /v1/segment-filters/{id}Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Responses
200
The filter (archived ones too, flagged archived).
| Field | Type | Required | Description |
|---|---|---|---|
segment_filter | object (SegmentFilter) | yes | A saved filter: its header and its CURRENT version. |
segment_filter.id | string (uuid) | yes | |
segment_filter.tenant_id | string (uuid) | no | |
segment_filter.name | string | yes | |
segment_filter.archived | boolean | yes | |
segment_filter.version | integer | yes | The current version. |
segment_filter.criteria | any | yes | The criteria of the current version, in canonical form (lists sorted, without repeats). |
segment_filter.version_created_at | string (date-time) | no | |
segment_filter.created_at | string (date-time) | no | |
segment_filter.updated_at | string (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). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.
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"
}
}Rename a filter, or edit its criteria into a NEW version
http
PATCH /v1/segment-filters/{id}Send at least one of name, criteria. A rename changes the header only. Changing criteria appends version n+1 and leaves version n exactly as it was: a list materialised from it may have used it. criteria REPLACES the current ones, it is not merged. An edit that changes nothing writes no version. base_version is optional and, when sent, must be the current version, otherwise 409 and nothing is written, so two people editing the same filter do not overwrite each other unnoticed. An archived filter cannot be edited (409); a filter holds at most 1 000 versions (422). Needs the tenant scope. With the flag off, 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Request body (JSON, required)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | no | |
criteria | object (SegmentCriteria) | no | Criteria accepted by the segment-filter writes and to-list routes (Dialer.Debts.Segment, ADR #221). A closed vocabulary, combined with AND; an empty object is the whole portfolio. state, debt_type, us_state and regf_status take one value or a list (they are always returned as a sorted list without repeats). phone, consumer_ref, external_ref and debtor_name are refused by name. |
criteria.campaign_id | string (uuid) | no | |
criteria.state | open · in_collection · promise_to_pay · paid · settled · disputed · closed | array of open · in_collection · promise_to_pay · paid · settled · disputed · closed | no | |
criteria.debt_type | other · student_loan | array of other · student_loan | no | |
criteria.us_state | string | array of string | no | |
criteria.regf_status | ok · blocked_7in7 · blocked_post_contact · undecidable | array of ok · blocked_7in7 · blocked_post_contact · undecidable | no | ADR #221 criterion: current Reg F eligibility derived by the server. |
criteria.min_amount_cents | integer | no | |
criteria.max_amount_cents | integer | no | |
criteria.min_age_days | integer | no | ADR #221 criterion: delinquent for at least this many days (debts.delinquent_since against today); a debt with no delinquent_since never matches. |
criteria.max_age_days | integer | no | ADR #221 criterion: delinquent for at most this many days (debts.delinquent_since against today); a debt with no delinquent_since never matches. A min_age_days above max_age_days is refused. |
base_version | integer | no |
json
{
"base_version": 1,
"criteria": {
"us_state": [
"TX",
"NY"
]
}
}Responses
200
The filter, at its current version after the edit.
| Field | Type | Required | Description |
|---|---|---|---|
segment_filter | object (SegmentFilter) | yes | A saved filter: its header and its CURRENT version. |
segment_filter.id | string (uuid) | yes | |
segment_filter.tenant_id | string (uuid) | no | |
segment_filter.name | string | yes | |
segment_filter.archived | boolean | yes | |
segment_filter.version | integer | yes | The current version. |
segment_filter.criteria | any | yes | The criteria of the current version, in canonical form (lists sorted, without repeats). |
segment_filter.version_created_at | string (date-time) | no | |
segment_filter.created_at | string (date-time) | no | |
segment_filter.updated_at | string (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). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.
json
{
"error": {
"code": "unauthorized",
"message": "invalid or revoked API key"
}
}403 — Forbidden
The tenant is suspended. A dashboard session (ddu_) of a tenant whose login policy (ADR 227) is in mode enforce answers 403 with the code login_policy_denied on a request from an address or at an hour the policy does not allow — the same body for both; the session is not revoked and a later request inside the policy goes through. A widget token (ddw_) of a seat is held to the same policy on every request (core#2406, flag widget_login_honors_policy). A synthetic (demo) tenant answers 403 with the code synthetic_tenant on every route that would reach a third party — manual dial, external transfer or conference leg, SMS send (core#2251, ADR #280 addendum). No payment changes it.
json
{
"error": {
"code": "forbidden",
"message": "tenant is suspended"
}
}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"
}
}409 — Conflict
Invalid state transition, uniqueness conflict, or a seat that is busy/reserved.
json
{
"error": {
"code": "conflict",
"message": "invalid state transition"
}
}422 — Unprocessable
Shape is fine, semantics are not (broken domain rule).
json
{
"error": {
"code": "unprocessable",
"message": "scheduled_at is closer than the minimum notice for a callback (10 minutes unless the tenant's callback_min_notice_seconds says otherwise)"
}
}Archive a saved filter
http
DELETE /v1/segment-filters/{id}Filters are never deleted: a version a list was materialised from is evidence. Archiving frees the name for a new filter and takes the filter out of the default list; it can no longer be edited. Idempotent. Needs the tenant scope. With the flag off, 404.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Responses
204
The filter is archived.
401 — Unauthorized
Missing, unknown or revoked API key (or, on /v1/admin/*, a bad/unset admin token; on webhooks, a bad/missing signature). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.
json
{
"error": {
"code": "unauthorized",
"message": "invalid or revoked API key"
}
}403 — Forbidden
The tenant is suspended. A dashboard session (ddu_) of a tenant whose login policy (ADR 227) is in mode enforce answers 403 with the code login_policy_denied on a request from an address or at an hour the policy does not allow — the same body for both; the session is not revoked and a later request inside the policy goes through. A widget token (ddw_) of a seat is held to the same policy on every request (core#2406, flag widget_login_honors_policy). A synthetic (demo) tenant answers 403 with the code synthetic_tenant on every route that would reach a third party — manual dial, external transfer or conference leg, SMS send (core#2251, ADR #280 addendum). No payment changes it.
json
{
"error": {
"code": "forbidden",
"message": "tenant is suspended"
}
}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"
}
}Freeze what a saved filter selects NOW into a list
http
POST /v1/segment-filters/{id}/to-listA PHOTO (ADR #221, core#1687): the debts the filter's LATEST version selects at this moment are put in the list, and the list does not follow the filter afterwards. Only the tenant's debts enter; the Reg F criteria use the real Reg F logic. Idempotent by (list_id, debt_id): repeating the request adds nothing (added: 0) and still records its own evidence row.
The target is EXACTLY ONE of list_id (an existing list of the tenant: 200) or new_list_name (a list created in the same request, unique name: 201); none or both is a 400.
The tenant's catalog cap debt_segment_max_rows (default 10 000, never above the Reg F candidate ceiling) bounds how many debts are written; reaching it is truncated: true in the answer, never silent, and the photo then covers only the most recent candidates. A cap of 0 or less is 422 and writes nothing. An archived filter, or an archived list_id list, is 409. A list_id or filter that is not the tenant's, or not a UUID, is 404. A request that fails leaves no empty list behind. Needs the tenant scope (403 for an agent token). Behind the debt_segmentation_enabled flag: off, 404 and nothing is read or written.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string (uuid) | yes | Resource UUID. Malformed or cross-tenant ids read as 404. |
Request body (JSON, required)
| Field | Type | Required | Description |
|---|---|---|---|
list_id | string (uuid) | no | |
new_list_name | string | no |
json
{
"new_list_name": "Texas student loans",
"July photo": null
}Responses
200
The photo was written into the existing list.
| Field | Type | Required | Description |
|---|---|---|---|
segment_materialization | object (SegmentMaterialization) | yes | The evidence row of one photo (append-only). matched debts were selected (at most max_rows), added of them were NEW in the list and truncated says the catalog cap cut the result. |
segment_materialization.id | string (uuid) | yes | |
segment_materialization.tenant_id | string (uuid) | no | |
segment_materialization.list_id | string (uuid) | yes | |
segment_materialization.filter_id | string (uuid) | null | yes | The saved filter, or null when the criteria came inline. |
segment_materialization.filter_version | integer | null | yes | The version of the filter that was used, or null when inline. |
segment_materialization.criteria | any | yes | The criteria that were evaluated, in canonical form. |
segment_materialization.max_rows | integer | yes | The cap in force for this photo. |
segment_materialization.matched | integer | yes | |
segment_materialization.added | integer | yes | |
segment_materialization.truncated | boolean | yes | |
segment_materialization.requested_at | string (date-time) | no | |
debt_list | any | yes | The target list, its size counted after the photo. |
201
The list was created and the photo written into it.
| Field | Type | Required | Description |
|---|---|---|---|
segment_materialization | object (SegmentMaterialization) | yes | The evidence row of one photo (append-only). matched debts were selected (at most max_rows), added of them were NEW in the list and truncated says the catalog cap cut the result. |
segment_materialization.id | string (uuid) | yes | |
segment_materialization.tenant_id | string (uuid) | no | |
segment_materialization.list_id | string (uuid) | yes | |
segment_materialization.filter_id | string (uuid) | null | yes | The saved filter, or null when the criteria came inline. |
segment_materialization.filter_version | integer | null | yes | The version of the filter that was used, or null when inline. |
segment_materialization.criteria | any | yes | The criteria that were evaluated, in canonical form. |
segment_materialization.max_rows | integer | yes | The cap in force for this photo. |
segment_materialization.matched | integer | yes | |
segment_materialization.added | integer | yes | |
segment_materialization.truncated | boolean | yes | |
segment_materialization.requested_at | string (date-time) | no | |
debt_list | any | yes | The target list, its size counted after the photo. |
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). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.
json
{
"error": {
"code": "unauthorized",
"message": "invalid or revoked API key"
}
}403 — Forbidden
The tenant is suspended. A dashboard session (ddu_) of a tenant whose login policy (ADR 227) is in mode enforce answers 403 with the code login_policy_denied on a request from an address or at an hour the policy does not allow — the same body for both; the session is not revoked and a later request inside the policy goes through. A widget token (ddw_) of a seat is held to the same policy on every request (core#2406, flag widget_login_honors_policy). A synthetic (demo) tenant answers 403 with the code synthetic_tenant on every route that would reach a third party — manual dial, external transfer or conference leg, SMS send (core#2251, ADR #280 addendum). No payment changes it.
json
{
"error": {
"code": "forbidden",
"message": "tenant is suspended"
}
}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"
}
}409 — Conflict
Invalid state transition, uniqueness conflict, or a seat that is busy/reserved.
json
{
"error": {
"code": "conflict",
"message": "invalid state transition"
}
}422 — Unprocessable
Shape is fine, semantics are not (broken domain rule).
json
{
"error": {
"code": "unprocessable",
"message": "scheduled_at is closer than the minimum notice for a callback (10 minutes unless the tenant's callback_min_notice_seconds says otherwise)"
}
}Freeze what inline criteria select NOW into a list
http
POST /v1/segment-filters/to-listThe same photo as POST /v1/segment-filters/{id}/to-list, with the criteria in the body instead of a saved filter (the evidence row then has no filter_id). criteria goes through Dialer.Debts.Segment: a value outside the closed vocabulary, a PII key or a non-object is a 400, and nothing is written. An empty object is the whole portfolio, still bounded by the cap. Target, cap, scope and flag as in the saved-filter form.
Request body (JSON, required)
| Field | Type | Required | Description |
|---|---|---|---|
criteria | object (SegmentCriteria) | yes | Criteria accepted by the segment-filter writes and to-list routes (Dialer.Debts.Segment, ADR #221). A closed vocabulary, combined with AND; an empty object is the whole portfolio. state, debt_type, us_state and regf_status take one value or a list (they are always returned as a sorted list without repeats). phone, consumer_ref, external_ref and debtor_name are refused by name. |
criteria.campaign_id | string (uuid) | no | |
criteria.state | open · in_collection · promise_to_pay · paid · settled · disputed · closed | array of open · in_collection · promise_to_pay · paid · settled · disputed · closed | no | |
criteria.debt_type | other · student_loan | array of other · student_loan | no | |
criteria.us_state | string | array of string | no | |
criteria.regf_status | ok · blocked_7in7 · blocked_post_contact · undecidable | array of ok · blocked_7in7 · blocked_post_contact · undecidable | no | ADR #221 criterion: current Reg F eligibility derived by the server. |
criteria.min_amount_cents | integer | no | |
criteria.max_amount_cents | integer | no | |
criteria.min_age_days | integer | no | ADR #221 criterion: delinquent for at least this many days (debts.delinquent_since against today); a debt with no delinquent_since never matches. |
criteria.max_age_days | integer | no | ADR #221 criterion: delinquent for at most this many days (debts.delinquent_since against today); a debt with no delinquent_since never matches. A min_age_days above max_age_days is refused. |
list_id | string (uuid) | no | |
new_list_name | string | no |
json
{
"criteria": {
"debt_type": [
"student_loan"
],
"us_state": [
"TX"
]
},
"list_id": "6f1c2a52-3b52-4b3d-9d57-0e5c6a8f1a10"
}Responses
200
The photo was written into the existing list.
| Field | Type | Required | Description |
|---|---|---|---|
segment_materialization | object (SegmentMaterialization) | yes | The evidence row of one photo (append-only). matched debts were selected (at most max_rows), added of them were NEW in the list and truncated says the catalog cap cut the result. |
segment_materialization.id | string (uuid) | yes | |
segment_materialization.tenant_id | string (uuid) | no | |
segment_materialization.list_id | string (uuid) | yes | |
segment_materialization.filter_id | string (uuid) | null | yes | The saved filter, or null when the criteria came inline. |
segment_materialization.filter_version | integer | null | yes | The version of the filter that was used, or null when inline. |
segment_materialization.criteria | any | yes | The criteria that were evaluated, in canonical form. |
segment_materialization.max_rows | integer | yes | The cap in force for this photo. |
segment_materialization.matched | integer | yes | |
segment_materialization.added | integer | yes | |
segment_materialization.truncated | boolean | yes | |
segment_materialization.requested_at | string (date-time) | no | |
debt_list | any | yes | The target list, its size counted after the photo. |
201
The list was created and the photo written into it.
| Field | Type | Required | Description |
|---|---|---|---|
segment_materialization | object (SegmentMaterialization) | yes | The evidence row of one photo (append-only). matched debts were selected (at most max_rows), added of them were NEW in the list and truncated says the catalog cap cut the result. |
segment_materialization.id | string (uuid) | yes | |
segment_materialization.tenant_id | string (uuid) | no | |
segment_materialization.list_id | string (uuid) | yes | |
segment_materialization.filter_id | string (uuid) | null | yes | The saved filter, or null when the criteria came inline. |
segment_materialization.filter_version | integer | null | yes | The version of the filter that was used, or null when inline. |
segment_materialization.criteria | any | yes | The criteria that were evaluated, in canonical form. |
segment_materialization.max_rows | integer | yes | The cap in force for this photo. |
segment_materialization.matched | integer | yes | |
segment_materialization.added | integer | yes | |
segment_materialization.truncated | boolean | yes | |
segment_materialization.requested_at | string (date-time) | no | |
debt_list | any | yes | The target list, its size counted after the photo. |
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). A dashboard session (ddu_) that a newer login of the same person ended answers the code session_superseded instead (tenant flag single_session_enforced), so the screen can say why it was signed out; a logout, an expired or an unknown token stay unauthorized.
json
{
"error": {
"code": "unauthorized",
"message": "invalid or revoked API key"
}
}403 — Forbidden
The tenant is suspended. A dashboard session (ddu_) of a tenant whose login policy (ADR 227) is in mode enforce answers 403 with the code login_policy_denied on a request from an address or at an hour the policy does not allow — the same body for both; the session is not revoked and a later request inside the policy goes through. A widget token (ddw_) of a seat is held to the same policy on every request (core#2406, flag widget_login_honors_policy). A synthetic (demo) tenant answers 403 with the code synthetic_tenant on every route that would reach a third party — manual dial, external transfer or conference leg, SMS send (core#2251, ADR #280 addendum). No payment changes it.
json
{
"error": {
"code": "forbidden",
"message": "tenant is suspended"
}
}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"
}
}409 — Conflict
Invalid state transition, uniqueness conflict, or a seat that is busy/reserved.
json
{
"error": {
"code": "conflict",
"message": "invalid state transition"
}
}422 — Unprocessable
Shape is fine, semantics are not (broken domain rule).
json
{
"error": {
"code": "unprocessable",
"message": "scheduled_at is closer than the minimum notice for a callback (10 minutes unless the tenant's callback_min_notice_seconds says otherwise)"
}
}