Tasks

Create and manage tasks with assignment, priority, reminders, and status tracking. Tasks can reference contacts, media, calendar events, and messages.

All endpoints require authentication via the X-API-Key header. See Authentication.

Notifications

Task operations trigger notifications to relevant users (via push, SMS, and email based on user preferences):

  • Create: All assigned users are notified.
  • Status → in-review: The task creator is notified.
  • Reassignment: Only newly assigned users are notified (existing assignees are not re-notified).

Reminders

Tasks support deadline reminders via GCP Cloud Tasks. Set reminderSeconds to the number of seconds before the deliveryBy deadline to fire a reminder. The reminder is scheduled at deliveryBy - (reminderSeconds * 1000). Set reminderSeconds to 0 for no reminder. Updating reminderSeconds cancels the old reminder and schedules a new one.


Create a task

POST /tasks

Status is automatically set to pending. Sends notifications to all assigned users and schedules a reminder if reminderSeconds > 0.

Request body

FieldTypeRequiredNotes
typestringYesOne of: video-request, follow-up-call, message-request, custom.
namestringYesTask name.
descriptionstringYesTask description.
prioritystringYesOne of: highest, high, medium, low.
assignedTostring[]YesArray of user IDs. Minimum 1.
createdBystringYesUser ID of the creator.
deliveryBynumberYesDeadline as Unix timestamp in milliseconds.
reminderSecondsnumberYesSeconds before deadline to send reminder. 0 for no reminder.
contactIdstringNoAssociated contact ID.
mediaIdstringNoAssociated media ID.
eventIdstringNoAssociated calendar event ID.
messageIdstringNoAssociated message ID.
notesstringNoAdditional notes.

Example request

curl -X POST https://<host>/api/tasks \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "follow-up-call",
    "name": "Call recruit",
    "description": "Follow up on campus visit",
    "priority": "high",
    "assignedTo": ["665a..."],
    "createdBy": "665b...",
    "deliveryBy": 1716100000000,
    "reminderSeconds": 3600,
    "contactId": "664a..."
  }'

Response

{
  "error": false,
  "success": true,
  "message": "Success",
  "data": {
    "_id": "674a...",
    "orgId": "...",
    "type": "follow-up-call",
    "name": "Call recruit",
    "description": "Follow up on campus visit",
    "priority": "high",
    "status": "pending",
    "assignedTo": ["665a..."],
    "createdBy": "665b...",
    "deliveryBy": 1716100000000,
    "reminderSeconds": 3600,
    "contactId": "664a...",
    "createdAt": 1716000000000,
    "updatedAt": 1716000000000
  }
}

Errors

StatusMessageCause
400Validation errorMissing or invalid fields.

List tasks

GET /tasks

List tasks with filtering. Uses offset-based pagination. When filtering by pending status only, results are sorted by deliveryBy ascending (due date order). Otherwise, sorted by createdAt descending.

Query parameters

ParameterTypeDefaultNotes
pagenumber00-indexed.
perPagenumber50Items per page.
statusstring | string[]—Filter by status: pending, in-review, completed, rejected.
assignedTostring | string[]—Filter by assigned user ID(s).
contactIdstring—Filter by associated contact.
prioritystring—Filter by priority level.
typestring—Filter by task type.
startDatenumber—Lower bound on deliveryBy (inclusive).
endDatenumber—Upper bound on deliveryBy (inclusive).

Example request

curl "https://<host>/api/tasks?status=pending&assignedTo=665a...&perPage=25" \
  -H "X-API-Key: your-api-key"

Response

{
  "success": true,
  "data": [
    {
      "_id": "674a...",
      "type": "follow-up-call",
      "name": "Call recruit",
      "priority": "high",
      "status": "pending",
      "assignedTo": ["665a..."],
      "assignedTo_": [
        { "_id": "665a...", "firstName": "John", "lastName": "Doe" }
      ],
      "createdBy": "665b...",
      "deliveryBy": 1716100000000,
      "contact": { "_id": "664a...", "firstName": "Jane", "lastName": "Smith" },
      "media": null,
      "createdAt": 1716000000000
    }
  ],
  "pagination": {
    "page": 0,
    "perPage": 25,
    "totalItems": 12,
    "totalPages": 1
  }
}

Get my tasks

GET /tasks/my

Returns all tasks assigned to the authenticated user with status pending or in-review. No pagination — returns all matching tasks.

Example request

