Appearance
Debt segmentation: saved filters and list snapshots
Español: Segmentación de deuda.
Saved segmentation filters give a tenant a named, reusable set of debt criteria. They are useful when an integration needs to repeat the same portfolio selection without sending the criteria again or putting person-identifying search values in a saved object.
This guide separates the API that is in the latest published core release from the list-snapshot operations that are currently present only in core@main.
Contract used by this guide
The available API below comes from the OpenAPI document in core v0.94.0, the latest published release when this page was written. The list-snapshot section is marked separately because those operations are not in that release.
Before you start
All requests use the normal bearer authentication described in Authentication. The feature is tenant-scoped and is behind debt_segmentation_enabled, which is off by default.
When the flag is off, every /v1/segment-filters route returns 404 not_found, regardless of the caller. This is intentional: the disabled surface behaves as if it does not exist and does not read or write saved filters.
Reads are available to an authenticated caller in the tenant. Creating, editing, archiving, and materializing require tenant scope; an agent token receives 403 forbidden. An id that is malformed, missing, or belongs to another tenant returns the same 404 not_found, so the API does not disclose whether another tenant owns it.
Criteria
criteria is an object with a closed vocabulary. The fields are combined with AND; array values within one field act as alternatives. An empty object selects the whole portfolio.
| Field | Shape | Rules |
|---|---|---|
campaign_id | UUID string | Restricts the selection to one campaign. |
state | string or array | open, in_collection, promise_to_pay, paid, settled, disputed, or closed. Arrays contain 1–100 values. |
debt_type | string or array | other or student_loan. Arrays contain 1–100 values. |
us_state | string or array | Two uppercase letters. Arrays contain 1–100 values. |
min_amount_cents | integer | Inclusive lower bound; zero or greater. |
max_amount_cents | integer | Inclusive upper bound; zero or greater. |
Unknown fields and values outside the allowed shape return 400 bad_request. The keys phone, consumer_ref, external_ref, and debtor_name are explicitly refused. A saved segment describes a group by attributes; it is not a stored person lookup.
The server stores criteria in canonical form: array values are sorted and duplicates are removed.
Create a saved filter
POST /v1/segment-filters accepts name and criteria:
bash
curl -X POST "$DIALER_BASE_URL/v1/segment-filters" \
-H "Authorization: Bearer $DIALER_API_KEY" \
-H "Content-Type: application/json" \
--data '{
"name": "Texas student loans over 500 USD",
"criteria": {
"debt_type": ["student_loan"],
"us_state": ["TX"],
"min_amount_cents": 50000
}
}'A successful response is 201 with a segment_filter object. A newly created filter starts at version 1.
name is trimmed, cannot be blank, and has a maximum length of 200 characters. It must be unique among the tenant's non-archived filters. The tenant can hold up to 500 non-archived filters.
Read filters
Use GET /v1/segment-filters to list non-archived filters by name. Add ?include_archived=true to include archived filters. Each result contains its current version, and the response is capped at 2,000 filters.
Use GET /v1/segment-filters/{id} for one filter. This route can return an archived filter, with archived: true.
A segment_filter contains:
| Field | Meaning |
|---|---|
id | Filter UUID. |
tenant_id | Owning tenant UUID. |
name | Saved name. |
archived | Whether the filter has been archived. |
version | Current version number. |
criteria | Current criteria in canonical form. |
version_created_at | Creation time of the current version. |
created_at | Filter creation time. |
updated_at | Last header or version change. |
Update without overwriting another editor
PATCH /v1/segment-filters/{id} accepts at least one of name or criteria. When changing criteria, send the version you read as base_version:
bash
curl -X PATCH "$DIALER_BASE_URL/v1/segment-filters/$FILTER_ID" \
-H "Authorization: Bearer $DIALER_API_KEY" \
-H "Content-Type: application/json" \
--data '{
"base_version": 1,
"criteria": {"us_state": ["NY", "TX"]}
}'criteria replaces the current object; it is not merged with it. Changing criteria appends the next version and preserves earlier versions. Renaming changes only the filter header. An edit that changes nothing does not append a version.
If base_version is not current, the server returns 409 conflict and writes nothing. An archived filter also returns 409 conflict. A filter can hold up to 1,000 versions; reaching that limit returns 422 unprocessable.
Archive a filter
DELETE /v1/segment-filters/{id} returns 204 and archives the filter. It does not physically delete its versions. Archiving is idempotent, removes the filter from the default list, prevents later edits, and makes its former name available for a new filter.
Error handling
Errors use the standard envelope:
json
{
"error": {
"code": "bad_request",
"message": "..."
}
}Branch on error.code, not on the human-readable message.
| Status and code | When to expect it |
|---|---|
400 bad_request | Invalid body, unknown criterion, refused person lookup, or a value outside the criterion vocabulary. |
401 unauthorized | Missing, unknown, or revoked credential. |
403 forbidden | A write without tenant scope, or a suspended tenant. |
404 not_found | Feature flag off; unknown or malformed id; or an id hidden by tenant isolation. |
409 conflict | Duplicate live name, stale base_version, or an attempt to edit an archived filter. |
422 unprocessable | The live-filter or per-filter version limit has been reached. |
These failures are fail-closed: invalid criteria do not become an empty filter, a broader query, or a partial write.
Materialize a segment into a debt list
Available in the next version
The operations in this section are present in the OpenAPI document on core@main (0.95.0) but are absent from the latest published release, v0.94.0. Do not call them against the published release yet.
Materialization creates a snapshot: it adds the debts that match now to a normal debt list. The list does not follow later changes to the filter or portfolio. Membership in the list does not bypass dialing compliance checks.
Two operations are planned by the current core@main contract:
| Method | Path | Source |
|---|---|---|
POST | /v1/segment-filters/{id}/to-list | Latest version of a saved filter. |
POST | /v1/segment-filters/to-list | Inline criteria in the request body. |
Choose exactly one target:
list_id: add matches to an existing tenant list; success returns200.new_list_name: create a list and add matches in the same request; success returns201.
For the inline operation, also send criteria. Sending neither target or both targets returns 400 bad_request.
The response contains segment_materialization and debt_list. segment_materialization includes id, tenant_id, list_id, filter_id, filter_version, criteria, max_rows, matched, added, truncated, and requested_at. Inline criteria produce null for filter_id and filter_version.
The operation is idempotent for an existing (list_id, debt_id) membership: repeating it adds no duplicate member, while recording a separate evidence row. The tenant catalog cap limits the number written. When the cap cuts the result, the response reports truncated: true; it does not silently claim that the snapshot contains every match. A non-positive cap returns 422 unprocessable and writes nothing. A failing request does not leave an empty newly-created list.
The snapshot endpoints use the same 400, 401, 403, 404, 409, and 422 codes described above. In addition, an archived saved filter returns 409 conflict.
Operational checklist
- Confirm that
debt_segmentation_enabledis enabled for the tenant. - Create the filter and retain its
idandversion. - Use
base_versionon edits to avoid unnoticed overwrites. - Treat
404as intentionally ambiguous; do not use it to infer another tenant's data or whether the feature is enabled. - Once the snapshot operations appear in a published release, inspect
truncatedbefore treating a materialized list as the intended selection.