Getting Started

Introduction

The Transcript API is a high-performance endpoint that generates and delivers clean channel transcripts for Discord bots — with no HTML overhead, no SDK requirements, and no configuration complexity.

A single authenticated POST request is all it takes. The API fetches the channel history, formats the transcript, and delivers it directly to a channel you designate — all in under 200ms.

Whether you're powering a ticket system, moderation log, or any workflow requiring channel history, this API integrates in minutes and runs reliably in production.

Ensure your bot has Read Message History and Send Messages permissions in both the source channel and the transcript destination channel before making requests.

Base URL

HTTPS https://ulquiorracifer.xyz
Reference

Endpoint

There is one endpoint. Send a POST request with a JSON body to generate and deliver a transcript to your specified channel.

POST https://ulquiorracifer.xyz/api/transcript

The request body must be valid JSON. Set your Content-Type header to application/json on every request.

Upon a successful call, the transcript is automatically sent to the transcriptChannelId you specify. The response confirms delivery — no polling required.
Reference

Parameters

The request body must be valid JSON. Only botToken and channelId are strictly required — all other parameters are optional and have sensible defaults. Parameters are grouped below by purpose.

Core

ParameterTypeStatusDescription
botToken string Required Your Discord bot token. Used to authenticate with the Discord API and read channel history. Prefix Bot is added automatically if omitted.
channelId string Required Snowflake ID of the Discord channel to transcribe. The bot must have Read Message History access to this channel.
transcriptChannelId string Optional Snowflake ID of the destination channel where the finished transcript file and embed will be sent. If omitted, the transcript is generated and stored but not delivered to any channel.

Ticket Identity

ParameterTypeStatusDescription
ticketCreatorId string Optional Discord user ID of the ticket opener. Populates the embed, badges the user as OWNER in the transcript, and triggers a DM with the transcript file sent directly to them.
ownerId string Optional Legacy alias for ticketCreatorId. Ignored if ticketCreatorId is also provided.
ticketCloserId string Optional Discord user ID of the staff member who closed the ticket. Shown in the embed's "Closed By" field.
ticketId string Optional Your internal ticket number or identifier. Displayed as a labelled field in the embed when provided.
claimedBy string Optional Discord user ID of the staff member who claimed the ticket. Appended to the embed as a "Claimed By" field.

Ticket Meta

ParameterTypeStatusDescription
ticketType string Optional Category or type of the ticket (e.g. "billing", "appeal", "support"). Shown in the embed's "Ticket Type" field. Default: "Support".
supportRoles array Optional Array of Discord role IDs that identify support staff. Members with these roles receive an ADMIN badge in the rendered transcript.

Transcript Config

ParameterTypeDefaultDescription
includeMessages boolean true Include message text content in the transcript. Set to false to produce a metadata-only transcript.
includeAttachments boolean true Render file attachments inline. Images and videos are embedded; other files are shown as download links.
includeEmbeds boolean true Render Discord message embeds (author, title, description, fields) inside the transcript.
saveImages boolean false When enabled, image attachments are saved and embedded as data URIs, making the transcript self-contained even if original URLs expire.

Embed Customization

These fields control the Discord embed sent to your transcript channel. If embedDescription is provided, the embed switches to description-only mode — a single resolved text block, no fields. Without it, a structured fields layout is used automatically.

ParameterTypeDefaultDescription
embedTitle string "Ticket Transcript" Embed title. Supports placeholders.
embedDescription string Custom embed body text. When set, disables the auto-generated fields layout. Supports placeholders.
embedColor string "#5865F2" Hex color for the embed accent bar (e.g. "#00eeff"). The leading # is optional.
embedFooter string Guild name Footer text shown below the embed. Supports placeholders.
embedTimestamp boolean true Attach the current timestamp to the embed footer.
embedThumbnail string URL of an image to display as the embed thumbnail (small image in the top-right corner).
embedImage string URL of a full-width image to display at the bottom of the embed.

Advanced

ParameterTypeDefaultDescription
timezone string "UTC" IANA timezone string used to format message timestamps in the HTML (e.g. "America/New_York", "Europe/London").
autoDeleteAfter number Seconds after which the transcript messages are automatically deleted from Discord. Useful for temporary or private transcripts.
customFields object Arbitrary JSON object attached to the transcript record. Useful for storing metadata specific to your system (e.g. {"tier": "premium", "region": "eu"}).

Pro Features

ParameterTypeDefaultDescription
showJoinLeave boolean false Include server join and leave events in the transcript timeline.
showEdits boolean false Show the full edit history for messages that were edited by the author.
showDeletes boolean false Include deleted messages in the transcript (shown with a strikethrough style).
generateSummary boolean false Auto-generate a short summary of the transcript conversation and prepend it to the HTML output.
watermark string Custom watermark text rendered at the bottom of the transcript HTML (e.g. your bot name or server name).
Reference

Example Request

Production-ready examples for every major environment. Copy, replace the placeholder values, and ship.