curl https://<host>/api/tasks/my \
  -H "X-API-Key: your-api-key"

Response

{
  "success": true,
  "data": [
    {
      "_id": "674a...",
      "type": "follow-up-call",
      "name": "Call recruit",
      "priority": "high",
      "status": "pending",
      "assignedTo": ["665a..."],
      "assignedTo_": [
        { "_id": "665a...", "firstName": "John", "lastName": "Doe" }
      ],
      "deliveryBy": 1716100000000,
      "contact": { "_id": "664a...", "firstName": "Jane", "lastName": "Smith" },
      "media": null
    }
  ]
}

Get a task

GET /tasks/:id

Returns a single task with all populated relations (assigned users, contact, media). If the task has a messageId, the full message object is also populated.

Path parameters

ParameterTypeDescription
idstringTask ID.

Example request

curl https://<host>/api/tasks/674a... \
  -H "X-API-Key: your-api-key"

Response

{
  "success": true,
  "data": {
    "_id": "674a...",
    "type": "follow-up-call",
    "name": "Call recruit",
    "description": "Follow up on campus visit",
    "priority": "high",
    "status": "pending",
    "assignedTo": ["665a..."],
    "assignedTo_": [
      { "_id": "665a...", "firstName": "John", "lastName": "Doe" }
    ],
    "createdBy": "665b...",
    "deliveryBy": 1716100000000,
    "reminderSeconds": 3600,
    "contactId": "664a...",
    "contact": { "_id": "664a...", "firstName": "Jane", "lastName": "Smith" },
    "media": null,
    "message": null
  }
}

Errors

StatusMessageCause
500Invalid task IDInvalid ObjectId format or task not found.

Update a task

PUT /tasks/:id

All fields are optional. Changing status to in-review notifies the task creator. Changing assignedTo notifies only newly assigned users. Changing reminderSeconds cancels the old reminder and schedules a new one.

Path parameters

ParameterTypeDescription
idstringTask ID.

Request body

FieldTypeRequiredNotes
typestringNo
namestringNo
descriptionstringNo
prioritystringNo
statusstringNoOne of: pending, in-review, completed, rejected.
assignedTostring[]No
deliveryBynumberNo
reminderSecondsnumberNo
contactIdstring | nullNo
mediaIdstring | nullNo
eventIdstring | nullNo
messageIdstring | nullNo
notesstring | nullNo

Example request

curl -X PUT https://<host>/api/tasks/674a... \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{ "status": "in-review", "notes": "Called and left voicemail" }'

Response

{
  "success": true,
  "message": "Success",
  "data": {
    "_id": "674a...",
    "status": "in-review",
    "notes": "Called and left voicemail",
    "updatedAt": 1716050000000
  }
}

Errors

StatusMessageCause
400Validation errorInvalid fields or invalid mediaId format.
500Invalid task IDInvalid ObjectId format.

Delete a task

DELETE /tasks/:id

Deletes a task and cancels any scheduled reminder.

Path parameters

ParameterTypeDescription
idstringTask ID.

Example request

curl -X DELETE https://<host>/api/tasks/674a... \
  -H "X-API-Key: your-api-key"

Response

{
  "success": true,
  "message": "Success",
  "data": null
}

Errors

StatusMessageCause
400Task not foundNo task with that ID, or deletion failed.
500Invalid task IDInvalid ObjectId format.

Response envelope

All endpoints use the standard envelope:

{
  "error": false,
  "success": true,
  "message": "...",
  "code": 200,
  "data": "...",
  "pagination": {}
}

Error responses:

{
  "error": true,
  "success": false,
  "message": "...",
  "code": 400,
  "data": null
}

data is null for a general failure, such as a database error or an upstream timeout. When the request is rejected because of a specific field, data carries the field(s) at fault instead:

{
  "error": true,
  "success": false,
  "message": "phone: Phone parse failed: The string supplied did not seem to be a phone number (input: <masked>)",
  "code": 400,
  "data": {
    "issues": [
      {
        "path": "phone",
        "message": "Phone parse failed: The string supplied did not seem to be a phone number (input: <masked>)"
      }
    ]
  }
}

Each issue carries a path (the dotted path into the request body) and a message. A label is added when the path is not self-describing, which today means custom fields only, for example "path": "fields.68b0a1f39c2e4d0012ab77e5", "label": "Class Year". issues is an array, but treat it as holding at most one entry: validation stops at the first failure.

On this page