Support

Akeeba Ticket System

#43492 JSON API: creating a ticket creates neither the documented opening post nor the tags

Posted in ‘Akeeba Ticket System for Joomla!’
This is a public ticket

Everybody will be able to see its contents. Do not include usernames, passwords or any other sensitive information.

Environment Information

Joomla! version
6.2.0
PHP version
8.5
Akeeba Ticket System version
5.6.1

Latest post by sdmarshall73 on Friday, 06 November 2026 17:07 CST

sdmarshall73

(component manifest 5.5.2)

Documentation: https://www.akeeba.com/documentation/ats-for-joomla/api-tickets-create.html

Issue #1: no opening post is created

The documentation says POST /v1/ats/tickets "creates a ticket along with its opening post", and that content_html is the "HTML body of the opening post. It fills the initial reply record and is not stored on the ticket row."

Instead, the ticket is created with no post at all. content_html is still required: without it the request fails with '400 Field required: Reply text'. The text is checked, then thrown away.

Steps to reproduce

1. Enable "Web Services - Akeeba Ticket System". Create a Joomla API token for a user who is Support Staff in the category and has Configure ACL & Options on ATS.
2. Send:
POST /api/index.php/v1/ats/tickets
Authorization: Bearer <token>
Accept: application/vnd.api+json
Content-Type: application/json

{"title": "Test", "catid": <catid>, "public": 0, "content_html": "<p>First post</p>"}
3. The response is the new ticket, with its id.
4. GET /api/index.php/v1/ats/tickets/{id}/posts returns no posts, and #__ats_posts has no row for the ticket.

Expected: as documented, the ticket has content_html as its opening post. Its author is the ticket's created_by when the caller is allowed to set it, just as when a ticket is filed in ATS's admin or front-end pages.

Likely cause: in ATS's own pages, the admin TicketController::save(), which the front end's controller extends, creates the opening post. For a new ticket it separates the post fieldset from the ticket data, saves the ticket with ticket.savingNew set, then runs PostController's save with the new ticket's id (administrator/components/com_ats/src/Controller/TicketController.php, around lines 193–263). The API's TicketsController (api/components/com_ats/src/Controller/TicketsController.php) has no equivalent. Its add() calls ApiController::add(), which saves only the ticket row. The content_html field in forms/ticket_new.xml is marked required="true", so the API still requires the text.

Issue #2: tags are silently dropped

The documentation lists tags ("array of integers, Joomla tag IDs to attach") as a field when creating a ticket.

Sending "tags": [2] with the request above creates the ticket with no tags, and returns no error. The tag exists and is published, and adding it to the ticket by hand in the admin works.

Likely cause: new tickets are validated against forms/ticket_new.xml, which has no tags field. Joomla's form validation therefore removes the value before the save, and ApiController::save() then sets tags to an empty array. Tags can only be set afterwards with PATCH tickets/{id}, which needs the Edit permission.

Expected: as documented, the tags are attached to the new ticket.

Workaround we use

1. Create the ticket with content_html (needed only to pass validation) and no tags.
2. POST /api/index.php/v1/ats/tickets/{id}/posts with {"ticket_id": id, "content_html": "...", "created_by": <user id>}, sending the same text again.
3. PATCH /api/index.php/v1/ats/tickets/{id} with {"tags": [2]}.

Before step 2 we check GET tickets/{id}/posts, so a fixed version won't produce a duplicate post.

Side note on the documentation

The 400 example says "Field required: Reply text" while the field table says content_html. "Reply text" is that field's label (COM_ATS_TICKETS_LBL_REPLY_TEXT). The mismatch caused a little confusion while troubleshooting.

moira

Thank you for such a detailed report, and for the reproduction steps and the workaround. Both of your findings are correct, and we have reproduced them.

Issue #1: no opening post. TicketsController::add() in the API only saves the ticket row. In the web interface, TicketController::save() creates the opening post as a separate step, and the API controller has no equivalent. The documentation describes the intended behaviour, so this is a bug in the API and not a documentation error. The content_html field is still required by the ticket_new form, which is why the text is validated and then discarded.

Issue #2: tags dropped. The ticket_new form has no tags field (only ticket.xml does), so the value is removed during validation. This also matches what you saw. Again, the documentation is correct and the code does not follow it.

Documentation. You are right that the 400 example says "Field required: Reply text" while the field table says content_html. We will make the two consistent.

We are fixing both bugs now. The fix will be in ATS 5.6.2, which we plan to release next week.

Your workaround is sound. Checking GET tickets/{id}/posts before adding the post is the right way to keep it safe once the bug is fixed.

Both problems are reproduced in our automated end-to-end tests, so the fix will be covered by tests.

Moira Fari

Support Specialist

🇬🇧English: native 🕐 My time zone is Asia / Nicosia
Kindly note that my replies are fully vetted by our developers.

sdmarshall73

Thanks for confirming both bugs and for your usual prompt reply and address. One question about the fix before 5.6.2 ships.

Who will own the opening post when a ticket is created through the API with created_by (a ticket opened for a customer)? If it follows the web form's TicketController::save(), the opening post is the API token's user. When that user is a manager in the category, PostTable then sets the ticket to Pending and assigns it to them. I tried this on 5.6.1 (component manifest 5.5.2) by adding a post through the API: the ticket went from O to P and was assigned to the API user. That would override the status and assigned_to sent in the same POST tickets request, which the documentation lists as fields of it.

Our case is an automated service opening tickets for customers based on certain conditions that require staff attention and customer collaboration: no staff member has replied, so the ticket should arrive Open and unassigned, with an opening post that reads as a system notice for both staff and customer. Staff would then attend to the ticket and may ask the user for any additional information. 

Could the fix do one of these?

 1. Not apply the reply rules (status and assignment) to the opening post of a new ticket, so the ticket keeps the status and assigned_to it was created with, or their documented defaults.
 2. Accept an author for the opening post, including the System User (-1), which PostTable already treats as an automated notice that leaves the status alone. Today PostModel replaces any created_by that isn't above 0 with the token's user, on the posts endpoint too.

Either works for us. Until then, we create the ticket, then PATCH status and assigned_to back, which works.

Support Information

Working hours: We are open Monday to Friday, 9am to 7pm Cyprus timezone (EET / EEST). Support is provided by the same developers writing the software, all of which live in Europe. You can still file tickets outside of our working hours, but we cannot respond to them until we're back at the office.

Support policy: We would like to kindly inform you that when using our support you have already agreed to the Support Policy which is part of our Terms of Service. Thank you for your understanding and for helping us help you!