Skip to content

Follow-up feed: every attempt this tenant owns, across campaigns

GET
/v1/contact-attempts
curl --request GET \
--url 'https://api.vocapable.com/v1/contact-attempts?limit=50' \
--header 'Authorization: Bearer <token>'

The board an operator works the morning after, and the only place callbacks surface.

Every attempt this tenant owns - campaign-backed and campaign-less alike - filterable on next_eligible_at, which is what makes “who is due before noon” a range query instead of a scan: ?state=scheduled&next_eligible_at.lte=2026-08-11T17:00:00Z.

It reports scheduling facts, not promises. scheduled_for is the earliest instant the window layers allowed when the row was written; every attempt is re-gated at dial time and one listed here can still be refused then (docs/07-compliance.md).

limit
Limit
integer
default: 50 >= 1 <= 200
cursor
Any of:
string
campaign_id
Any of:
string

Filter on campaign_id. Comma-separated values are OR.

campaign_id.gte
Any of:
string

Filter on campaign_id with the gte operator.

campaign_id.lte
Any of:
string

Filter on campaign_id with the lte operator.

campaign_id.gt
Any of:
string

Filter on campaign_id with the gt operator.

campaign_id.lt
Any of:
string

Filter on campaign_id with the lt operator.

campaign_id.in
Any of:
string

Filter on campaign_id with the in operator.

contact_id
Any of:
string

Filter on contact_id. Comma-separated values are OR.

contact_id.gte
Any of:
string

Filter on contact_id with the gte operator.

contact_id.lte
Any of:
string

Filter on contact_id with the lte operator.

contact_id.gt
Any of:
string

Filter on contact_id with the gt operator.

contact_id.lt
Any of:
string

Filter on contact_id with the lt operator.

contact_id.in
Any of:
string

Filter on contact_id with the in operator.

disposition
Any of:
string

Filter on disposition. Comma-separated values are OR.

disposition.gte
Any of:
string

Filter on disposition with the gte operator.

disposition.lte
Any of:
string

Filter on disposition with the lte operator.

disposition.gt
Any of:
string

Filter on disposition with the gt operator.

disposition.lt
Any of:
string

Filter on disposition with the lt operator.

disposition.in
Any of:
string

Filter on disposition with the in operator.

next_eligible_at
Any of:
string

Filter on next_eligible_at. Comma-separated values are OR.

next_eligible_at.gte
Any of:
string

Filter on next_eligible_at with the gte operator.

next_eligible_at.lte
Any of:
string

Filter on next_eligible_at with the lte operator.

next_eligible_at.gt
Any of:
string

Filter on next_eligible_at with the gt operator.

next_eligible_at.lt
Any of:
string

Filter on next_eligible_at with the lt operator.

next_eligible_at.in
Any of:
string

Filter on next_eligible_at with the in operator.

origin_kind
Any of:
string

Filter on origin_kind. Comma-separated values are OR.

origin_kind.gte
Any of:
string

Filter on origin_kind with the gte operator.

origin_kind.lte
Any of:
string

Filter on origin_kind with the lte operator.

origin_kind.gt
Any of:
string

Filter on origin_kind with the gt operator.

origin_kind.lt
Any of:
string

Filter on origin_kind with the lt operator.

origin_kind.in
Any of:
string

Filter on origin_kind with the in operator.

state
Any of:
string

Filter on state. Comma-separated values are OR.

state.gte
Any of:
string

Filter on state with the gte operator.

state.lte
Any of:
string

Filter on state with the lte operator.

state.gt
Any of:
string

Filter on state with the gt operator.

state.lt
Any of:
string

Filter on state with the lt operator.

state.in
Any of:
string

Filter on state with the in operator.

updated_at
Any of:
string

Filter on updated_at. Comma-separated values are OR.

updated_at.gte
Any of:
string

Filter on updated_at with the gte operator.

updated_at.lte
Any of:
string

Filter on updated_at with the lte operator.

updated_at.gt
Any of:
string

Filter on updated_at with the gt operator.

updated_at.lt
Any of:
string

Filter on updated_at with the lt operator.

updated_at.in
Any of:
string

Filter on updated_at with the in operator.

Successful Response

Media typeapplication/json
CursorPage[ContactAttemptSummary]
object
data
required
Data
Array<object>
ContactAttemptSummary

One attempt on the tenant-wide feed (GET /v1/contact-attempts).

The follow-up board. scheduled_for is the attempt’s next_eligible_at - the earliest instant every window layer allows, which is what makes “who is due today” a server-side range filter rather than a client-side scan.

It states scheduling facts and nothing more. An attempt appearing here is not a promise that the dial will be placed: every attempt is re-gated at dial time, and one listed as due can still be refused then (docs/07-compliance.md).

object
id
required
Id
string
contact_id
required
Contact Id
string
contact_phone
required
Contact Phone
string
attempt_number
required
Attempt Number
integer
state
required
AttemptState
string
Allowed values: pending scrubbed scheduled dialing answered in_conversation completed machine no_answer busy failed disposed
disposition
Any of:
Disposition

Terminal outcome of a contact attempt (docs/06-campaign-engine.md).

string
Allowed values: completed_goal completed_no_goal answered_incomplete voicemail_machine no_answer busy failed opt_out wrong_person_opt_out dnc_hit scrub_blocked blocked_by_policy abandoned_no_slot inbound_unavailable browser_unavailable
sub_code
Any of:
string
failure_reason
Any of:
FailureReason

Why an attempt failed. Exactly four values (CANON fact 64).

Machine detection is not here - it lands the attempt in the machine state. A missing conversation slot is not here either - that is the abandoned_no_slot disposition.

string
Allowed values: wss_dropped carrier_block bootstrap_timeout provider_error
call_id
Any of:
string
scheduled_for
Any of:
string format: date-time
dialed_at
Any of:
string format: date-time
ended_at
Any of:
string format: date-time
updated_at
required
Updated At
string format: date-time
campaign_id
Any of:
string
contact_first_name
Any of:
string
contact_last_name
Any of:
string
origin_kind
Any of:
string
callback_reason
Any of:
string
next_cursor
Any of:
string
has_more
Has More
boolean
Example
{
"data": [
{
"state": "pending",
"disposition": "completed_goal",
"failure_reason": "wss_dropped"
}
],
"has_more": false
}

Validation Error

Media typeapplication/json
HTTPValidationError
object
detail
Detail
Array<object>
ValidationError
object
loc
required
Location
Array
msg
required
Message
string
type
required
Error Type
string
input
Input
ctx
Context
object
Examplegenerated
{
"detail": [
{
"loc": [
"example"
],
"msg": "example",
"type": "example",
"input": "example",
"ctx": {}
}
]
}