FiveM Discord refund bot observability with structured logs and alert rules
Build reliable refund automation by instrumenting your Discord bot with structured logs, correlation IDs, and alert rules that catch failures before your community does.
Refund workflows in a FiveM community touch multiple systems: Discord roles and permissions, ticket channels, payment references, and sometimes in-game identifiers like license/steam/discord IDs. When something breaks, “the bot didn’t work” is not a diagnosis. Observability turns that complaint into a timeline: who requested a refund, which ticket it came from, what permission check ran, what external call failed, and what message the bot sent (or didn’t). This post focuses on practical structured logging and alert rules for a Discord refund bot used in FiveM communities, so you can troubleshoot quickly and keep support consistent.
Define the refund workflow and failure points
Start by writing down your bot’s refund path as discrete steps. Observability works best when you can say which step failed and why. A typical flow looks like: a user opens a ticket in a #support category, selects “Refund” in a Discord select menu, the bot validates eligibility (purchase window, product, prior refunds), checks permissions (e.g., Support Team role can approve), logs a decision, and posts an outcome in the ticket plus a staff log channel like #refund-audit.
- Ticket intake: bot receives an interaction in a channel under the Tickets category (or a thread) and captures ticket/channel metadata.
- Identity resolution: bot maps Discord user ID to FiveM identifiers (license/steam) if required, or links to a purchase reference.
- Authorization: bot checks roles (e.g., @Support, @Senior Support) and channel permissions (View Channel, Send Messages) before taking action.
- Validation: bot verifies refund rules (time since purchase, product type, chargeback status) and prevents duplicates.
- Execution: bot triggers the refund action (internal ledger update, webhook to a payment provider, or a manual approval record).
- Notification and audit: bot posts a user-facing message in the ticket and writes an immutable audit entry to #refund-audit or a database.
Each step has common failure points: missing intents, rate limits, permission errors, message send failures in locked tickets, stale role IDs after a server restructure, or mismatched identifiers (user changed Discord account). Your logs and alerts should map directly to these steps so you can pinpoint the break without reproducing it live.
Design structured logs for Discord and FiveM context
Structured logs mean you emit JSON (or key-value) with consistent fields, not free-form strings. This lets you filter by guildId, ticketChannelId, refundId, or error.code. For Discord bots, include both interaction-level fields (interactionId, commandName/customId) and moderation context (actor role IDs, permission check results). For FiveM communities, add identifiers you actually use in support: discordUserId, fivemLicense, steamHex, and any internal purchase ID.
- ts: ISO timestamp (UTC)
- level: info/warn/error
- event: stable name like refund.requested, refund.approved, refund.denied, refund.executed, refund.audit_written
- guildId, guildName (optional)
- channelId, channelName, ticketId (if you generate one)
- discordUserId, discordTag (optional), staffUserId (when applicable)
- roleIdsChecked and permissionResult (allowed/denied + missing perms)
- refundId: your internal unique ID for the refund attempt
- purchaseId / orderId and productSku (if applicable)
- correlationId: one ID shared across all logs for a single refund flow
- error: {name, message, code, stack} for failures
- latencyMs for external calls (HTTP/webhooks/database)
Use stable event names and avoid logging secrets. Do not log full payment tokens, email addresses, or raw IPs. If you must reference sensitive data, hash it (e.g., SHA-256 of orderId) and store the clear value only in your secure system of record. If you use LD Refund System, align your event names with the actions your staff recognizes (request, review, approve/deny, execute, audit) so your logs match your operational language.
Practical tip: log permission checks explicitly
When a staff member clicks “Approve Refund,” log the exact roles present on the actor and the required role IDs. Also log the channel permission snapshot (e.g., missing Send Messages in the ticket channel). This turns “bot ignored me” into a concrete denial reason you can fix by updating role mappings or channel overwrites.
Implement correlation IDs across tickets, interactions, and refunds
Correlation IDs are the difference between “we saw an error” and “we can trace this one refund end-to-end.” Generate a correlationId at the first entry point (e.g., when the user selects “Refund” in the ticket) and attach it to every subsequent log line, including retries. If you create a refundId in your database, log both: correlationId for the flow, refundId for the record.
Example: a user opens ticket #ticket-4821, then clicks a button with customId refund_request. Your bot logs event=refund.requested with correlationId=2f3c… and includes channelId, messageId, discordUserId. When staff approves, log event=refund.approved with the same correlationId plus staffUserId and roleIdsChecked. If the bot calls a webhook and gets HTTP 429, log event=refund.execute_failed with error.code=429 and retryAttempt=1, still under the same correlationId. Later, you can search one ID and see the complete story.
“”
Route logs to the right places (and keep them searchable)
Discord-only “log channels” are useful for human visibility but weak for troubleshooting at scale. Keep #refund-audit for quick review (who approved what, when), but also ship structured logs to a searchable store: a hosted log platform, Elasticsearch/OpenSearch, or even a managed database table if volume is low. The key is that you can filter by correlationId, guildId, and event, and you can retain logs long enough to handle disputes.
For Discord audit channels, post a compact embed that mirrors your structured fields: Refund ID, Ticket, Requester, Approver, Decision, Reason, and a link to the ticket message. For the log store, keep the full JSON. If you run multiple FiveM servers (multiple guilds or multiple environments like staging/prod), include environment and shard identifiers so you don’t chase the wrong instance.
Practical tip: separate “user-facing” and “diagnostic” messages
In tickets, keep messages short (“Refund request received; staff will review”). Put diagnostics in logs (permission results, webhook response codes). This avoids leaking internal rules to users while still giving you everything you need to debug.
Create alert rules that match real failure modes
Alerts should fire on conditions that require action, not on every error. Refund bots commonly fail in predictable ways: permission drift (role IDs changed), Discord API issues (rate limits, missing intents), database outages, or stuck workflows where requests never reach “approved/denied.” Build alert rules around these patterns using your structured fields.
- High error rate: count(event ends with _failed) by environment over 5–10 minutes; alert when above a baseline.
- Permission denials spike: count(event=refund.permission_denied) grouped by requiredRoleId; indicates role rename/recreate or misconfigured staff roles.
- Stuck refunds: event=refund.requested without a terminal event (refund.approved/refund.denied) within X hours; route to a staff queue.
- Webhook/provider failures: error.code in [401,403] (credentials) or repeated 5xx; page immediately because refunds may not execute.
- Discord send failures: error.code=50013 (Missing Permissions) or 50001 (Missing Access) when posting in ticket channels; indicates category overwrite changes.
- Rate limiting: error.code=429 with retry exhaustion; tune backoff and reduce message spam in tickets.
Tie alerts to ownership. For example, permission drift alerts go to whoever manages Discord roles and category overwrites; database alerts go to whoever maintains the bot host. If you use on-call rotations, include runbook links in the alert payload: “Check role ID mapping in config,” “Verify bot has View Channels in Tickets category,” “Confirm privileged intents enabled in Developer Portal.”
Troubleshooting playbook: from alert to fix
When an alert fires or a user reports an issue, follow a consistent process. Your goal is to confirm impact, identify the failing step, and apply the smallest safe fix. With correlation IDs and structured logs, you can do this quickly even if the original staff member is offline.
- Identify a single example: grab the ticket channel ID and approximate time, or ask for the bot’s last message in the ticket.
- Search logs by channelId and time window; find event=refund.requested and capture correlationId/refundId.
- Walk the timeline for that correlationId; note the first error event and its step (authorization, validation, execution, notification).
- Check Discord-side causes: bot role position, missing permissions in the ticket category, changed role IDs, disabled intents, or channel archived/locked.
- Check service-side causes: database connectivity, webhook credentials, rate-limit backoff, or queue backlog.
- Apply the fix and re-run safely: use an admin-only “retry refund execution” command that logs event=refund.retry_started and references the same refundId.
- Document the resolution: add a short internal note (what changed, why it happened) and update alert thresholds or runbooks if needed.
For example, if logs show error.code=50013 when posting the approval message, the bot likely lost Send Messages in the ticket channel due to a category overwrite change. Fix the overwrite on the Tickets category (or ensure the bot role has Administrator if that fits your security model), then retry the notification step. If logs show repeated 429s during bulk audit posting, reduce duplicate messages and consolidate staff updates into a single embed per refund state change.
A final operational note: treat refund automation as part of your support system, not a “set and forget” bot. Review logs weekly for trends (denial reasons, stuck workflows, permission denials). Even if you run a packaged solution like LD Refund System, you still benefit from consistent fields, correlation IDs, and alert rules around Discord permissions and ticket handling—those are the most common sources of real-world failures in FiveM communities.
Need a smarter refund flow?
LD Refund System automates Discord approvals, in-game claims, and audit logging so your staff stay focused on players.