BizKitHub
DocsAPI ReferenceIssue/bff/issue/detail
getIssueAdmin BFF

/bff/issue/detail

Returns full issue detail including description, project info, assignee, reporter, parent issue, due date, and linked URLs. Returns { exist: false } if the issue is not found.

IssuegetBffIssueDetail

Parameters

1 query

Query parameters

· 1
issueKeystringRequired

Issue key (e.g. "PROJ-123").

ExamplePROJ-123

Response schema

1 status code documented

200Success
object | object
One of 2:
Variant 1
idstringRequired

Issue key.

internalIdnumberRequired

Internal numeric ID.

externalIdstringRequired

Immutable 16-char alphanumeric public identifier (pm__issue.external_id). Used in customer-facing URLs (support portal, e-mail deep links, [BKH-ISSUE:xxxxxxxxxxxxxxxx] tokens) and for cross-system references — never changes across the ticket's lifetime, unlike issueKey which is tied to the project prefix and could theoretically re-key on a merge.

issueKeystringRequired

Issue key (e.g. "PROJ-123").

subjectstringRequired

Issue subject/title.

descriptionstringRequired

Issue description (HTML).

internalDescriptionstring | nullRequired
One of 2:
Variant 1
string

Internal notes visible only to team members.

Variant 2
null
aiSummarystring | nullRequired
One of 2:
Variant 1
string

LLM-produced short paraphrase of the description in the reporter's language (~400 chars). Read-only in the admin UI — writes only originate from the inbound-mail classifier, updateIssue regen when the description is edited, or the explicit /bff/issue/generate-summary button. null when no summary has been generated yet.

Variant 2
null
prioritynumberRequired

Priority (1-5).

priorityLabelstringRequired

Human-readable priority label.

velocitynumberRequired

Effort/complexity score (0..100). DB default 25. Anchors: 1 trivial, 25 default ~20 min, 50 ~4 h, 75 ~2 days, 90+ split, 100 unsolvable/unclear.

Range: 0–100
projectIdnumberRequired

Internal project id — link the admin breadcrumb to /project/{projectId}.

projectKeystringRequired

Project key (e.g. "PROJ").

projectNamestringRequired

Project display name.

typeobjectRequired
idnumberRequired

Issue type ID (pm__issue_type.id).

codestringRequired

Stable slug (story, epic, task, sub_task, bug, …). Admin resolves the localized label from its dictionary.

iconstring | nullRequired
One of 2:
Variant 1
string

Lucide icon name to render alongside the subject.

Variant 2
null
statusobjectRequired
idnumberRequired

Status ID.

labelstringRequired

Status display label (localized to the viewing organisation).

categoryIdnumberRequired

Status category ID (1=new, 2=progress, 3=waiting, 4=done).

categoryCodestringRequired

Status category code.

assigneeobject | nullRequired
One of 2:
Variant 1
idnumberRequired

Contact ID.

externalIdstring | nullRequired
One of 2:
Variant 1
string

Public contact identifier used in admin URLs (/contact/{externalId}) and in /bff/contact/detail?customerId=.... null for legacy rows that predate the external-id backfill; the UI should render the name without a link in that case.

Variant 2
null
namestringRequired

Full name.

emailstring | nullRequired
One of 2:
Variant 1
string

Contact e-mail. null for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to name or the contact ID.

Variant 2
null
avatarUrlstringOptional

Avatar image URL resolved via core__blob. Falls back through the contact's own avatar_blob_id, then the linked member user's contact avatar_blob_id. Omitted when neither has an avatar uploaded.

Variant 2
null
reporterobject | nullRequired
One of 2:
Variant 1
idnumberRequired

Contact ID.

externalIdstring | nullRequired
One of 2:
Variant 1
string

Public contact identifier used in admin URLs (/contact/{externalId}) and in /bff/contact/detail?customerId=.... null for legacy rows that predate the external-id backfill; the UI should render the name without a link in that case.

Variant 2
null
namestringRequired

Full name.

emailstring | nullRequired
One of 2:
Variant 1
string

Contact e-mail. null for phone-only contacts (no e-mail registered) and for contacts anonymised via GDPR. UI should fall back to name or the contact ID.

Variant 2
null
avatarUrlstringOptional

Avatar image URL resolved via core__blob. Falls back through the contact's own avatar_blob_id, then the linked member user's contact avatar_blob_id. Omitted when neither has an avatar uploaded.

Variant 2
null
isSpamboolean | nullRequired
One of 2:
Variant 1
boolean

Spam classification. Null = not yet classified.

Variant 2
null
parentIdnumber | nullRequired
One of 2:
Variant 1
number

Internal ID of the parent issue (for sub-tasks or merged children).

Variant 2
null
parentobject | nullRequired

