Case Management¶
Note
AI Context
Complexity: Medium
Cost: Free – case management has no per-operation charge.
Async: No. All
/service_agents/contact_cases*endpoints are synchronous.
A Case is a lightweight, per-channel session header that groups the interactions with a single remote party (a phone number, an email address, …) into a start/end unit an agent can pick up, work, and close. Where a Contact is a durable identity record and Interactions are the raw event log, a Case is the working unit an agent-facing console builds its queue/inbox UI around: “here is everything related to this customer’s current issue, and who owns it.”
With the Case API you can:
List and inspect the cases open for your customer
Assign a case to a specific agent, or close it once resolved
Attach or detach the case’s resolved Contact
Attach internal, agent-only notes that never leak into customer-facing webhooks or responses
Cases are created automatically by the platform (e.g. by a Flow action or an AI tool when a new call/conversation arrives for a peer with no open Case) – there is no POST /service_agents/contact_cases endpoint. The Agent Console surface only reads, assigns, annotates, and closes cases.
How Cases Work¶
Case Lifecycle
+------------------------------------------------------------------+
| Case Lifecycle |
+------------------------------------------------------------------+
New interaction arrives
for a peer with no open Case
|
v
+-------------+ assign +-------------+
| open |----------------->| open |
| (unowned) | | (owned by |
+------+------+ | agent) |
| +------+------+
| close | close
v v
+-------------+ +-------------+
| closed |<-----------------| closed |
+------+------+ +-------------+
|
| re-contact (new interaction for same peer)
v
+-------------+
| new open |
| Case, chained via previous_case_id
+-------------+
Status is either
openorclosed. Cases startopenand unowned.Owner (
owner_type/owner_id) identifies which agent is working the case. Assignment does not change status – an assigned case staysopenuntil explicitly closed.Closing a case is permanent for that Case instance; a subsequent interaction from the same peer creates a new Case with
previous_case_idpointing at the just-closed one, so the console can show re-contact history.The owner is never cleared by closing a case –
owner_idremains a durable record of who last worked it, even afterstatusbecomesclosed.
Endpoints¶
Method |
Path |
Description |
|---|---|---|
GET |
|
List cases for the caller’s customer (paginated, no server-side owner filter – filter client-side). |
GET |
|
Get a single case by ID. Any agent of the customer may view any case. |
PUT |
|
Attach (non-empty |
POST |
|
Assign the case to an owner agent ( |
POST |
|
Close the case. |
GET |
|
List notes on the case, in creation order. |
POST |
|
Create a note on the case, authored by the caller. |
DELETE |
|
Delete a note. Only the note’s own author may delete it. |
See Structures for the Case and CaseNote field reference.
Listing and Viewing Cases¶
List cases
$ curl -X GET 'https://api.voipbin.net/v1.0/service_agents/contact_cases?page_size=50&token=<token>'
Get a case
$ curl -X GET 'https://api.voipbin.net/v1.0/service_agents/contact_cases/<case-id>?token=<token>'
Note
AI Implementation Hint
GET /service_agents/contact_cases returns every open and closed case for the customer with no server-side status/owner_id filter – console UIs (e.g. an agent’s “My Cases” view) are expected to filter the result client-side. There is no status=open or owner_id=<my-agent-id> query parameter on this endpoint today.
Assigning and Closing¶
Assignment and closing are separate operations: assigning a case to an agent does not close it, and closing a case does not require it to have an owner.
Assign a case to an agent
$ curl -X POST 'https://api.voipbin.net/v1.0/service_agents/contact_cases/<case-id>/assign?token=<token>' \
--header 'Content-Type: application/json' \
--data '{
"owner_id": "<agent-id>"
}'
owner_id must reference an existing agent of the same customer as the caller. A cross-tenant or nonexistent agent ID and a nonexistent case ID both return the same 404 – the API deliberately does not reveal which one failed.
Close a case
$ curl -X POST 'https://api.voipbin.net/v1.0/service_agents/contact_cases/<case-id>/close?token=<token>'
closed_by_type/closed_by_id are always derived from the caller’s own authenticated agent identity – the request body carries no fields, so a case can never be closed “as” another agent.
Attach or detach the case’s Contact
$ curl -X PUT 'https://api.voipbin.net/v1.0/service_agents/contact_cases/<case-id>?token=<token>' \
--header 'Content-Type: application/json' \
--data '{
"contact_id": "<contact-id>"
}'
Send an empty string for contact_id to detach:
$ curl -X PUT 'https://api.voipbin.net/v1.0/service_agents/contact_cases/<case-id>?token=<token>' \
--header 'Content-Type: application/json' \
--data '{
"contact_id": ""
}'
Every attach/detach is recorded as a case_contact_attributed/case_contact_detached audit event, queryable via bin-timeline-manager.
Case Notes¶
Notes are an internal, agent-facing annotation on a Case – free-text scratchpad entries like “called back, no answer” that help agents hand a case off to each other. Notes are physically and transport-isolated from customer-facing data: they never appear in any customer webhook, in GET /contact_cases (the admin/manager surface), or in any other customer-visible response.
List notes
$ curl -X GET 'https://api.voipbin.net/v1.0/service_agents/contact_cases/<case-id>/notes?token=<token>'
Create a note
$ curl -X POST 'https://api.voipbin.net/v1.0/service_agents/contact_cases/<case-id>/notes?token=<token>' \
--header 'Content-Type: application/json' \
--data '{
"text": "Called the customer back, no answer."
}'
The note’s author_type/author_id are always derived server-side from the caller’s authenticated agent identity – there is no way to author a note as another agent or as the system through this endpoint.
Delete a note
$ curl -X DELETE 'https://api.voipbin.net/v1.0/service_agents/contact_cases/<case-id>/notes/<note-id>?token=<token>'
Note
AI Implementation Hint
An agent may only delete a note it authored itself. Attempting to delete a note authored by another agent, or a system-authored note (author_id is null), returns 403 PermissionDenied – not 404, so the caller can distinguish “not my note” from “note doesn’t exist”.
Relationship to the Admin/Manager Case API¶
The same underlying Case resource is also exposed at the top level (/contact_cases, gated by admin/manager permission) – see Case Overview. That surface additionally supports POST /contact_cases/{id}/continue (reopen a closed case) and sending an outbound conversation message tied to the case, neither of which exists under /service_agents/contact_cases. Conversely, POST /service_agents/contact_cases/{id}/assign (owner assignment) exists only on this Agent Console surface – there is no top-level equivalent.