Exchange the user’s sign-in email and password once.
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.
Treat the token like a password and keep it server-side.
Prefix the token with Token on every API call.
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"
}'
{ "token": "YOUR_API_TOKEN" }curl --request GET \
--url 'https://tickets-please.xodelabs.com/api/v1/helpdesk/tickets/?priority=high' \
--header 'Authorization: Token YOUR_API_TOKEN'
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_TOKENNever expose a token in client-side JavaScript, URLs, logs, screenshots, or source control. Use a dedicated integration user where practical.
/api-token-auth/Create or retrieve a tokenThis is the only endpoint that does not require a token. The username value is the email address used to log in.
| Field | Type | Required | Description |
|---|---|---|---|
username | Yes | Tickets Please sign-in email. | |
password | string | Yes | The user’s current password. |
Predictable behavior
Conventions and errors
A token sees only records belonging to its user’s organization. Cross-organization UUIDs return not found.
Send application/json. Source-list upload is the one multipart/form-data endpoint.
Timestamps are returned as timezone-aware ISO 8601 strings. Empty related values are null.
Ticket and lead list endpoints currently return a plain JSON array, not a pagination envelope.
Collection paths end with /. Ticket and lead detail paths, and /api/v1/crm/contacts/contact, do not.
| Status | Meaning | What to do |
|---|---|---|
| 200 / 201 | Success | Read the JSON body. A successful assignment returns an empty body. |
| 204 | Deleted | Success; there is no response body. |
| 400 | Invalid request | Read the field names and messages in the response body. |
| 401 | Unauthenticated | Check the token and the exact authorization-header format. |
| 403 | Access denied | Check the user, organization subscription, and operation permissions. |
| 404 | Not found | Check the UUID and that the record belongs to the token’s organization. |
Complete surface
Endpoint index
/api-token-auth/
Create or retrieve an API token
GET
/api/v1/helpdesk/tickets/
List tickets
POST
/api/v1/helpdesk/tickets/
Create a ticket
GET
/api/v1/helpdesk/tickets/{ticket_uid}
Retrieve a ticket
PATCH
/api/v1/helpdesk/tickets/{ticket_uid}
Update a ticket
DELETE
/api/v1/helpdesk/tickets/{ticket_uid}
Delete a ticket
GET
/api/v1/leads/
List leads
POST
/api/v1/leads/
Create a lead
GET
/api/v1/leads/{lead_uid}
Retrieve a lead
PATCH
/api/v1/leads/{lead_uid}
Update a lead
DELETE
/api/v1/leads/{lead_uid}
Delete a lead
POST
/api/v1/crm/contacts/contact
Create a contact
POST
/api/v1/source-lists/
Import a CSV source list
POST
/api/v1/campaigns/
Create a campaign
POST
/api/v1/campaign-lead-assignments/
Assign a lead to a campaign
Helpdesk
Tickets
List, filter, create, retrieve, update, and delete customer requests./api/v1/helpdesk/tickets/List ticketsReturns the organization’s tickets as a newest-first JSON array. Filters may be combined.
Query parameters
| Parameter | Match | Example |
|---|---|---|
state | Exact state name | Open |
priority | Exact value: low, medium, or high | high |
contact_email | Case-insensitive exact email | ada@example.com |
curl 'https://tickets-please.xodelabs.com/api/v1/helpdesk/tickets/?state=Open&priority=high' \
--header 'Authorization: Token YOUR_API_TOKEN'/api/v1/helpdesk/tickets/Create a ticketEither description or its legacy alias message is required. If contact details are supplied and the email is new, a contact is created automatically.
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
| Field | Type | Required | Behavior |
|---|---|---|---|
description or message | string | Yes on create | Ticket body. Prefer description. |
subject | string | No | Defaults to “Website contact form request”. Maximum 256 characters. |
priority | enum | No | low, medium, or high; defaults to medium. |
state | string | No | Defaults to the organization’s default ticket state. |
company_uid | UUID or null | No | Must belong to the same organization. |
contact_uid | UUID or null | No | Uses an existing organization contact. |
contact_first_name, contact_last_name | string | No | Used when creating a contact from contact_email. |
contact_email | No | Reuses an existing matching contact or creates one. | |
contact_number | string | No | Maximum 50 characters. |
department_id, category_id | integer or null | No | Tenant-local configuration IDs. |
assigned_to_id | integer or null | No | User ID; the user must belong to the organization. |
resolution_id | integer or null | No | Tenant-local resolution ID. |
/api/v1/helpdesk/tickets/{ticket_uid}Retrieve a ticketReturns the ticket when its public UUID belongs to the token’s organization. There is no trailing slash.
{
"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
}/api/v1/helpdesk/tickets/{ticket_uid}Update selected fieldsSend only the fields that should change. The fields accepted by create are also accepted by update; send null to clear a supported related record.
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"}'/api/v1/helpdesk/tickets/{ticket_uid}Delete a ticketOrganization 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./api/v1/crm/contacts/contactCreate a contactAll four fields are required. The response repeats them and adds the contact’s public uid.
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"
}'| Field | Type | Limit |
|---|---|---|
name | string | 128 characters |
surname | string | 128 characters |
email | Valid email address | |
contact_number | string | 50 characters |
Outreach
Leads
Create simple prospects and manage them by public UUID./api/v1/leads/List leadsReturns an unpaginated array of the organization’s full lead records. The response includes profile fields, stage, timestamps, counters, and related database IDs where present.
/api/v1/leads/Create a leadname, surname, and phone_number are required. A new lead starts in the new stage.
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"
}'{ "uid": "…", "name": "Grace", "surname": "Hopper", "phone_number": "+27 10 555 0199" }/api/v1/leads/{lead_uid}Retrieve a leadReturns the full lead record. There is no trailing slash after the UUID.
/api/v1/leads/{lead_uid}Update a leadPartially updates name, surname, or phone_number. Other lead fields cannot currently be changed through this endpoint.
/api/v1/leads/{lead_uid}Delete a leadDeletes 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./api/v1/source-lists/Import a CSV source listSend multipart/form-data with a list name and CSV file. Rows missing a first name, surname, or phone number are skipped.
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
| Data | Accepted headers | Required per row |
|---|---|---|
| First name | name, first_name | Yes |
| Surname | surname, last_name | Yes |
| Phone | phone_number, phone, mobile, contact_number | Yes |
email, email_address | No | |
| Company | company_name, company, account_name | No |
| Address | street_number, street_name or address, suburb, city, postal_code or postcode or zip | No |
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./api/v1/campaigns/Create a campaignSend a required name of up to 128 characters. The response contains the new campaign’s public uid.
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"}'/api/v1/campaign-lead-assignments/Assign a leadBoth UUIDs must belong to the token’s organization. Success returns 201 Created with an empty body.
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"
}'Start with one test ticket.
Use a non-production workspace, confirm the record in the Tickets Please UI, and then expand the workflow.