Skip to main content

Payment Approval (P2P Manual)

Venmo and CashApp P2P payments require manual admin review before an order is marked confirmed.

Workflow

  1. Customer places an order using a P2P payment method (e.g. Venmo, Cash App, Zelle, Chime). The Discord checkout now displays each method's human-readable name and icon from the payment-method registry rather than raw enum strings like VENMO_P2P.
  2. The ordering flow calls submitForApproval on the payment record, transitioning it to awaiting_admin_approval.
  3. A notification embed (with Approve and Reject buttons) is posted to the admin channel.
  4. An admin clicks Approve or Reject.

Status transitions

pending_payment → awaiting_admin_approval → confirmed
→ rejected

Transitions are guarded: only admins may confirm or reject; double-clicking is idempotent (first action wins).

Admin panel actions

In the AdminJS panel under Commerce → Payments, two record-level actions are available when a payment is in awaiting_admin_approval status:

ActionForm fieldResult
Confirm PaymentcustomerReferenceNoteTransitions to confirmed, creates audit log entry, emits payment.confirmed
Reject PaymentrejectionReasonTransitions to rejected, creates audit log entry, emits payment.rejected

Both actions are gated to the admin role in AdminJS.

Audit trail

Every confirmation and rejection creates an AuditLog record:

FieldValue
actionpayment.confirm or payment.reject
entityTypePayment
entityIdpayment ID
actorIdAdminJS user ID
meta{ referenceNote } or { reason }

Events emitted

EventWhenDownstream consumers
payment.confirmedTransition to confirmedNotifications, RBAC role grant, Fulfillment
payment.rejectedTransition to rejectedNotifications, Order cancellation

BTC via NOWPayments — no admin action required

BTC_NOWPAYMENTS payments confirm automatically when the blockchain transaction is detected by the NOWPayments IPN callback. The approval workflow above does not apply to these payments — they never enter awaiting_admin_approval. Admins can monitor these payments in Commerce → Payments by filtering on method = BTC_NOWPAYMENTS. The providerRef field on the payment record stores the NOWPayments invoice ID for cross-referencing with the NOWPayments dashboard.