PBN.LTD API docs
View as Markdown

Support tickets

Open support tickets and reply to them.

Ticket categories

GET/api/v1/tickets/queues

Scope tickets:read

The categories (queues) a ticket can be opened in.

Example

curl -s "https://app.pbn.ltd/api/v1/tickets/queues" \
  -H "Authorization: Bearer $PBN_API_KEY"
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/tickets/queues", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/tickets/queues", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());

Response

200

{
  "data": [
    {
      "slug": "technical-problems",
      "title": "Technical Problems"
    }
  ]
}

Errors: rate_limited, scope_missing, unauthorized

List tickets

GET/api/v1/tickets

Scope tickets:read

Your tickets, newest first.

Parameters

NameInTypeRequiredDescription
statusquerystring (one of: open, closed)noOnly open or only closed tickets.
limitqueryintegernoItems per page (1-200). Default: 50.
cursorquerystringnoThe next_cursor value of the previous page. Omit for the first page.

Example

curl -s "https://app.pbn.ltd/api/v1/tickets?status=open" \
  -H "Authorization: Bearer $PBN_API_KEY"
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/tickets?status=open", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/tickets?status=open", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());

Response

200

{
  "data": [
    {
      "id": 4412,
      "reference": "general-support-request-4412",
      "title": "Site shows error 500",
      "queue": "General Support Request",
      "status": "open",
      "priority": "normal",
      "created_at": "2026-09-20T08:00:00Z",
      "updated_at": "2026-09-20T08:00:00Z",
      "panel_url": "https://app.pbn.ltd/account/tickets"
    }
  ],
  "next_cursor": null,
  "has_more": false
}

Errors: rate_limited, scope_missing, unauthorized

Read a ticket

GET/api/v1/tickets/{ticket_id}

Scope tickets:read

A ticket with every public message (yours and support's). can_reply says if you may add a message now (ticket limits: one message before support answers).

Parameters

NameInTypeRequiredDescription
ticket_idpathintegeryesThe ticket id.

Example

curl -s "https://app.pbn.ltd/api/v1/tickets/4412" \
  -H "Authorization: Bearer $PBN_API_KEY"
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/tickets/4412", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/tickets/4412", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());

Response

200

{
  "data": {
    "id": 4412,
    "reference": "general-support-request-4412",
    "title": "Site shows error 500",
    "queue": "General Support Request",
    "status": "open",
    "priority": "normal",
    "created_at": "2026-09-20T08:00:00Z",
    "updated_at": "2026-09-20T08:00:00Z",
    "panel_url": "https://app.pbn.ltd/account/tickets",
    "resolution": null,
    "can_reply": true,
    "can_reply_reason": null,
    "messages": [
      {
        "at": "2026-09-20T08:00:00Z",
        "from": "you",
        "text": "My site shows error 500 since this morning."
      },
      {
        "at": "2026-09-20T08:40:00Z",
        "from": "support",
        "text": "We are looking at it now.",
        "attachments": []
      }
    ]
  }
}

Errors: not_found, rate_limited, scope_missing, unauthorized

Open a ticket

POST/api/v1/tickets

Scope tickets:write

Opens a ticket (support is e-mailed as for a panel ticket). The ticket limits apply: at most 2 open tickets at a time (409 ticket_limit).

Parameters

NameInTypeRequiredDescription
titlebodystringyesShort summary.
messagebodystringyesWhat happened, what you expected.
queuebodystringnoCategory slug (GET /tickets/queues). Default: general-support-request.
prioritybodystring (one of: low, normal, high)noPriority. Default: normal.
site_idbodyintegernoThe site it is about (its domain is added to the ticket).

Example

curl -s -X POST "https://app.pbn.ltd/api/v1/tickets" \
  -H "Authorization: Bearer $PBN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title": "Question about my site", "message": "How do I add a subdomain?", "queue": "general-support-request", "site_id": 123}'
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.post("https://app.pbn.ltd/api/v1/tickets", headers=headers, json={"title": "Question about my site", "message": "How do I add a subdomain?", "queue": "general-support-request", "site_id": 123}, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/tickets", {
  method: "POST",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`, "Content-Type": "application/json"},
  body: JSON.stringify({"title": "Question about my site", "message": "How do I add a subdomain?", "queue": "general-support-request", "site_id": 123})
});
console.log(res.status, await res.json());

Response

201

{
  "data": {
    "id": 4412,
    "reference": "general-support-request-4412",
    "title": "Site shows error 500",
    "queue": "General Support Request",
    "status": "open",
    "priority": "normal",
    "created_at": "2026-09-20T08:00:00Z",
    "updated_at": "2026-09-20T08:00:00Z",
    "panel_url": "https://app.pbn.ltd/account/tickets"
  }
}

Errors: conflict, rate_limited, scope_missing, unauthorized, validation_failed

Reply to a ticket

POST/api/v1/tickets/{ticket_id}/messages

Scope tickets:write

Adds your message to the ticket (support is notified). One message until support answers.

Parameters

NameInTypeRequiredDescription
ticket_idpathintegeryesThe ticket id.
messagebodystringyesYour message.

Example

curl -s -X POST "https://app.pbn.ltd/api/v1/tickets/4412/messages" \
  -H "Authorization: Bearer $PBN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message": "Thanks, that worked."}'
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.post("https://app.pbn.ltd/api/v1/tickets/4412/messages", headers=headers, json={"message": "Thanks, that worked."}, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/tickets/4412/messages", {
  method: "POST",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`, "Content-Type": "application/json"},
  body: JSON.stringify({"message": "Thanks, that worked."})
});
console.log(res.status, await res.json());

Response

201

{
  "data": {
    "id": 4412,
    "reference": "general-support-request-4412",
    "title": "Site shows error 500",
    "queue": "General Support Request",
    "status": "open",
    "priority": "normal",
    "created_at": "2026-09-20T08:00:00Z",
    "updated_at": "2026-09-20T08:00:00Z",
    "panel_url": "https://app.pbn.ltd/account/tickets",
    "messages": []
  }
}

Errors: conflict, not_found, rate_limited, scope_missing, unauthorized