Reviewed static rich-embed messages
Static rich-embed messages have no immediate-call path and do not inherit the ordinary interaction capability. Set capabilities.embedMessages: true, list every eligible channel or thread by its own exact ID in scopes.embedMessageChannelIds, pin the expected application and bot IDs, include embed-messages in tools.toolsets, and enable the application's Message Content privileged intent. The embed-message allowlist must remain inside configured read scope. A parent grants neither rich-embed scope nor private-thread membership to a child. Supported targets are text and announcement channels plus active unlocked public, private, and announcement threads. Grant View Channel, Read Message History, Embed Links, and Send Messages for direct channels, or Send Messages in Threads for threads.
The request accepts optional non-blank plain content without HTTP URLs of at most 2,000 characters plus 1 through 10 static embeds. Each embed may contain a title, description, integer RGB color from 0 through 16777215, ISO 8601 timestamp with an explicit offset, author label, footer text, and up to 25 ordered fields with explicit inline defaults. Title, author, and field-name text is limited to 256 characters, description to 4,096, each field value to 1,024, and footer text to 2,048. All embed text across one message is limited to 6,000 Unicode characters, the canonical presentation is limited to 64 KiB, and each embed must contain at least one supported presentation value.
This is a deliberately remote-free presentation DSL rather than raw Discord embed JSON. Embed URLs, author and footer icon URLs, images, thumbnails, video, providers, attachments, caller-selected embed types, unknown fields, and arbitrary JSON are rejected. HTTP URLs are also rejected from plain content because the required Embed Links permission would let Discord append an automatic link embed outside the reviewed layout. Ordinary markdown links may remain untrusted text inside an embed field, but the connector never fetches them and grants them no hidden asset authority.
- Call
preview_embed_messageto validate and normalize the complete presentation locally. Review the deterministic preview, normalized timestamp and defaults, embed and field counts, content and aggregate character counts, serialized byte count, mentioned and suppressed user IDs, notification projection, and warnings. - Call
plan_embed_messagewithaction: "create"oraction: "edit", the exact channel, presentation, explicit notification users, and a unique one-shot operation key. Create may include one exact reply and a separate reply-author notification choice. Edit requires one exact message ID and forbids reply fields. - Review the verified application, bot, guild, channel or thread, parent and private-thread membership where applicable, confirmed intent, complete role and overwrite evidence, required and effective permissions, current edit state, target presentation and preview, notifications, reply, privacy projection, warnings, operation-key hash, and keyed digest.
- If an edit plan reports
already-current, the live presentation matches, the live parsed user-mention state is empty, and the requested notification list is empty. Call execution with the matching digest to receive a record-free no-op. No confirmation, claim, receipt, activity record, rate budget, or Discord mutation is needed. - For a real change, call
execute_embed_messagewith the identical request plus the digest and approve the signed confirmation only if every identity, target, presentation, permission, notification, warning, hash, and digest remains intended. - Review the exact returned message ID, jump URL, response and readback match, activity ID, and terminal outcome before any follow-up.
- Retain the exact request. Call
verify_embed_messageafter completion or a connector restart to bind it to the durable receipt and check the receipt-bound exact message without supplying a plan digest or trusted create message ID.
Creation sends a channel-bound deterministic nonce with uniqueness enforcement and may create a default message or exact reply. Editing is a full replacement of the legacy content and embed arrays rather than a merge. The target must be an exact unpinned default, non-reply message owned by the verified bot, with default flags and no webhook owner, attachment, component, sticker, poll, or unsupported embed data. The connector preserves exact message identity, flags, pin state, creation timestamp, and reply state while editing and does not convert a Components V2, poll, forwarded, webhook, or mixed-media message.
Nobody is notified by default. User mentions inside supported embed text remain visible presentation but cannot authorize a notification; every notified user must appear as an exact visible mention in the optional plain content and must be listed in scopes.mentionUserIds. Role, @everyone, and @here notifications remain disabled. Create reply-author notification is a separate reviewed boolean whose exact reply author must be locally authorized. Edits cannot notify a reply author.
The process-keyed digest binds the normalized presentation, live target state, identities, intent, independent exact scope, thread evidence, permission evidence, reply, notifications, operation-key hash, privacy projection, and warnings. The adapter replans before elicitation, and the service replans again before mutation. A real create acquires a durable exact-channel claim; a real edit acquires a durable exact-message claim. Both consume the shared process-local interaction budget, atomically reserve the one-shot key, append pending content-free activity, and send one non-retried POST or PATCH.
The mutation response and a fresh exact GET must both prove the reviewed bot, guild, channel, message type, default flags, reply identity, parsed mention state, and semantically exact plain content and embed layout. A known non-rate-limited Discord 4xx before a response is failed. Transport ambiguity, rate limiting, server failure, malformed response evidence, response mismatch, readback failure, or local completion-record failure is uncertain; the key remains spent and the durable target claim remains quarantined for operator review. The connector never retries, rolls back, or deletes a created message as compensation.
Verification recomputes a domain-separated HMAC over the normalized caller-retained request and pinned application and bot identities. Production derives its verification key from the bot token independently of the process-bound plan key, so a normal restart preserves the binding while token rotation intentionally invalidates old verification requests. A request mismatch, nonterminal receipt, or receipt target mismatch stops before Discord access. A matching completed receipt triggers fresh identity, intent, exact scope, thread, reply, notification-policy, and read-permission checks followed by one exact message GET. Verification does not require send or Embed Links permission, inspect the write coordinator, reserve a key, append activity, consume the interaction limiter, scan channel history, or infer a created message from content.
Plain content, embed layouts and text, notification and parsed-mention IDs, URLs, raw payloads, nonce, and raw operation key never enter activity records, operation receipts, diagnostics, or telemetry. Durable records contain only exact guild, channel, optional reply, and resulting message IDs, keyed request and plan digests, operation-key hash, timestamps, fixed action, verification and outcome values, activity ID, and a sanitized error category. See Discord's message resource reference, embed object reference, and permissions reference for the underlying platform contracts.
Canonical source: docs/reference.md
Documentation generated for guildcontrol@0.0.0. Canonical source and edit history remain in the public repository. GuildControl is an independent project and is not affiliated with or endorsed by Discord Inc. Discord is used only to identify the platform that GuildControl connects to.