Discussions

Updated 11 Oct, 2026 08:43 PM in API

A discussion is one support conversation: a title, the customer's first message and every reply after it. With the API you can list discussions the way your dashboard does, read one with its comments, start one for a customer, and resolve, move, queue or delete it.

Replies have their own article: Comments.

Listing discussions

GET /yoursite/discussions
GET /yoursite/discussions/{state}
curl -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     https://api.tenderapp.com/yoursite/discussions/open
{
  "offset": 0,
  "total": 8,
  "per_page": 30,
  "discussions": [
    {
      "title": "Mobile app crashes when I open an attachment",
      "number": 6,
      "state": "open",
      "public": false,
      "unread": true,
      "unresponded": true,
      "comments_count": 1,
      "last_updated_at": "2026-10-09T06:05:12Z",
      "author_name": "Jonas Berg",
      "author_email": "jonas.berg@mailbox.example.org",
      "href": "https://api.tenderapp.com/yoursite/discussions/13",
      "category_href": "https://api.tenderapp.com/yoursite/categories/8",
      "html_href": "https://yoursite.tenderapp.com/discussions/problems/6"
    }
  ]
}

Each entry has all the discussion fields except comments (trimmed here). Lists come 30 to a page, the most recently active first; ask for the next with ?page=2.

Without a state you get every discussion that isn't deleted or spam. The states are:

State Discussions
new Open, and no supporter has replied yet.
open Waiting on someone, with no ticket linked.
assigned Open, with a ticket linked in an issue tracker.
resolved Resolved.
pending Open or assigned, and waiting on you: the customer wrote last, or someone marked it unread. This is your dashboard's inbox.
deleted Deleted, and spam too.
spam Marked as spam.

Narrowing a list

These parameters work on every list:

Parameter
page The page to return, from 1.
since A number: only discussions whose id is higher. A date or time (2026-10-01, 2026-10-09T06:00:00Z): only discussions with activity after it.
sort updated makes a date in since compare with updated_at (any change to the discussion, including staff actions) instead of last_updated_at.
public public=true: only public discussions.
user_email Only discussions started by this email address, with or without an account.
user_id Only discussions started by this user.
user_current user_current=true: only discussions you started.

For example, every discussion with activity since the start of October:

curl -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     "https://api.tenderapp.com/yoursite/discussions?since=2026-10-01"

And a customer's discussions:

curl -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     "https://api.tenderapp.com/yoursite/discussions?user_email=lucas@northwind.example.com"

The pending list

/discussions/pending (alone, or in a category or queue) is built from the same live counts as your dashboard, so it's fast, but it works a little differently:

  • It has no offset, total or per_page, and its pages are longer than 30. Ask for the next page until one comes back with no discussions.
  • sort orders it: new (most recently active first, the default) or old (longest waiting first).
  • Other parameters, such as user_email and public, are ignored. Adding since or user_id gives you an ordinary list of pending discussions instead, with paging fields.
curl -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     "https://api.tenderapp.com/yoursite/discussions/pending?sort=old"
{
  "discussions": [
    {
      "title": "Recurring tasks skip a week after the clocks changed",
      "state": "assigned",
      "unread": true,
      "last_updated_at": "2026-10-07T05:47:11Z",
      "href": "https://api.tenderapp.com/yoursite/discussions/7"
    },
    {
      "title": "Google Calendar sync stopped working",
      "state": "open",
      "unread": true,
      "last_updated_at": "2026-10-08T09:47:12Z",
      "href": "https://api.tenderapp.com/yoursite/discussions/10"
    }
  ]
}

In a category, a queue or for a user

The same lists, with the same states and parameters, exist under a category, a queue and a user:

GET /yoursite/categories/{category}/discussions/{state}
GET /yoursite/queues/{queue_id}/discussions/{state}
GET /yoursite/users/{user_id}/discussions/{state}

{category} is the category's id or its permalink (problems). The state is optional everywhere.