// JavaScript — Fetch API const response = await fetch('https://ulquiorracifer.xyz/api/transcript', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ // ── Core (required) ── botToken: 'YOUR_BOT_TOKEN', channelId: 'TICKET_CHANNEL_ID', transcriptChannelId: 'LOG_CHANNEL_ID', // ── Ticket Identity ── ticketId: '42', ticketCreatorId: 'USER_ID', ticketCloserId: 'STAFF_ID', // ── Ticket Meta ── ticketType: 'support', // ── Embed Customization ── embedTitle: '{serverName} — Ticket #{ticketID}', embedDescription: 'Opened by {ticketOpener} · Closed by {ticketCloser}\nChannel: {channelName} · Messages: {messageCount}', embedColor: '#00eeff', embedFooter: 'TranscriptAPI · {serverName}', // ── Transcript Config ── includeMessages: true, includeAttachments: true, includeEmbeds: true, // ── Advanced ── timezone: 'America/New_York' }) }); const data = await response.json(); console.log(data.url); // direct link to the stored transcript
# Python — requests library import requests url = 'https://ulquiorracifer.xyz/api/transcript' headers = {'Content-Type': 'application/json'} payload = { # ── Core (required) ── 'botToken': 'YOUR_BOT_TOKEN', 'channelId': 'TICKET_CHANNEL_ID', 'transcriptChannelId': 'LOG_CHANNEL_ID', # ── Ticket Identity ── 'ticketId': '42', 'ticketCreatorId': 'USER_ID', 'ticketCloserId': 'STAFF_ID', # ── Embed Customization ── 'embedTitle': '{serverName} — Ticket #{ticketID}', 'embedDescription': 'Opened by {ticketOpener} · {messageCount} messages', 'embedColor': '#00eeff', 'embedFooter': 'TranscriptAPI · {serverName}', # ── Advanced ── 'timezone': 'Europe/London' } resp = requests.post(url, json=payload, headers=headers) print(resp.json()) # {'status': 'sent', 'url': 'https://...'}
// BDFD — Bot Designer for Discord $httpPost[https://ulquiorracifer.xyz/api/transcript; { // Core "botToken": "$getVar[BotToken]", "channelId": "$channelID", "transcriptChannelId": "$json[transcriptchannel]", // Ticket Identity "ticketCreatorId": "$channelTopic", "ticketCloserId": "$authorID", "ticketId": "$getVar[ticketNumber]", // Embed Customization "embedTitle": "{serverName} — Ticket #{ticketID}", "embedDescription": "Opened by {ticketOpener} · {messageCount} messages", "embedColor": "#00eeff" } ]
Reference

Example Response

On success, the API returns a 200 OK JSON response confirming the transcript was generated and delivered to your channel.

200 OK application/json
{ "status": "sent", "url": "https://ulquiorracifer.xyz/t/a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
Reference

Error Handling

The API uses standard HTTP status codes. All error responses return a JSON body with an error field containing a human-readable message. For 500 errors a detail field is also included with the underlying exception message.

400
Bad Request

A required parameter is missing or invalid. The three distinct 400 paths are: botToken absent, channelId absent, or channelId is invalid / the bot cannot access it. A descriptive error message is returned in each case, and the bot also sends the error to your transcriptChannelId if possible.

Triggered when botToken or channelId is missing, empty, or refers to a channel the bot cannot read.
{ "error": "Channel ID is invalid or bot lacks access." }
429
Too Many Requests

Your IP or guild has hit the rate limit. Two limits are enforced independently: a 5-second per-IP cooldown and a 5-second per-guild cooldown. The response tells you exactly how many seconds to wait before retrying.

Triggered when More than one request is made within 5 seconds from the same IP address or the same Discord guild.
{ "error": "You have been rate limited. Please try again after 3 seconds." }
500
Internal Server Error

An unexpected condition occurred on the server. This is extremely rare — zero 500 errors have been recorded in production. A detail field is included in the response with the underlying error message. The bot also attempts to send the error to your transcriptChannelId.

Triggered when An unhandled server-side exception occurs (not encountered in live usage).
{ "error": "Transcript generation failed.", "detail": "fetch failed" }
The infrastructure is engineered for stability. All parameters are validated before execution and the server has maintained a 100% success rate across all production requests to date.
Reference

Rate Limits

Two independent rate limits protect the API from abuse. Both use a sliding-window mechanism — the cooldown resets from the timestamp of your last request.

ScopeLimitKeyNotes
IP 1 req / 5 s Caller's IP address Applied before any parameter validation. Returns 429 with a countdown in seconds.
Guild 1 req / 5 s Discord guild ID (from channelId) Applied after the channel is resolved. Prevents burst usage within the same server.
In practice, ticket bots close one ticket at a time and never hit these limits. The limits only activate if you send multiple requests back-to-back in automation scripts or tests.
Reference

Placeholders

Placeholders let you inject live data into embedTitle, embedDescription, and embedFooter. They are resolved at request time using values from the channel, guild, and your request body. Placeholders are case-insensitive.

PlaceholderResolves to
{ticketOpener} Discord mention of the ticket creator — <@USER_ID>. Requires ticketCreatorId (or ownerId).
{ticketOpenerID} Raw user ID of the ticket creator.
{ticketCloser} Discord mention of the staff member who closed the ticket. Requires ticketCloserId.
{ticketCloserID} Raw user ID of the ticket closer.
{ticketID} Your ticketId value (e.g. "42").
{ticketChannelID} Snowflake ID of the transcribed channel.
{channelName} Name of the transcribed channel (e.g. ticket-0042). Also aliased as {channel}.
{serverName} Name of the Discord guild. Also aliased as {server}.
{ticketType} Value of ticketType (or panelName). Defaults to "Support".
{claimedBy} Discord mention of the staff member who claimed the ticket. Requires claimedBy.
{claimedByID} Raw user ID of the staff member who claimed the ticket.
{users} Comma-separated Discord mentions of every unique non-bot user who sent a message in the transcript.
{messageCount} Total number of messages included in the transcript.
{closedAt} Discord long-form timestamp of when the transcript was generated — e.g. Monday, 7 April 2026 14:30:00.
{closedAtR} Discord relative timestamp — e.g. 2 minutes ago.
Placeholders that depend on values you didn't provide (e.g. {ticketCloser} without ticketCloserId) resolve to "Unknown" rather than throwing an error.
Need help or have questions?
Reach out to Cenzo directly or join the community support server.