Tickets Please Developers
Public API · Version 1

Build support workflows without guesswork.

Create and manage tickets, sync contacts, and connect outreach workflows with an organization-scoped JSON API.

Base URL
https://tickets-please.xodelabs.com/api/v1

HTTPS is required in production. Requests and responses use JSON unless an endpoint says otherwise.

01

Quick start

Make an authenticated request

Use an existing Tickets Please user. Their token inherits their organization and service access, so API data stays in the same workspace as the browser application.

1
Request a token

Exchange the user’s sign-in email and password once.

2
Store it safely

Treat the token like a password and keep it server-side.

3
Send the header

Prefix the token with Token on every API call.

1. Get a token
curl --request POST \
  --url https://tickets-please.xodelabs.com/api-token-auth/ \
  --header 'Content-Type: application/json' \
  --data '{
    "username": "developer@example.com",
    "password": "your-password"
  }'
200 OK{ "token": "YOUR_API_TOKEN" }
2. List tickets
curl --request GET \
  --url 'https://tickets-please.xodelabs.com/api/v1/helpdesk/tickets/?priority=high' \
  --header 'Authorization: Token YOUR_API_TOKEN'
02

Security

Authentication

Token header

Every business endpoint requires Django REST Framework token authentication. Send this exact header, including the word Token and one space:

Authorization: Token YOUR_API_TOKEN
Protect customer data

Never expose a token in client-side JavaScript, URLs, logs, screenshots, or source control. Use a dedicated integration user where practical.

POST/api-token-auth/Create or retrieve a token

This is the only endpoint that does not require a token. The username value is the email address used to log in.

FieldTypeRequiredDescription
usernameemailYesTickets Please sign-in email.
passwordstringYesThe user’s current password.
03

Predictable behavior

Conventions and errors

Organization scoped

A token sees only records belonging to its user’s organization. Cross-organization UUIDs return not found.

JSON by default

Send application/json. Source-list upload is the one multipart/form-data endpoint.

ISO 8601 dates

Timestamps are returned as timezone-aware ISO 8601 strings. Empty related values are null.

Arrays are unpaginated

Ticket and lead list endpoints currently return a plain JSON array, not a pagination envelope.

Copy paths exactly

Collection paths end with /. Ticket and lead detail paths, and /api/v1/crm/contacts/contact, do not.

StatusMeaningWhat to do
200 / 201SuccessRead the JSON body. A successful assignment returns an empty body.
204DeletedSuccess; there is no response body.
400Invalid requestRead the field names and messages in the response body.
401UnauthenticatedCheck the token and the exact authorization-header format.
403Access deniedCheck the user, organization subscription, and operation permissions.
404Not foundCheck the UUID and that the record belongs to the token’s organization.
04

Complete surface

Endpoint index

Helpdesk

Tickets

List, filter, create, retrieve, update, and delete customer requests.
GET/api/v1/helpdesk/tickets/List tickets

Returns the organization’s tickets as a newest-first JSON array. Filters may be combined.

Query parameters

ParameterMatchExample
stateExact state nameOpen
priorityExact value: low, medium, or highhigh
contact_emailCase-insensitive exact emailada@example.com
Example
curl 'https://tickets-please.xodelabs.com/api/v1/helpdesk/tickets/?state=Open&priority=high' \
  --header 'Authorization: Token YOUR_API_TOKEN'
POST/api/v1/helpdesk/tickets/Create a ticket

Either description or its legacy alias message is required. If contact details are supplied and the email is new, a contact is created automatically.

Minimal useful request
curl --request POST \
  --url https://tickets-please.xodelabs.com/api/v1/helpdesk/tickets/ \
  --header 'Authorization: Token YOUR_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "subject": "Unable to access the billing portal",
    "description": "The customer sees a blank page after signing in.",
    "priority": "high",
    "contact_first_name": "Ada",
    "contact_last_name": "Lovelace",
    "contact_email": "ada@example.com"
  }'

Request fields

FieldTypeRequiredBehavior
description or messagestringYes on createTicket body. Prefer description.
subjectstringNoDefaults to “Website contact form request”. Maximum 256 characters.
priorityenumNolow, medium, or high; defaults to medium.
statestringNoDefaults to the organization’s default ticket state.
company_uidUUID or nullNoMust belong to the same organization.
contact_uidUUID or nullNoUses an existing organization contact.
contact_first_name, contact_last_namestringNoUsed when creating a contact from contact_email.
contact_emailemailNoReuses an existing matching contact or creates one.
contact_numberstringNoMaximum 50 characters.
department_id, category_idinteger or nullNoTenant-local configuration IDs.
assigned_to_idinteger or nullNoUser ID; the user must belong to the organization.
resolution_idinteger or nullNoTenant-local resolution ID.
GET/api/v1/helpdesk/tickets/{ticket_uid}Retrieve a ticket

Returns the ticket when its public UUID belongs to the token’s organization. There is no trailing slash.