Populated when this issue has been merged into another via /bff/issue/merge (or filed as a sub-task with a parent). The admin renders a prominent "merged into" callout linking here. null for regular top-level issues.

One of 2:
Variant 1
issueKeystringRequired

Parent issue key — use in /issue/{issueKey} for the FE link.

subjectstringRequired

Parent subject, rendered inline in the "merged into" callout.

statusCategoryCodestringRequired

Canonical bucket code (new / progress / waiting / done) so the FE can dot-color the callout.

Variant 2
null
dueDateDate | string | string | number | nullRequired
One of 2:
Variant 1
Date | string | string | number

Due date.

One of 4:
Variant 1
Date

Due date.

Variant 2
stringdate-time
Variant 3
stringdate
Variant 4
number
Variant 2
null
testUrlstring | nullRequired
One of 2:
Variant 1
string

URL to test environment.

Variant 2
null
documentationUrlstring | nullRequired
One of 2:
Variant 1
string

URL to documentation.

Variant 2
null
humanOnlybooleanRequired

When true, the AI orchestrator (and any future automated agent) aborts and never touches this ticket. Set by operators for tickets that need human judgement (legal escalation, incident, VIP).

securedTicketbooleanRequired

When true, the ticket is marked confidential (pm__issue.secured_ticket) and only ORG ROOT members can see it. Regular members receive { exist: false } from /bff/issue/detail for this issue and never see it in lists or counts. Written by the AI classifiers (mail + triage) on the way in — a Comgate payment-status mail auto-flags the issue as secured — and toggled by root operators from the sidebar.

insertedDateDate | string | string | numberRequired

When the issue was created.

One of 4:
Variant 1
Date

When the issue was created.

Variant 2
stringdate-time
Variant 3
stringdate
Variant 4
number
updatedDateDate | string | string | number | nullRequired
One of 2:
Variant 1
Date | string | string | number

Last update timestamp.

One of 4:
Variant 1
Date

Last update timestamp.

Variant 2
stringdate-time
Variant 3
stringdate
Variant 4
number
Variant 2
null
attachmentsobject[]Required

Files linked to the issue via pm__issue_attachment. Empty when the issue has none.

Each array item:
blobTokenstringRequired

core__blob.token — pass to for inline preview.

filenamestringRequired

Original filename as stored on the blob. Never null — when the blob was ingested without a filename (e.g. an inbound e-mail attachment with a missing Content-Disposition: filename=…), the endpoint substitutes a priloha.<ext> placeholder derived from the MIME type.

contentTypestringOptional

MIME type.

sizenumberRequired

File size in bytes.

downloadUrlstringRequired

Signed direct-download URL to the storage bucket.

positionnumberRequired

Display order within the issue (1-based).

sourceEmailsobject[]Required

Inbound-mail rows linked via brj__emailer_received_email.issue_id. Ordered oldest first — the first entry is the originating mail that lifted the ticket. Empty when the issue was not created from mail.

Each array item:
externalIdstringRequired

Public 16-char identifier of the inbound mail — use in /emailer/received/:externalId for the admin link.

subjectstringRequired

Subject as received from Resend.

fromAddressstringRequired

Envelope From address.

receivedAtDate | string | string | numberRequired

When Resend received the message.

One of 4:
Variant 1
Date

When Resend received the message.

Variant 2
stringdate-time
Variant 3
stringdate
Variant 4
number
ipnull | objectRequired

Reporter geolocation snapshot resolved from the request IP at ticket creation. Same shape as the order-detail ip block so the admin can reuse the same rendering component. null for tickets created without request-time IP context (cron, mail pipeline, manual admin entry). Admin hides the block for 127.0.0.1.

One of 2:
Variant 1
null
Variant 2
ipstringRequired

Accepted formats:

  • IPv4 dot-decimal, e.g. 1.1.1.1 (4 octets, 0–255, no leading zeros).
  • IPv6 as defined by RFC 4291 — full 2001:0db8:0000:0000:0000:0000:0000:0001, zero-compressed 2001:db8::1, IPv4-mapped ::ffff:1.2.3.4, or scoped literals. Both upper- and lower-case hex are accepted.

Server-side canonicalization (ipNormalize in core/src/lib/network/ipNormalize.ts):

  • Valid IPv4 is passed through verbatim.
  • Valid IPv6 is lowercased (RFC 5952 §4.3).
  • IPv4-mapped IPv6 ::ffff:X.X.X.X is unwrapped to plain IPv4 (RFC 4291 §2.5.5.2) so 1.2.3.4 and ::ffff:1.2.3.4 share one brj__geo_ip row.
  • Loopback aliases (::1, 0.0.0.0, localhost, empty string) collapse to 127.0.0.1.
  • Junk values that fail both IPv4 and IPv6 validation are silently rejected and replaced with 127.0.0.1 (loopback).

