Skip to main content

Order & Payment Approval

This guide walks an admin through what happens on the admin channel when a customer submits an order, and how to approve or reject the payment from inside Discord.

What you see when an order is submitted

When a guild member confirms an order via /order, two things happen immediately:

  1. A DM goes to the customer with their order number and payment instructions for the method they picked.
  2. An admin-channel embed is posted to the channel configured as announcementChannelId (or adminChannelId as a fallback) on the tenant's BotConfig.

The admin-channel embed looks like this:

  • Title: Payment Awaiting Approval — Order <orderNumber>
  • Fields: Customer mention, payment method, amount, payment ID, and the customer's reference note (typically the order number).
  • Two buttons: Approve Payment (green) and Reject Payment (red).

Approving a payment

Click Approve Payment. The bot:

  1. Verifies you hold an admin role (fails with an ephemeral error otherwise).
  2. Transitions the payment from awaiting_admin_approvalconfirmed.
  3. Emits payment.confirmed. The notifications consumer then DMs the customer "Payment received!" and the order moves into fulfillment.
  4. Posts an ephemeral confirmation to you and a thread message in the order channel so other staff see the action.

If you click twice, the second click is a no-op — only the first transition wins.

Rejecting a payment

Click Reject Payment. A modal opens asking for a rejection reason.

When you submit the modal:

  1. Admin role is re-verified.
  2. The payment transitions to rejected and emits payment.rejected.
  3. The order consumer releases the inventory reservation and transitions the order to CANCELLED.
  4. The notifications consumer DMs the customer with the rejection reason and posts an audit entry to the admin channel.

The reject reason is stored on the payment record (rejectionReason) for the audit trail.

Operational notes

  • Idempotency. Both approve and reject are idempotent at the service layer. If a duplicate event is delivered, the second delivery is a no-op.
  • Role gating. Only members with a role listed in BotConfig.adminRoleIds can approve or reject.
  • Audit trail. Every transition updates approverUserId, approvedAt / rejectedAt, and rejectionReason (when rejected). Cancelled orders gain a note line on Order.notes.
  • Refunds. For already-approved payments, use /refund to reverse — see the Order Management guide.