Response shape
{
  "uid": "120e62c0-a891-4a20-a26b-424a5e4830aa",
  "id": 42,
  "ticket_number": 100042,
  "subject": "Unable to access the billing portal",
  "description": "The customer sees a blank page after signing in.",
  "state": "Open",
  "priority": "high",
  "company_uid": null,
  "contact_uid": "7f93b8a0-5f5b-4b8d-89cf-6a3380a68220",
  "contact_name": "Ada",
  "contact_surname": "Lovelace",
  "contact_email": "ada@example.com",
  "assigned_to_id": null,
  "department_id": null,
  "category_id": null,
  "resolution_id": null,
  "created_at": "2026-08-28T09:15:00Z",
  "last_modified_at": null,
  "closed_at": null
}
PATCH/api/v1/helpdesk/tickets/{ticket_uid}Update selected fields

Send only the fields that should change. The fields accepted by create are also accepted by update; send null to clear a supported related record.

Example
curl --request PATCH \
  --url https://tickets-please.xodelabs.com/api/v1/helpdesk/tickets/TICKET_UUID \
  --header 'Authorization: Token YOUR_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{"priority": "medium", "subject": "Billing portal access restored"}'
DELETE/api/v1/helpdesk/tickets/{ticket_uid}Delete a ticket
Platform superusers only

Organization admins are not sufficient for this operation. A successful deletion returns 204 No Content.

CRM

Contacts

Create customer records that can be attached to tickets.
POST/api/v1/crm/contacts/contactCreate a contact

All four fields are required. The response repeats them and adds the contact’s public uid.

Example
curl --request POST \
  --url https://tickets-please.xodelabs.com/api/v1/crm/contacts/contact \
  --header 'Authorization: Token YOUR_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Ada",
    "surname": "Lovelace",
    "email": "ada@example.com",
    "contact_number": "+27 10 555 0123"
  }'
FieldTypeLimit
namestring128 characters
surnamestring128 characters
emailemailValid email address
contact_numberstring50 characters

Outreach

Leads

Create simple prospects and manage them by public UUID.
GET/api/v1/leads/List leads

Returns an unpaginated array of the organization’s full lead records. The response includes profile fields, stage, timestamps, counters, and related database IDs where present.

POST/api/v1/leads/Create a lead

name, surname, and phone_number are required. A new lead starts in the new stage.

Example
curl --request POST \
  --url https://tickets-please.xodelabs.com/api/v1/leads/ \
  --header 'Authorization: Token YOUR_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Grace",
    "surname": "Hopper",
    "phone_number": "+27 10 555 0199"
  }'
201 Created{ "uid": "…", "name": "Grace", "surname": "Hopper", "phone_number": "+27 10 555 0199" }
GET/api/v1/leads/{lead_uid}Retrieve a lead

Returns the full lead record. There is no trailing slash after the UUID.

PATCH/api/v1/leads/{lead_uid}Update a lead

Partially updates name, surname, or phone_number. Other lead fields cannot currently be changed through this endpoint.

DELETE/api/v1/leads/{lead_uid}Delete a lead

Deletes a lead in the token’s organization and returns 204 No Content. Unlike ticket deletion, this operation does not require a platform superuser.

Outreach

Source lists

Import many leads from a CSV file.
POST/api/v1/source-lists/Import a CSV source list

Send multipart/form-data with a list name and CSV file. Rows missing a first name, surname, or phone number are skipped.

Example
curl --request POST \
  --url https://tickets-please.xodelabs.com/api/v1/source-lists/ \
  --header 'Authorization: Token YOUR_API_TOKEN' \
  --form 'name=August prospects' \
  --form 'file=@prospects.csv;type=text/csv'

CSV columns

DataAccepted headersRequired per row
First namename, first_nameYes
Surnamesurname, last_nameYes
Phonephone_number, phone, mobile, contact_numberYes
Emailemail, email_addressNo
Companycompany_name, company, account_nameNo
Addressstreet_number, street_name or address, suburb, city, postal_code or postcode or zipNo
Headers are forgiving

Case, surrounding spaces, and spaces or hyphens in headings are normalized. For example, First Name becomes first_name.

Outreach

Campaigns

Create a campaign, then assign existing leads to it.
POST/api/v1/campaigns/Create a campaign

Send a required name of up to 128 characters. The response contains the new campaign’s public uid.

Example
curl --request POST \
  --url https://tickets-please.xodelabs.com/api/v1/campaigns/ \
  --header 'Authorization: Token YOUR_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{"name": "August customer outreach"}'
POST/api/v1/campaign-lead-assignments/Assign a lead

Both UUIDs must belong to the token’s organization. Success returns 201 Created with an empty body.

Example
curl --request POST \
  --url https://tickets-please.xodelabs.com/api/v1/campaign-lead-assignments/ \
  --header 'Authorization: Token YOUR_API_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "campaign_uid": "CAMPAIGN_UUID",
    "lead_uid": "LEAD_UUID"
  }'
Ready to integrate?

Start with one test ticket.

Use a non-production workspace, confirm the record in the Tickets Please UI, and then expand the workflow.

Review quick startDownload OpenAPI
Copied to clipboard