On the wire: every response returns the canonicalized form — clients can safely rely on lowercase IPv6 and the plain-IPv4 unwrap when de-duping or joining. Server-originated writers (activity log, session log, ban list) resolve the visitor IP via resolveClientIp / resolveClientIpOrNull — always native IPv6 on Vercel Edge (there is no auto-mapping to ::ffff:X.X.X.X).

Enrichment: the system resolves reverse DNS, geolocation, ASN, mobile/proxy/hosting/Tor flags via our VikiTron GEO/IP resolver for both address families. Learn more

Examples1.1.1.12001:4860:4860::8888
citystring | nullRequired
One of 2:
Variant 1
string

City name (brj__geo_ip_city.city).

Variant 2
null
countrystring | nullRequired
One of 2:
Variant 1
string

Country name (brj__geo_ip_city.country).

Variant 2
null
countryRegionstring | nullRequired
One of 2:
Variant 1
string

ISO 3166-2 country subdivision (brj__geo_ip_city.country_region).

Variant 2
null
latitudenumber | nullRequired
One of 2:
Variant 1
number

City-center latitude (brj__geo_ip_city.latitude).

Variant 2
null
longitudenumber | nullRequired
One of 2:
Variant 1
number

City-center longitude (brj__geo_ip_city.longitude).

Variant 2
null
hostnamestring | nullRequired
One of 2:
Variant 1
string

Reverse-DNS hostname (brj__geo_ip.hostname), when resolved.

Variant 2
null
timezonestring | nullRequired
One of 2:
Variant 1
string

IANA timezone (cas__timezone.timezone) resolved via brj__geo_ip.timezone_id.

Variant 2
null
mobilebooleanRequired

true when ip-api flagged the IP as a mobile carrier network. Defaults to false when the enrichment has not yet run.

proxybooleanRequired

true when ip-api flagged the IP as an anonymising proxy / VPN. Defaults to false when the enrichment has not yet run.

hostingbooleanRequired

true when ip-api flagged the IP as hosting infrastructure (data-center, cloud provider). Defaults to false when the enrichment has not yet run.

torboolean | nullRequired
One of 2:
Variant 1
boolean

true when the IP is on the TOR exit-node list at the time the ticket was created. null when TOR classification has not yet been resolved (distinct from a known non-TOR false).

Variant 2
null
originChannelnull | objectRequired

Entry point that created the issue, resolved via pm__issue.origin_channel_id → pm__issue_origin_channel. null for pre-migration rows and paths that do not yet pass a channel code. Rendered as "Zdroj: …" in the admin sidebar Details card.

One of 2:
Variant 1
null
Variant 2
codestringRequired

Stable machine identifier of the entry point (contact_form, mail_in, admin, api, cron, agent) from pm__issue_origin_channel.code. Opaque to the admin — used as a lookup key into the FE i18n dictionary.

labelstringRequired

Canonical Czech label from pm__issue_origin_channel.label. Used as a fallback when the admin has no translation for the code.

localestringRequired

ISO 639-1 code (e.g. "cs", "en") of the language this issue is conducted in — the value of pm__issue.locale_id joined to core__localization_locale.locale. Populated deterministically at INSERT (reporter → org fallback) and refined by AI during triage; NOT NULL invariant, so every issue has a real code. The admin renders it as "EN — angličtina" (short code + Intl.DisplayNames full name in the operator's UI locale) in the sidebar Details card.

Variant 2
exist"false"Required

Response example

application/json
{
  "id": "example_id",
  "internalId": 0,
  "externalId": "example_externalId",
  "issueKey": "example_issueKey",
  "subject": "example_subject",
  "description": "example_description",
  "priority": 0,
  "priorityLabel": "example_priorityLabel",
  "velocity": 0,
  "projectId": 0,
  "projectKey": "example_projectKey",
  "projectName": "example_projectName",
  "type": {
    "id": 0,
    "code": "example_code"
  },
  "status": {
    "id": 0,
    "label": "example_label",
    "categoryId": 0,
    "categoryCode": "example_categoryCode"
  },
  "humanOnly": false,
  "securedTicket": false,
  "attachments": [
    {
      "blobToken": "example_blobToken",
      "filename": "example_filename",
      "contentType": "example_contentType",
      "size": 0,
      "downloadUrl": "example_downloadUrl",
      "position": 0
    }
  ],
  "sourceEmails": [
    {
      "externalId": "example_externalId",
      "subject": "example_subject",
      "fromAddress": "example_fromAddress"
    }
  ],
  "locale": "example_locale"
}

Request example

GET /bff/issue/detail

get
curl -X GET "https://api.bizkithub.com/bff/issue/detail?issueKey=PROJ-123" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY"

Need an API key?

All BizKitHub public API endpoints require authentication via API key.

Get API Key