Helpdesk API
29 PracBill API endpoints for helpdesk. Base URL https://billing.pracbill.com.au/api.
Get tickets for a customer (any status unless filtered), newest first. Failure: `customer not found`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
GET /{api_key}/helpdesk/customer/{cid}/tickets
Parameters
| Name | In | Type | Description |
|---|---|---|---|
status | query | integer | Filter by status (0=open, 1=closed, 2=void); all statuses when omitted |
limit | query | integer | Maximum rows (default 50) |
Responses
200— Customer tickets retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Get a specific note. Failure: `note not found`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
GET /{api_key}/helpdesk/note/{noteid}
Responses
200— Note retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Soft-delete a note (POST or DELETE, same behaviour). Failure: `note not found`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
DELETE /{api_key}/helpdesk/note/{noteid}/delete
Responses
200— Note deleted successfully (failures: HTTP 200 with the ErrorResponse envelope)
Soft-delete a note (POST or DELETE, same behaviour). Failure: `note not found`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/note/{noteid}/delete
Responses
200— Note deleted successfully (failures: HTTP 200 with the ErrorResponse envelope)
Update a note (POST or PUT, same behaviour). The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. Failures: `note not found`, `no update data provided`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/note/{noteid}/update
Request body
| Field | Type | Description |
|---|---|---|
note | string | New note text |
internal | integer | Truthy = internal (1), otherwise 0 |
ignore_response | integer | Truthy = exclude from response statistics (1), otherwise 0 |
Responses
200— Note updated successfully (failures: HTTP 200 with the ErrorResponse envelope)
Update a note (POST or PUT, same behaviour). The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. Failures: `note not found`, `no update data provided`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
PUT /{api_key}/helpdesk/note/{noteid}/update
Request body
| Field | Type | Description |
|---|---|---|
note | string | New note text |
internal | integer | Truthy = internal (1), otherwise 0 |
ignore_response | integer | Truthy = exclude from response statistics (1), otherwise 0 |
Responses
200— Note updated successfully (failures: HTTP 200 with the ErrorResponse envelope)
Get helpdesk statistics for the department. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
GET /{api_key}/helpdesk/stats
Responses
200— Statistics retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Get helpdesk statistics for the department, filtered to one assignee. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
GET /{api_key}/helpdesk/stats/{uid}
Responses
200— Statistics retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Create a new helpdesk ticket (status open). The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. Failures: `customer id (cid) is required`, `subject is required`, `customer not found`, `failed to create ticket`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/ticket/create
Request body
| Field | Type | Description |
|---|---|---|
cid required | object | Customer: accepts cid, crm_id or customers_id (resolved by getCustomer()). Required, must not be empty/0 |
subject required | string | Required, must not be empty |
body | string | Optional. When non-empty an initial note (hlpjob_note) is created from it; the ticket's own `body` column is stored as an empty string |
uid | integer | Assigned user id (also recorded as the author of the initial note, 0 when omitted) |
priority | integer | 1=Low, 2=Medium, 3=High, 4=Critical. Invalid or omitted values default to 1 |
ostype | string | Stored in helptickets.ostype when non-empty |
internal | integer | Internal flag of the initial note (cast with intval, default 0) |
contacts | array of object | Extra ticket contacts (helptickets_contacts) |
Responses
200— Ticket created successfully (failures: HTTP 200 with the ErrorResponse envelope)
Get a ticket with its customer, assigned user, notes, attachments and contacts. Failure: `ticket not found`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
GET /{api_key}/helpdesk/ticket/{htid}
Responses
200— Ticket retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Assign a ticket to a user. Failures: `ticket not found`, `user not found`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/ticket/{htid}/assign/{uid}
Responses
200— Ticket assigned successfully (failures: HTTP 200 with the ErrorResponse envelope)
Upload a single attachment to an existing helpdesk ticket. The request must be multipart/form-data with the binary in the `file` field; JSON or base64 bodies are not accepted. Files larger than 10MB are rejected. The new attachment is listed by the ticket detail endpoint and served by the attachment download endpoint.
POST /{api_key}/helpdesk/ticket/{htid}/attachment
Responses
200— Attachment stored successfully, or a JSON error describing why it was rejected
Download a single attachment belonging to a helpdesk ticket. The file content is base64 encoded in the JSON response. Files larger than 10MB are not served.
GET /{api_key}/helpdesk/ticket/{htid}/attachment/{rdid}
Responses
200— Attachment retrieved successfully, or a JSON error describing why it could not be served
Close a helpdesk ticket, optionally adding a note. The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. Failures: `ticket not found`, `ticket is already closed`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/ticket/{htid}/close
Request body
| Field | Type | Description |
|---|---|---|
note | string | Optional. When non-empty a customer-visible note is added, prefixed `Ticket Closed: ` / `Ticket Voided: ` / `Ticket Reopened: ` |
uid | integer | Author of that note (default 0) |
Responses
200— Ticket closed successfully (failures: HTTP 200 with the ErrorResponse envelope)
Merge source tickets into the primary ticket {htid}, mirroring the helpdesk merge screen: each source's notes, helpdesk attachments (every legacy helpdesk module-type spelling; other modules' attachments sharing the numeric id never move) and ticket contacts move to the primary, the source gets an internal `Job Merged with: {htid}` note and is closed (status 1). The primary ticket is otherwise unchanged and no notification is sent. Sources must exist in the API key's department and belong to the primary ticket's customer. Every source is validated before anything is written, so a rejected request makes no changes. The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. Failures: `ticket not found` (primary or any source missing or in another department), `ticket_ids must be a non-empty array of ticket ids`, `ticket_ids must only contain positive integer ticket ids`, `ticket_ids contains duplicate ticket id {id}`, `a ticket cannot be merged into itself`, `ticket {id} belongs to a different customer`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/ticket/{htid}/merge
Request body
| Field | Type | Description |
|---|---|---|
ticket_ids required | array of integer | Source ticket ids to merge into the primary ticket. Unique positive integers (numeric strings are accepted); must not include the primary ticket id |
Responses
200— Tickets merged successfully (failures: HTTP 200 with the ErrorResponse envelope)
Add a note to a ticket. Optionally stores base64 encoded file attachments against the ticket (up to 10, each at most 10MB decoded) and, with send_notification set, sends the standard helpdesk update email for the note with those files attached. Invalid attachment input is rejected before the note or any attachment is written. The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/ticket/{htid}/note/add
Request body
| Field | Type | Description |
|---|---|---|
note required | string | Required, must not be empty |
uid | integer | Author user id (default 0 = system/API) |
internal | integer | Truthy = internal only (stored 1), otherwise 0 (default) |
ignore_response | integer | Truthy = exclude from response-time statistics (stored 1/0). Omitted = column default |
send_notification | integer | 1 to send the standard helpdesk update email for this note (attachments from this request included). Default 0: nothing is emailed. Internal notes/tickets keep the notifier's customer-email suppression. |
attachments | array of object | Files to attach to the ticket. Each is stored in the department's attacheddocs directory and listed on the ticket, exactly as a UI upload. Names must be plain file names (no path separators or control characters); content must be valid base64 decoding to 1..10485760 bytes. |
Responses
200— Note added successfully, or a failure envelope
Get all notes for a ticket (newest first). Failure: `ticket not found`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
GET /{api_key}/helpdesk/ticket/{htid}/notes
Responses
200— Notes retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Set ticket priority. Failures: `ticket not found`, `invalid priority (must be 1, 2, 3, 4)`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/ticket/{htid}/priority/{priority}
Responses
200— Priority updated successfully (failures: HTTP 200 with the ErrorResponse envelope)
Reopen a helpdesk ticket, optionally adding a note. The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. Failures: `ticket not found`, `ticket is already open`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/ticket/{htid}/reopen
Request body
| Field | Type | Description |
|---|---|---|
note | string | Optional. When non-empty a customer-visible note is added, prefixed `Ticket Closed: ` / `Ticket Voided: ` / `Ticket Reopened: ` |
uid | integer | Author of that note (default 0) |
Responses
200— Ticket reopened successfully (failures: HTTP 200 with the ErrorResponse envelope)
Update a helpdesk ticket (POST or PUT, same behaviour). The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. Failures: `ticket not found`, `invalid status` (a supplied `status` outside 0-4 rejects the whole request and nothing is written), `no update data provided`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/ticket/{htid}/update
Request body
| Field | Type | Description |
|---|---|---|
subject | string | |
uid | integer | Assign to user id |
priority | integer | 1-4; values outside the accepted levels are silently ignored |
status | integer (0 | 1 | 2 | 3 | 4) | 0=open, 1=closed, 2=void, 3=awaiting customer input, 4=awaiting supplier input. Any other value rejects the whole request with `invalid status` and nothing is written |
ostype | string | |
cid | object | Move the ticket to another customer (cid/crm_id/customers_id); company is updated too. An unknown customer is silently ignored |
Responses
200— Ticket updated successfully (failures: HTTP 200 with the ErrorResponse envelope)
Update a helpdesk ticket (POST or PUT, same behaviour). The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. Failures: `ticket not found`, `invalid status` (a supplied `status` outside 0-4 rejects the whole request and nothing is written), `no update data provided`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
PUT /{api_key}/helpdesk/ticket/{htid}/update
Request body
| Field | Type | Description |
|---|---|---|
subject | string | |
uid | integer | Assign to user id |
priority | integer | 1-4; values outside the accepted levels are silently ignored |
status | integer (0 | 1 | 2 | 3 | 4) | 0=open, 1=closed, 2=void, 3=awaiting customer input, 4=awaiting supplier input. Any other value rejects the whole request with `invalid status` and nothing is written |
ostype | string | |
cid | object | Move the ticket to another customer (cid/crm_id/customers_id); company is updated too. An unknown customer is silently ignored |
Responses
200— Ticket updated successfully (failures: HTTP 200 with the ErrorResponse envelope)
Void a helpdesk ticket, optionally adding a note. The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. Failures: `ticket not found`, `ticket is already voided`. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/ticket/{htid}/void
Request body
| Field | Type | Description |
|---|---|---|
note | string | Optional. When non-empty a customer-visible note is added, prefixed `Ticket Closed: ` / `Ticket Voided: ` / `Ticket Reopened: ` |
uid | integer | Author of that note (default 0) |
Responses
200— Ticket voided successfully (failures: HTTP 200 with the ErrorResponse envelope)
Get a paginated list of helpdesk tickets (page 1). GET and POST behave identically. Filters are read from $_REQUEST, so they may be sent in the query string (GET) or as query/form-encoded parameters on a POST; a JSON body is not read. Results are scoped to the API key's department. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
GET /{api_key}/helpdesk/tickets
Parameters
| Name | In | Type | Description |
|---|---|---|---|
status | query | integer | Status filter (0=open, 1=closed, 2=void). Defaults to 0 (open) when not supplied |
cid | query | integer | Filter by customer id (ignored when 0/empty) |
uid | query | integer | Filter by assigned user id; 0 returns unassigned tickets |
priority | query | integer | Filter by priority (1=Low..4=Critical; ignored when 0) |
date_from | query | string | Tickets with date >= this value (YYYY-MM-DD) |
date_to | query | string | Tickets with date <= this value (YYYY-MM-DD) |
search | query | string | Search in subject and company |
limit | query | integer | Records per page (default 20) |
order_by | query | string | Sort column (default lastupdate; other values fall back to lastupdate) |
order_dir | query | string | ASC or DESC (default DESC; anything other than ASC is treated as DESC) |
Responses
200— Tickets retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Get a paginated list of helpdesk tickets (page 1). GET and POST behave identically. Filters are read from $_REQUEST, so they may be sent in the query string (GET) or as query/form-encoded parameters on a POST; a JSON body is not read. Results are scoped to the API key's department. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/tickets
Parameters
| Name | In | Type | Description |
|---|---|---|---|
status | query | integer | Status filter (0=open, 1=closed, 2=void). Defaults to 0 (open) when not supplied |
cid | query | integer | Filter by customer id (ignored when 0/empty) |
uid | query | integer | Filter by assigned user id; 0 returns unassigned tickets |
priority | query | integer | Filter by priority (1=Low..4=Critical; ignored when 0) |
date_from | query | string | Tickets with date >= this value (YYYY-MM-DD) |
date_to | query | string | Tickets with date <= this value (YYYY-MM-DD) |
search | query | string | Search in subject and company |
limit | query | integer | Records per page (default 20) |
order_by | query | string | Sort column (default lastupdate; other values fall back to lastupdate) |
order_dir | query | string | ASC or DESC (default DESC; anything other than ASC is treated as DESC) |
Responses
200— Tickets retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Get all open (status 0) tickets across the department, ordered by priority DESC then lastupdate ASC. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
GET /{api_key}/helpdesk/tickets/outstanding
Responses
200— Outstanding tickets retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Get open tickets assigned to a specific user. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
GET /{api_key}/helpdesk/tickets/outstanding/{uid}
Responses
200— Outstanding tickets retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Get a paginated list of helpdesk tickets. GET and POST behave identically. Filters are read from $_REQUEST, so they may be sent in the query string (GET) or as query/form-encoded parameters on a POST; a JSON body is not read. Results are scoped to the API key's department. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
GET /{api_key}/helpdesk/tickets/page/{page_number}
Parameters
| Name | In | Type | Description |
|---|---|---|---|
status | query | integer | Status filter (0=open, 1=closed, 2=void). Defaults to 0 (open) when not supplied |
cid | query | integer | Filter by customer id (ignored when 0/empty) |
uid | query | integer | Filter by assigned user id; 0 returns unassigned tickets |
priority | query | integer | Filter by priority (1=Low..4=Critical; ignored when 0) |
date_from | query | string | Tickets with date >= this value (YYYY-MM-DD) |
date_to | query | string | Tickets with date <= this value (YYYY-MM-DD) |
search | query | string | Search in subject and company |
limit | query | integer | Records per page (default 20) |
order_by | query | string | Sort column (default lastupdate; other values fall back to lastupdate) |
order_dir | query | string | ASC or DESC (default DESC; anything other than ASC is treated as DESC) |
Responses
200— Tickets retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Get a paginated list of helpdesk tickets. GET and POST behave identically. Filters are read from $_REQUEST, so they may be sent in the query string (GET) or as query/form-encoded parameters on a POST; a JSON body is not read. Results are scoped to the API key's department. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/tickets/page/{page_number}
Parameters
| Name | In | Type | Description |
|---|---|---|---|
status | query | integer | Status filter (0=open, 1=closed, 2=void). Defaults to 0 (open) when not supplied |
cid | query | integer | Filter by customer id (ignored when 0/empty) |
uid | query | integer | Filter by assigned user id; 0 returns unassigned tickets |
priority | query | integer | Filter by priority (1=Low..4=Critical; ignored when 0) |
date_from | query | string | Tickets with date >= this value (YYYY-MM-DD) |
date_to | query | string | Tickets with date <= this value (YYYY-MM-DD) |
search | query | string | Search in subject and company |
limit | query | integer | Records per page (default 20) |
order_by | query | string | Sort column (default lastupdate; other values fall back to lastupdate) |
order_dir | query | string | ASC or DESC (default DESC; anything other than ASC is treated as DESC) |
Responses
200— Tickets retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)
Search tickets by subject, company or htid. The body is parsed by the shared extractDataFromRequest() helper: a raw JSON body is normal; a url-encoded JSON string or the legacy `json={...}` / `data={...}` form-encoded wrapper is also accepted. Failure: `search query required` when `query` is empty. An invalid or unknown API key returns HTTP 200 with the `ErrorResponse` envelope `{"success": false, "description": "invalid key"}`; the handler's other failures use the same envelope with a different `description`.
POST /{api_key}/helpdesk/tickets/search
Request body
| Field | Type | Description |
|---|---|---|
query required | string | Search term, matched (LIKE %term%) against subject, company and htid |
status | integer | Optional status filter (0=open, 1=closed, 2=void). When omitted tickets of every status are searched |
limit | integer | Maximum rows returned (default 50) |
Responses
200— Search results retrieved successfully (failures: HTTP 200 with the ErrorResponse envelope)