FiveM Refund Request Intake Form Design Using Discord Modals and Validation
Build a refund intake form that captures the right data, blocks bad submissions, and routes requests to the right staff—without turning your support channels into a mess.
Refund requests are a high-friction support case in FiveM communities because they mix player emotion, payment details, and policy enforcement. A good intake form reduces back-and-forth, prevents missing evidence, and creates an audit trail staff can trust. Discord modals are ideal for this: they collect structured input at the moment a user asks for help, before the conversation drifts into DMs or public channels. This article focuses on practical design: what fields to ask for, how to validate them, and how to connect submissions to tickets, logs, and staff roles.
“A refund policy is only enforceable when your intake process captures the facts consistently.”
Start with a refund policy checklist and map it to fields
Before you build a modal, write down the minimum information you need to approve or deny a refund under your rules. If your policy says “no refunds after 48 hours” or “chargebacks result in a ban,” your form must capture timestamps and transaction identifiers. If you require proof (e.g., store receipt, in-game purchase record, or clip), your form must capture links and specify what is acceptable. Treat the modal as a policy-to-data mapping exercise: each rule should correspond to at least one field or validation step.
- Purchase platform (Tebex, Patreon, Stripe, etc.) and transaction/reference ID
- FiveM identifiers: Rockstar license, Steam hex, and/or Discord ID (depending on how you identify players)
- Date/time of purchase and approximate time zone
- Package or product name (exact store listing)
- Reason category (e.g., accidental purchase, product not delivered, server downtime)
- Evidence links (receipt screenshot, clip, ticket history link)
Keep the first modal focused on intake, not adjudication. You can ask for a short explanation, but don’t ask users to argue their case across multiple long fields. If you need more context, collect it later inside the ticket where staff can ask targeted questions. This reduces abandonment and keeps the modal within Discord’s component limits.
Design the Discord modal: field types, constraints, and naming
Discord modals support text inputs with short or paragraph styles. Use short fields for IDs and dates, and one paragraph field for the user’s explanation. Name fields exactly how staff refer to them in reviews and logs (for example, “Tebex Transaction ID” rather than “Order number”). Consistent naming makes it easier to search logs and correlate with store dashboards.
- Trigger: a “Request Refund” button in a dedicated channel (e.g., #support-start) visible to @Verified but not @Guest.
- Modal title: “Refund Request Intake”.
- Field 1 (short): “Transaction ID / Reference” (required).
- Field 2 (short): “FiveM Identifier (license/steam/discord)” (required).
- Field 3 (short): “Purchase Date (YYYY-MM-DD)” (required).
- Field 4 (short): “Product/Package Name” (required).
- Field 5 (paragraph): “Reason + what you expected to receive” (required, 50–800 chars).
For FiveM-specific operations, the identifier field matters. If your staff tools key off Rockstar license (license:xxxxxxxx) but players only know their Discord tag, you’ll waste time. Consider accepting multiple formats in one field, then validating and normalizing them in your bot (for example, extract a steam hex if present). If you run a whitelist or use ACE permissions in-game, align the identifier you collect with what you can verify quickly in your admin tooling.
Practical tip: reduce invalid IDs with examples
In each field’s placeholder text, show one valid example: “txn_12345ABC” or “license:2f3a…”. Players copy patterns. This alone cuts “N/A” submissions without adding extra rules.
Validation rules that actually prevent bad submissions
Discord does not provide server-side regex validation inside the modal UI, so your bot must validate after submission and respond with clear, actionable errors. Do not silently accept malformed data and “fix it later.” Your goal is to stop low-quality requests at the edge and keep staff queues clean.
- Required fields: reject empty or whitespace-only input.
- Length bounds: enforce minimums (e.g., reason >= 50 chars) to prevent “refund pls”.
- Format checks: validate date format (YYYY-MM-DD) and reject impossible dates.
- Identifier parsing: detect at least one supported identifier pattern (license:, steam:, discord numeric ID).
- URL checks: if you accept evidence links, allow only https:// and optionally restrict to trusted hosts (Discord CDN, Streamable, YouTube).
- Duplicate detection: if the same transaction ID is already in an open ticket, block the submission and link the existing ticket.
When validation fails, reply ephemerally with a short list of fixes and a button to re-open the modal. For example: “Transaction ID looks too short (min 8). Purchase Date must be YYYY-MM-DD.” This keeps the user in one guided flow. If you already use an automated workflow like LD Refund System for tracking outcomes, validation should happen before creating any permanent case record so your dataset stays clean and searchable.
Routing: tickets, roles, and permissions that protect sensitive data
Refund intake often includes payment references and potentially personal information. Route submissions into private tickets with strict permission overwrites. A common pattern is: create a channel under a “Refund Tickets” category, set @everyone to deny View Channel, allow the requester, and allow only the staff roles that handle refunds (e.g., @Support, @Finance, @Admin). Avoid giving broad access to @Moderator if they do not need transaction details.
Use Discord roles and permissions intentionally:
- @Verified: can press the “Request Refund” button.
- @Support: can view and respond in refund tickets, but cannot close as “approved” if you separate duties.
- @Finance: can approve/deny and post final outcomes.
- @Admin: can override and view logs for disputes.
- Bot role: must have Manage Channels, Manage Roles (optional), Send Messages, Embed Links, and Read Message History in the ticket category.
Practical tip: separate “support” from “decision” permissions
If you have enough staff, split duties: support collects missing info, finance/admin decides. Implement this with role-gated buttons (Approve/Deny) visible only to @Finance/@Admin. It reduces inconsistent decisions and protects staff from social pressure.
Logging and audit trails: what to store and where
Refund decisions are frequently revisited: players appeal, staff changes, or a chargeback occurs weeks later. Build an audit trail from day one. At minimum, log the raw intake payload, the normalized fields, and every state change (opened, awaiting info, approved, denied, closed). Keep logs immutable and separate from the ticket conversation so deletions or edits do not erase history.
A practical Discord setup is a locked #refund-logs channel where only @Admin and the bot can post. Log entries should include: ticket channel link, requester Discord ID, transaction ID, timestamps, and the staff member who changed status. If you use webhooks, sign or restrict them to prevent spoofed log messages. If you already run a refund workflow tool like LD Refund System, align your log fields with its case identifiers so you can reconcile Discord actions with your internal tracking.
- On modal submit: post a log entry “Intake received” with the parsed fields and a hash of the raw content (optional).
- On ticket creation: log the new channel ID and category.
- On staff action: log button presses (Approve/Deny/Need More Info) with staff Discord ID.
- On closure: log final outcome, reason code, and any store-side action reference (e.g., refund confirmation ID).
Operational safeguards: rate limits, duplicates, and edge cases
Even well-designed forms get abused or spammed. Add guardrails that protect staff time without blocking legitimate users. Rate-limit refund submissions per user (for example, one open refund ticket at a time, or one submission every 30 minutes). Detect duplicates by transaction ID and by user ID. If a user is banned or flagged (e.g., has a “Chargeback” role), block the modal submission and direct them to a policy channel instead of opening tickets.
- User has no “Verified” role: deny and prompt them to complete verification first.
- Transaction ID already exists in an open/closed case: show the existing ticket link or case status.
- User has “Chargeback” or “Refund Abuser” role: block intake and notify @Admin privately.
- Evidence link missing for categories that require it (e.g., “Product not delivered”): send “Need More Info” response and do not create a ticket until provided.
- Discord outages or bot restarts: queue submissions and confirm receipt to the user once processed.
Finally, test the flow with real staff. Run through scenarios: a valid Tebex purchase, a missing transaction ID, a user who only provides a Steam name, and a user who submits the same request twice. Measure success by how often staff can make a decision without asking a follow-up question. If follow-ups are common, adjust the modal fields and validation—your intake form is a living part of your Discord integration, not a one-time setup.
Need a smarter refund flow?
LD Refund System automates Discord approvals, in-game claims, and audit logging so your staff stay focused on players.