Account tasks in Billabex represent action items that require human input or approval. They are created exclusively by the Billabex AI agent when it needs user guidance, contact information, or explicit approval to proceed with dunning activities on a specific account.
This guide covers how to interact with account tasks via the API: listing, retrieving, canceling, and responding with interactions.
Overview
Account tasks follow a simple lifecycle:
- Created - The Billabex agent creates an account task when user input is required
- Open - The task awaits user input
- Interaction - A user responds via an interaction message
- Closed/Canceled - The task is resolved by the agent or canceled by the user
Each account task has a type that determines what kind of response is expected.
Note: Account tasks can only be created by the Billabex agent. The public API allows you to read tasks, respond to them, and cancel them - but not create new ones.
Account Task Types
| Type | Description | Expected Response |
|---|---|---|
ApproveEligibility |
Approve or reject a contact for dunning | Structured: boolean |
NeedContacts |
Provide contact details for an account | Structured: contact object |
AskNextAction |
Free-form question from the agent | Text message |
NeedUserInput |
Agent needs clarification or information | Text message |
Unknown |
Fallback task type | Structured: boolean |
Notice |
The agent reports something it already did; nothing is expected back | None |
extraData.idempotencyKey
Task types that carry no structured payload of their own (Notice, AskNextAction,
NeedContacts, ApproveFirstOutreach, Unknown) expose extraData.idempotencyKey. It is a stable
key the agent sets when several tasks of the same type may legitimately coexist on one account, and
it is null otherwise. It does not change when the task is replayed, so use it to reconcile a task
you have already seen. A Notice about a customer complaint, for instance, is keyed
contact-grievance:<incoming email id>.
Required Scopes
| Scope | Access Level | Endpoints |
|---|---|---|
tasks:read |
Read-only | GET /account-tasks, GET /account-tasks/search, GET /account-tasks/:accountTaskId |
tasks:all |
Full access | All read + POST /account-tasks/:accountTaskId/cancel, add interactions |
List Active Account Tasks
Retrieve active account tasks for a specific account.
GET [baseURL]/api/public/v1/account-tasks?accountId=ACCOUNT_ID
Authorization: Bearer YOUR_ACCESS_TOKEN
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
accountId |
UUID | Yes | Filter account tasks by account |
type |
string | No | Filter by account task type (optional) |
Example response:
[
{
"task": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"organizationId": "org-uuid",
"accountId": "account-uuid",
"type": "NeedUserInput",
"title": "Clarification needed on invoice #1234",
"status": "UserActionRequired",
"isActive": true,
"isClosed": false,
"isCanceled": false,
"thread": [
{
"id": "interaction-uuid",
"message": {
"type": "Text",
"value": "The customer mentioned a dispute. How should I proceed?"
},
"attachments": [],
"sentAt": "2024-05-01T10:15:30.000Z",
"agent": {
"email": "agent@billabex.com",
"firstName": "Alex",
"lastName": "Martin"
}
}
],
"assignees": [],
"createdAt": "2024-05-01T10:15:30.000Z",
"closedAt": null,
"canceledAt": null,
"cancelReason": null,
"completedAt": null,
"isPending": false,
"pendingAt": null,
"extraData": { "refEmailMessageIds": [] }
}
}
]
Search Account Tasks
GET /account-tasks answers a single account and returns its active tasks in
one shot. To work across the whole organization, with filters, sorting and
pagination, use the search endpoint.
GET [baseURL]/api/public/v1/account-tasks/search?organizationId=ORG_ID&first=20
Authorization: Bearer YOUR_ACCESS_TOKEN
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
organizationId |
UUID | Yes | Organization to search in |
accountId |
UUID | No | Restrict to a single account |
query |
string | No | Free text search on the task title and the account name |
filters |
string | No | Filter conditions, see Pagination & Filtering |
sortBy |
string | No | createdAt, updatedAt, title, accountFullName, status or balance |
sortOrder |
string | No | asc or desc |
first |
integer | No | Between 1 and 100 |
after |
string | No | Cursor from pageInfo.endCursor |
Filterable fields:
| Field | Operators |
|---|---|
title |
contains, startsWith, equals |
accountName |
contains, startsWith, equals |
status |
is, isNot, isAnyOf |
type |
is, isNot, isAnyOf |
tags |
containsAny, containsAll, containsNone, isEmpty, isNotEmpty |
balance |
equals, greaterThan, lessThan, between, isEmpty, isNotEmpty |
createdAt |
on, before, after, between |
updatedAt |
on, before, after, between, isEmpty, isNotEmpty |
type accepts ApproveEligibility, ApproveContactChange,
ApprovePaymentArrangement, ApproveFirstOutreach, NeedContacts,
AskNextAction, NeedUserInput, PaymentScheduleInvalidated, Notice and
Unknown. status accepts the values of the table further down this page.
Open tasks of a given type, most recent first:
GET [baseURL]/api/public/v1/account-tasks/search?organizationId=ORG_ID&filters=status%3Ais%3AUserActionRequired%3Btype%3Ais%3ANeedContacts&sortBy=createdAt&sortOrder=desc
Tasks created since the start of the quarter, on accounts owing more than 1000:
GET [baseURL]/api/public/v1/account-tasks/search?organizationId=ORG_ID&filters=createdAt%3Aafter%3A2026-06-30%3Bbalance%3AgreaterThan%3A1000
Example response:
{
"nodes": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"organizationId": "org-uuid",
"accountId": "account-uuid",
"accountFullName": "Acme Corporation",
"accountTagIds": [],
"title": "Clarification needed on invoice #1234",
"type": "NeedUserInput",
"status": "UserActionRequired",
"assignees": [],
"assigneesFullName": [],
"isActive": true,
"isClosed": false,
"isCanceled": false,
"isPending": false,
"balance": 1250.5,
"currency": "EUR",
"createdAt": "2026-05-01T10:15:30.000Z",
"updatedAt": "2026-05-02T08:00:00.000Z",
"closedAt": null,
"canceledAt": null,
"cancelReason": null,
"pendingAt": null,
"completedAt": null,
"lastAgentInteractionAt": "2026-05-01T10:15:30.000Z"
}
],
"pageInfo": {
"endCursor": "v2:8f14e45fceea:2"
}
}
Two things to keep in mind:
- Items do not carry the interaction
thread. CallGET /account-tasks/:accountTaskIdfor the thread of a task. - The
endCursorbelongs to the filters and the sort it was issued for. Changing either one invalidates it, and the call returns400with the codeLIST_CURSOR_INVALID.
Get an Account Task
Retrieve a single account task by ID.
GET [baseURL]/api/public/v1/account-tasks/:accountTaskId
Authorization: Bearer YOUR_ACCESS_TOKEN
Returns the same structure as above, wrapped in { "task": { ... } }.
Cancel an Account Task
Cancel an active account task. This marks the task as canceled without resolving it.
POST [baseURL]/api/public/v1/account-tasks/:accountTaskId/cancel
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
{
"reason": "Invoice re-sent by hand, the contact confirmed reception."
}
The body is optional, and so is reason (2000 characters at most). Sending one
is strongly recommended: cancelling is the only ending that answers nothing, and
several task types hold the automatic follow-ups back while they are active, so
cancelling one hands the cadence back to the agent. The reason is shown next to
the cancellation and is read back by the agent before it reopens the same
subject on that account.
Returns the updated account task with isCanceled: true, canceledAt set, and
cancelReason carrying the reason when one was given.
Add an Interaction
Respond to an account task by adding a user interaction. This is how users provide the requested input to the Billabex agent.
POST [baseURL]/api/public/v1/account-tasks/:accountTaskId/interactions
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
Text Interaction
For NeedUserInput and AskNextAction account tasks:
{
"interaction": {
"message": {
"type": "Text",
"value": "Please offer a 3-month payment plan with 10% interest."
},
"attachments": []
}
}
Structured Interaction
For ApproveEligibility, NeedContacts, and Unknown account tasks, use structured messages.
ApproveEligibility Response
{
"interaction": {
"message": {
"type": "Structured",
"schema": "ApproveEligibility",
"schemaVersion": 1,
"value": true
}
}
}
The value is a boolean: true to approve, false to reject.
NeedContacts Response
{
"interaction": {
"message": {
"type": "Structured",
"schema": "NeedContacts",
"schemaVersion": 1,
"value": {
"fullName": "Jane Doe",
"email": "jane@company.com",
"language": "en"
}
}
}
}
Required fields in value:
fullName(string)email(string)language(string, e.g., “en”, “fr”)
Unknown Response
{
"interaction": {
"message": {
"type": "Structured",
"schema": "Unknown",
"schemaVersion": 1,
"value": true
}
}
}
Message Schema Reference
| Account Task Type | Schema Name | Version | Value Type |
|---|---|---|---|
ApproveEligibility |
ApproveEligibility |
1 | boolean |
NeedContacts |
NeedContacts |
1 | { fullName, email, language } |
Unknown |
Unknown |
1 | boolean |
AskNextAction |
N/A | N/A | Text message only |
NeedUserInput |
N/A | N/A | Text message only |
Validation Rules
The API enforces strict validation on interaction messages:
- Text account tasks (
NeedUserInput,AskNextAction) must receivetype: "Text"messages - Structured account tasks must receive
type: "Structured"messages with matching schema - Schema name and version must match exactly
- Value must conform to the expected type for that schema
Invalid messages return a 400 Bad Request with details.
Account Task Status Values
| Status | Description |
|---|---|
Open |
Task created, awaiting processing |
InProgress |
Agent is working on it |
UserActionRequired |
Waiting for user input |
Closed |
Task completed successfully |
Canceled |
Task was canceled |
Pending |
Task is paused |
Common Errors
400 Bad Request - Invalid Message
{
"statusCode": 400,
"message": "Text message is required for this task type"
}
Cause: Sending a structured message to a text-only account task type.
404 Not Found - Account Task Not Found
{
"statusCode": 404,
"message": "Account task 123e4567-e89b-12d3-a456-426614174000 not found"
}
Cause: The account task ID does not exist or belongs to another organization.
403 Forbidden - Insufficient Scope
{
"statusCode": 403,
"message": "Forbidden",
"error": "insufficient_scope"
}
Cause: Your token lacks tasks:all for write operations.
Next Steps
- Getting Started - Integration quick start
- OAuth Scopes - Required permissions
- Pagination & Filtering - Cursors and the
filtersparameter - Rate Limiting - Avoid hitting limits
- API Reference - Full endpoint documentation
Support
Questions about account tasks and interactions?
Contact us via the website contact form.