curl -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     https://api.tenderapp.com/yoursite/categories/questions/discussions/resolved

For queues:

  • Without a state, a queue lists its open and assigned discussions. Ask for /resolved (or another state) to see the rest.
  • mine is your own queue: the discussions assigned to you.
  curl -H "Accept: application/vnd.tender-v1+json" \
       -H "Authorization: Bearer $TENDER_TOKEN" \
       https://api.tenderapp.com/yoursite/queues/mine/discussions
  • none is the discussions in no queue at all. It only works with the pending list: /queues/none/discussions/pending.

More about queues in Queues.

Response time statistics

GET /yoursite/discussions/statistics

How quickly your team first answers customers, over a day, week, month or year:

curl -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     "https://api.tenderapp.com/yoursite/discussions/statistics?date_range=week"
{
  "count": 9,
  "percent": 69.0,
  "average": 0,
  "stddev": 0.31,
  "median": 0
}
Parameter
date_range day, week (the default), month or year.
end A date in the period you want, such as 2026-09-15. The default is today.
Field
count Discussions started in the period that have had a first reply from a supporter.
percent That count as a percentage of all discussions started in the period.
average The average time to that first reply, in seconds.
median The median time to the first reply, in seconds.
stddev The standard deviation of those times, in seconds.

A period with no replied discussions gives an empty object, {}.

A single discussion

GET /yoursite/discussions/{id}
GET /yoursite/categories/{category}/discussions/{number}

A discussion has an id, which is unique on your site, and a number, which counts up within its category: the 6 in yoursite.tenderapp.com/discussions/problems/6. Either way you get the discussion and its comments:

curl -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     https://api.tenderapp.com/yoursite/discussions/17
curl -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     https://api.tenderapp.com/yoursite/categories/problems/discussions/8
{
  "title": "Board view is slow with 500+ cards",
  "permalink": "board-view-is-slow-with-500-cards",
  "number": 8,
  "state": "open",
  "public": false,
  "unread": true,
  "unresponded": false,
  "hidden": false,
  "via": "web",
  "last_via": "web",
  "comments_count": 3,
  "watchers_count": 2,
  "avg_response_time": 0,
  "company_id": 4,
  "cached_queue_list": [8],
  "created_at": "2026-10-08T10:47:13Z",
  "updated_at": "2026-10-09T06:47:24Z",
  "last_updated_at": "2026-10-08T14:07:13Z",
  "author_name": "Fatima Haddad",
  "author_email": "fatima@harborpine.example.com",
  "last_author_name": "Fatima Haddad",
  "last_author_email": "fatima@harborpine.example.com",
  "comments": [
    {
      "body": "Our \"Fleet maintenance\" board has about 600 cards and takes 15 seconds to load. Other boards are fine.",
      "number": 1,
      "user_is_supporter": false,
      "internal": false,
      "author_name": "Fatima Haddad",
      "created_at": "2026-10-08T10:47:13Z"
    },
    {
      "body": "Discussion was added to Bugs queue",
      "number": 2,
      "user_is_supporter": true,
      "internal": true,
      "system_message": true,
      "author_name": "Maya Okafor",
      "created_at": "2026-10-08T10:48:13Z"
    },
    {
      "body": "Thanks Fatima. Could you tell us which browser you're using, and whether filtering the board to one column makes it faster?",
      "number": 3,
      "user_is_supporter": true,
      "internal": false,
      "author_name": "Daniel Reyes",
      "created_at": "2026-10-08T11:47:13Z"
    }
  ],
  "href": "https://api.tenderapp.com/yoursite/discussions/17",
  "comments_href": "https://api.tenderapp.com/yoursite/discussions/17/comments{?page}",
  "user_href": "https://api.tenderapp.com/yoursite/users/17",
  "category_href": "https://api.tenderapp.com/yoursite/categories/8",
  "resolve_href": "https://api.tenderapp.com/yoursite/discussions/17/resolve",
  "queue_href": "https://api.tenderapp.com/yoursite/discussions/17/queue?queue={queue_id}",
  "html_href": "https://yoursite.tenderapp.com/discussions/problems/8"
}

Comments come 30 to a page, oldest first, internal notes included; ?page=2 gives the next 30. A page past the last has no comments field. The comment fields are in Comments.

Deleted and spam discussions answer 404 here; find them with the deleted and spam lists.

Discussion fields

Field
title The title.
permalink The title as it appears in the discussion's address.
number The discussion's number in its category.
state open, assigned, resolved or spam.
public true if anyone can read it in your forum; false if only the customer and your staff can.
unread true while it waits on your team (it's in the pending list).
unresponded true until a supporter replies (it's in the new list).
hidden true when it has been deleted or marked as spam.
via How it started: web (the website and the API), email and so on.
last_via How the latest comment came in.
comments_count Comments the customer can see, the first message included. Internal notes don't count.
watchers_count People who get email about it.
avg_response_time The average time your team took to reply, in seconds, or null before the first reply.
company_id The author's company, or null.
cached_queue_list The ids of the queues it's in.
extras The extra information sent when it was created; only there when there is some.
private_body The same extra information as an HTML list, as staff see it in Tender, or null.
suggested_faqs Ids of KB articles Tender suggested to the customer while they wrote; only there when there are some.
anon_user_token When the author has no account, the key in the link that lets them open the discussion; otherwise null.
redirection_id Set when the discussion was moved; otherwise null.
spawned_from_comment_id Set when it was split off from a comment in another discussion; otherwise null.
activity_filter_stamp Used by your activity filters.
last_comment_id, last_user_id The latest comment the customer can see, and its author.
created_at When it was started.
updated_at When anything about it last changed.
last_updated_at When its latest comment was posted.
author_name, author_email Who started it, with or without an account.
last_author_name, last_author_email Who wrote the latest comment the customer can see.
comments Its comments (a single discussion only).
href This discussion. The last part is its id.
comments_href Its comments.
user_href The author, when they have an account.
category_href Its category.
resolve_href, unresolve_href, toggle_href, acknowledge_href, unacknowledge_href, change_category_href, queue_href, unqueue_href, restore_href The actions.
html_href The discussion in Tender.

Creating a discussion

POST /yoursite/categories/{category_id}/discussions

Use this to open a discussion for a customer, from a contact form or another system. {category_id} must be the category's id here (not its permalink). Send a JSON object:

curl -X POST \
     -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"title": "Export to CSV leaves out custom fields",
          "body": "When I export a project to CSV, the custom field columns are empty.",
          "author_email": "priya.nair@example.com",
          "author_name": "Priya Nair",
          "private": true,
          "skip_spam": true,
          "extras": {"plan": "Business", "account_id": "4821"}}' \
     https://api.tenderapp.com/yoursite/categories/8/discussions

The answer is 201 Created with the new discussion and its first comment:

{
  "title": "Export to CSV leaves out custom fields",
  "number": 10,
  "state": "open",
  "public": false,
  "unread": true,
  "unresponded": true,
  "private_body": "<ul><li>Plan: Business</li><li>Account: 4821</li></ul>",
  "extras": {
    "plan": "Business",
    "account_id": "4821"
  },
  "author_name": "Priya Nair",
  "author_email": "priya.nair@example.com",
  "comments": [
    {
      "body": "When I export a project to CSV, the custom field columns are empty.",
      "number": 1,
      "user_is_supporter": false,
      "internal": false,
      "author_name": "Priya Nair",
      "author_email": "priya.nair@example.com",
      "created_at": "2026-10-09T07:16:48Z"
    }
  ],
  "href": "https://api.tenderapp.com/yoursite/discussions/21",
  "html_href": "https://yoursite.tenderapp.com/discussions/problems/10"
}
Field
body Required. The first message.
title The title. Without one it's "No subject".
author_email Post it as this customer. Someone with an account on your site gets it under their account; anyone else is a guest, who gets replies by email. Without author_email (or unique_id), the discussion is yours.
author_name The customer's name, with author_email.
unique_id Post it as one of your single sign-on users: their id in your own system. If nobody has that id yet, a user is made from author_email, author_name and trusted; if someone has, their name and email are updated from those. A user that isn't valid gets 422.
trusted With unique_id: true makes the user trusted, so their posts skip the spam check.
public, private "public": true or "private": true. Discussions in private categories, and on sites without a public forum, are always private, and categories set to make discussions public do so for customers.
extras Extra information about the customer or their account, as a JSON object of names and values (or that object as a string). See below.
skip_spam true: don't run the spam check on it.
skip_notifications true: don't email anyone about it. Only works when you post it yourself (without author_email).
user_ip, user_agent, referrer The customer's IP address, browser and the page they came from, when you post from your own web form. The spam check uses them.

Extra information

extras is for what your team needs to know about the customer: their plan, account number, app version. Tender shows it to staff above the discussion and never to the customer, and the API gives it back in extras and, as HTML, in private_body. Names are shown made readable: account_id is shown as "Account".

Errors

A field that isn't valid gets 422 with the problems:

{"body": ["can't be blank"]}

A missing or unknown category, or one given by its permalink, gets 422 with [["category_id", "can't be blank"]].

Attachments

To attach files, send the same fields as a multipart/form-data form instead of JSON, with each file as uploaded_assets[] (and 1 or 0 for true and false). See Comments.

Actions

Each action is a POST to the discussion's address and needs no body. They need a token with Read and write access.

Action What it does Answer
resolve Resolves it and adds an internal note saying you did. The discussion
unresolve Opens it again, with a note. The discussion
toggle Switches it between public and private, with a note. The discussion
acknowledge Takes it out of the pending list without replying. The discussion
unacknowledge Puts it back in the pending list, as if the customer had just written. The discussion
queue?queue={queue_id} Adds it to a queue, with a note. mine is your own queue, so this assigns it to you. {}
unqueue?queue={queue_id} Takes it out of a queue, with a note. {}
change_category?to={category} Moves it to another category (by id or permalink). {}
restore Brings back a deleted or spam discussion. {}

The discussion that comes back has no comments in it. Resolving a resolved discussion, or opening an open one, changes nothing.

curl -X POST \
     -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     https://api.tenderapp.com/yoursite/discussions/21/resolve
curl -X POST \
     -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     "https://api.tenderapp.com/yoursite/discussions/21/queue?queue=10"

queue and unqueue without a queue, and change_category without to, get 422 with no body; an unknown queue or category gets 404.

Moving to another category

change_category gives the discussion a new id and a new number in its new category, and the old id stops working. To find it again, list the new category's discussions: it has the same title, author and comments, and an internal note saying where it came from.

Restoring

restore brings a deleted or spam discussion back, comments included, and tells the spam filter it was wrong when it was spam. A discussion that isn't deleted or spam gets 422:

{"error": "Discussion 22 isn't spam or deleted."}

Deleting

DELETE /yoursite/discussions/{id}
DELETE /yoursite/discussions/{id}?type=spam
DELETE /yoursite/discussions/{id}?type=harsh
curl -X DELETE \
     -H "Accept: application/vnd.tender-v1+json" \
     -H "Authorization: Bearer $TENDER_TOKEN" \
     https://api.tenderapp.com/yoursite/discussions/22

The answer is {}. What happens depends on type:

type What it does
none, or delete Deletes it: it moves to the deleted list, and you can restore it.
spam Marks it as spam, the same as the Spam button in Tender: it moves to the spam list, the spam filter learns from it, and its author is blocked from posting again. Use it only for certain spam. You can restore it.
harsh Deletes it and permanently erases its first message. Restoring it later brings back the discussion without that message.

Tender finishes deleting in the background, so the lists can take a moment to show the change. A discussion that's already deleted or spam answers 404.

More from the knowledge base