Skip to content

Customer Payment Processing

Complete guide to customer-initiated appointment payment processing with automatic platform fee calculation and invoice generation.


Overview

The customer payment system provides secure payment processing for appointment bookings through Paper.id integration with:

  • Invoice Generation - Professional PDF invoices for customer records
  • Platform Fee Calculation - Automatic fee calculation based on subscription tier
  • Wallet Integration - Optional wallet balance application to reduce payment
  • Payment Gateway Integration - Unified Paper.id payment processing
  • Webhook Automation - Automatic payment confirmation and status updates
  • Multi-Method Support - Support for Indonesian payment methods (QRIS, E-Wallet, Bank Transfer, etc.)

Key Concepts:

  • Base Amount = Service price (what the merchant receives minus platform fee)
  • Platform Fee = Variable based on subscription tier (FREE: 8%, PRO: 5%, ENTERPRISE: 3%)
  • Total Amount = Base Amount + Platform Fee (what customer pays)
  • Wallet Application = Optional reduction from wallet balance (applied to base amount only)
  • Invoice = Professional document with payment URL and PDF download

Subscription Plan Fee Tiers

Platform fees are automatically calculated based on the tenant's subscription plan:

Subscription Plan Platform Fee Example on IDR 100,000
FREE 8% IDR 8,000 fee → IDR 108,000 total
PRO 5% IDR 5,000 fee → IDR 105,000 total
ENTERPRISE 3% IDR 3,000 fee → IDR 103,000 total

Fee Application:

  • Fee is calculated on the base appointment amount
  • Fee is added to the customer's payment amount
  • Merchant receives base amount minus platform fee after payment
  • Wallet balance (if used) reduces base amount before fee calculation

Example with Wallet Balance:

  • Appointment base: IDR 100,000
  • Wallet applied: IDR 20,000
  • New base: IDR 80,000
  • Platform fee (8% FREE tier): IDR 6,400
  • Customer pays: IDR 86,400
  • Wallet deducted: IDR 20,000

Process Appointment Payment

Initiate payment for a customer appointment with automatic fee calculation and invoice generation.

Endpoint

POST /api/v1/customer/payments/process-appointment

Authentication: Required (Customer JWT token)

Portal: 🟦 CUSTOMER (customer-only endpoint)

Request Body

{
  "appointment_id": "507f1f77bcf86cd799439011"
}

Parameters:

  • appointment_id (required) - ID of the appointment to pay for (24-character ObjectId)
  • payment_method (optional) - Payment method enum (defaults to QRIS if not specified)
  • Options: QRIS, BANK_TRANSFER, VIRTUAL_ACCOUNT, E_WALLET, CREDIT_CARD
  • use_wallet_balance (optional) - Apply wallet balance if available (default: false)
  • return_url (optional) - URL to redirect after payment completion

Response

{
  "payment_id": "507f1f77bcf86cd799439012",
  "status": "PENDING",
  "payment_url": "https://payper.id/short456",
  "invoice_url": "https://stg-v2.paper.id/abc123",
  "invoice_pdf_url": "https://stg-v2.paper.id/pdf/xyz789",
  "invoice_number": "INV-2025-001",
  "amount": 108000.00,
  "wallet_applied": null,
  "expires_at": "2025-01-17T10:30:00Z",
  "message": "Invoice created. Total: IDR 108,000.00 (Base: IDR 100,000.00 + Fee: IDR 8,000.00)"
}

Response Fields:

  • payment_id - Payment tracking record ID
  • status - Payment status (PENDING, COMPLETED, FAILED, CANCELLED)
  • payment_url - Paper.id payment URL for customer to complete payment
  • invoice_url - Invoice payment page URL
  • invoice_pdf_url - Direct PDF invoice download URL
  • invoice_number - Invoice reference number (e.g., INV-2025-001)
  • amount - Total amount customer must pay (base + platform fee - wallet)
  • wallet_applied - Amount deducted from wallet (if used)
  • expires_at - Payment link expiration timestamp (24 hours)
  • message - Detailed breakdown of payment amounts

Request Examples

Simplest form - only appointment_id required. System defaults to QRIS payment method.

{
  "appointment_id": "507f1f77bcf86cd799439011"
}

Use Case: Quick payment initiation without specifying payment method preferences.

With Wallet Balance

Apply customer wallet balance to reduce the payment amount.

{
  "appointment_id": "507f1f77bcf86cd799439011",
  "use_wallet_balance": true
}

Use Case: Customer wants to use stored wallet credits to partially or fully pay for appointment.

Full Request with All Options

Complete request with all optional parameters specified.

{
  "appointment_id": "507f1f77bcf86cd799439011",
  "payment_method": "CREDIT_CARD",
  "use_wallet_balance": true,
  "return_url": "https://app.example.com/payment-success"
}

Use Case: Advanced integration with specific payment method and return URL handling.


Payment Flow (10 Steps)

The payment process follows this complete sequence:

1. Validation

  • Verify appointment exists and belongs to authenticated customer
  • Check appointment status is PENDING or CONFIRMED
  • Ensure appointment hasn't been paid already
  • Validate tenant Paper.id configuration is enabled

2. Platform Fee Calculation

  • Retrieve tenant's subscription plan (FREE/PRO/ENTERPRISE)
  • Calculate platform fee percentage:
  • FREE: 8%
  • PRO: 5%
  • ENTERPRISE: 3%
  • Calculate fee amount: base_amount × fee_percentage

3. Wallet Balance Application (Optional)

  • If use_wallet_balance: true, retrieve customer wallet
  • Check wallet status is ACTIVE and balance > 0
  • Calculate wallet application: min(wallet_balance, base_amount)
  • Deduct from wallet immediately (refunded if payment fails)
  • Reduce base amount by wallet applied amount

4. Full Wallet Payment Shortcut

  • If wallet covers full base amount, skip invoice generation
  • Update appointment status to CONFIRMED immediately
  • Mark payment as COMPLETED with wallet_payment ID
  • Return success response without payment URL

5. Invoice Creation (Database)

  • Create invoice record in database with type APPOINTMENT
  • Generate unique invoice number (e.g., INV-2025-001)
  • Store line items for appointment services
  • Add platform fee as separate line item
  • Store metadata: customer_initiated: true, payment_flow: customer_booking

6. Customer Partner Verification

  • Ensure customer has Paper.id partner record
  • Create partner record if doesn't exist
  • Retrieve partner_number for Paper.id integration

7. Paper.id Invoice Generation

  • Create sales invoice in Paper.id using tenant credentials
  • Include customer details (name, email, phone, address)
  • Add appointment service line items
  • Add platform fee line item with subscription plan metadata
  • Configure callback webhook URL: /api/v1/webhooks/paper-invoice/tenant/{tenant_id}
  • Receive Paper.id invoice ID, PDF URL, and payment URL
  • Update database invoice with Paper.id references:
  • paper_invoice_id - Paper.id invoice ID
  • paper_invoice_url - Invoice page URL
  • paper_pdf_url - PDF download URL
  • paper_payment_url - Payment page URL

9. Create Payment Record

  • Create payment record with status PENDING
  • Link to appointment, customer, invoice, and tenant
  • Store payment method (or default to QRIS)
  • Store amount breakdown (base, fee, total)
  • Generate reference ID: APT-{appointment_id}-{timestamp}
  • Store metadata with customer_initiated: true

10. Return Payment URL

  • Return payment response with invoice URLs
  • Customer redirects to payment_url to complete payment
  • System awaits webhook confirmation from Paper.id
  • Webhook automatically updates payment and appointment status

Webhook Processing

After the customer completes payment on Paper.id, the webhook automatically processes the payment:

Webhook Endpoint

POST /api/v1/webhooks/paper-invoice/tenant/{tenant_id}

Automatic Actions on Payment Success

  1. Verify Payment Status - Validate status: paid in webhook payload
  2. Update Payment Record - Set payment status to COMPLETED
  3. Update Appointment - Set appointment status to CONFIRMED
  4. Update Invoice - Mark invoice as PAID with payment date
  5. Merchant Balance - Credit merchant account with base amount minus platform fee
  6. Customer Notification - Send booking confirmation email
  7. Staff Notification - Notify assigned staff of confirmed appointment
  8. Audit Log - Record payment event for compliance

Webhook Security

  • Tenant Isolation - Webhook URL includes tenant_id for automatic routing
  • Idempotency - Duplicate webhooks ignored based on invoice ID tracking
  • Amount Verification - Payment amount validated against invoice total
  • Invoice Validation - Invoice existence checked before processing
  • Tenant Validation - Ensure invoice belongs to correct tenant

Payment Statuses

The payment can transition through the following statuses:

Status Description Next Actions
PENDING Payment initiated, awaiting completion Customer must complete payment via payment_url
PROCESSING Payment in progress at gateway Wait for webhook confirmation
COMPLETED Payment successful, appointment confirmed Appointment ready, customer and staff notified
FAILED Payment failed at gateway Customer can retry with new payment request
CANCELLED Payment cancelled by customer Customer can create new payment request
REFUNDED Payment refunded to customer Refund processed, appointment cancelled

Error Handling

Common Error Responses

400 Bad Request - Payment Gateway Not Configured

{
  "detail": "Payment gateway not configured for this tenant. Please contact support or try alternative payment methods."
}

Cause: Tenant has not enabled or configured Paper.id integration Resolution: Contact tenant administrator to configure Paper.id credentials in tenant settings

403 Forbidden - Not Authorized

{
  "detail": "Not authorized to pay for this appointment"
}

Cause: Appointment does not belong to authenticated customer Resolution: Verify customer is paying for their own appointment

404 Not Found - Appointment Not Found

{
  "detail": "Appointment not found"
}

Cause: Appointment ID does not exist or was deleted Resolution: Verify appointment ID is correct and appointment exists

409 Conflict - Already Paid

{
  "detail": "Appointment already paid"
}

Cause: Appointment has existing completed payment Resolution: Check payment history, appointment is already confirmed

409 Conflict - Invalid Status

{
  "detail": "Cannot pay for appointment with status: CANCELLED"
}

Cause: Appointment status is not PENDING or CONFIRMED Resolution: Only pending or confirmed appointments can be paid

500 Internal Server Error - Invoice Creation Failed

{
  "detail": "Failed to create invoice"
}

Cause: Database error during invoice creation Resolution: Retry request, wallet automatically refunded if deducted

502 Bad Gateway - Paper.id API Error

{
  "detail": "Failed to create invoice in Paper.id: Connection timeout"
}

Cause: Paper.id API unavailable or network error Resolution: Retry request, invoice and wallet automatically rolled back


Subscription Plan Limitations

The appointment payment system has no usage limits based on subscription plans. However, the platform fee percentage varies by plan:

Platform Fee by Plan

Feature FREE Plan PRO Plan ENTERPRISE Plan
Platform Fee 8% 5% 3%
Fee on IDR 100k IDR 8,000 IDR 5,000 IDR 3,000
Appointment Payments Unlimited Unlimited Unlimited
Invoice Generation ✅ Included ✅ Included ✅ Included
PDF Invoices ✅ Included ✅ Included ✅ Included
Wallet Integration ✅ Included ✅ Included ✅ Included
Payment Methods All methods All methods All methods

Key Points:

  • All plans support unlimited appointment payments
  • Higher-tier plans reduce platform fees, increasing merchant profit margins
  • No restrictions on payment volume or invoice generation
  • All payment methods available on all plans

See Also:


Integration with Other Features

Appointment Management

Reference: Appointment Management

  • Payment links appointments to confirmed bookings
  • Appointment status automatically updated to CONFIRMED on payment success
  • Unpaid appointments can be cancelled by customer or system
  • Payment required before appointment is finalized

Invoice Management

Reference: Invoice Management

  • Professional PDF invoice generated for every payment
  • Invoice stored in database with Paper.id linkage
  • Customers can download invoices from payment history
  • Invoices include itemized service breakdown and platform fee

Customer Booking Flow

Reference: Customer Booking & Appointments

  • Payment is final step in booking process
  • Customer selects services → Staff → Time slot → Payment
  • Booking not confirmed until payment completed
  • Wallet balance can be applied during payment

Payment History

Reference: Payment History

  • All payments tracked in customer payment history
  • Platform fee and base amount displayed separately
  • Downloadable invoices linked to payment records
  • Filter by status, date range, payment type

Wallet Management

Reference: Customer Payments - Wallet Operations

  • Wallet balance can reduce appointment payment amount
  • Wallet deducted immediately, refunded if payment fails
  • Wallet top-up requires separate payment with platform fee
  • Wallet transactions tracked for audit

Subscription Plans

Reference: Subscription Management

  • Subscription plan determines platform fee percentage
  • Upgrading subscription reduces platform fees for customers
  • Fee calculation automatic based on active subscription
  • No manual configuration required

Best Practices

For Customers

DO:

  • Use wallet balance to reduce payment amounts when available
  • Download and save PDF invoices for records
  • Complete payment within 24 hours before link expires
  • Contact support if payment fails to retry

DON'T:

  • Share payment URLs with others
  • Attempt to pay for same appointment multiple times
  • Ignore payment expiration deadlines
  • Use expired or invalid payment methods

For Frontend Developers

DO:

  • Default to minimal request (only appointment_id) for simplicity
  • Display platform fee breakdown transparently to customers
  • Show wallet balance application option if customer has credits
  • Provide invoice PDF download button in payment confirmation
  • Handle payment URL redirect gracefully
  • Implement webhook listener for real-time status updates
  • Show payment expiration countdown timer

DON'T:

  • Require payment method selection upfront (QRIS is good default)
  • Hide platform fee from customers (transparency required)
  • Allow duplicate payment submissions
  • Ignore expires_at timestamp in UI
  • Cache payment URLs (they expire)

For Backend Developers

DO:

  • Always validate appointment ownership before payment
  • Use PaymentProcessor service for automatic fee calculation
  • Roll back wallet deduction if invoice creation fails
  • Log all Paper.id API responses for debugging
  • Implement idempotency checks in webhook handler
  • Store complete fee breakdown in payment metadata
  • Handle Paper.id API timeouts gracefully

DON'T:

  • Skip wallet refund on payment failure
  • Trust client-provided fee calculations
  • Process webhook without idempotency check
  • Expose Paper.id credentials in logs
  • Skip tenant validation in webhook processing
  • Allow payment for cancelled appointments

Testing Payment Flow

Prerequisites

  1. Customer Account - Active customer with valid JWT token
  2. Appointment - Pending appointment belonging to customer
  3. Tenant Configuration - Paper.id credentials configured and enabled
  4. ngrok Setup - Expose local server for webhook testing
ngrok http 8000

Test Scenario 1: Basic Payment (No Wallet)

Scenario: Customer pays for IDR 100,000 appointment on FREE plan

Step 1: Initiate Payment

curl -X POST http://localhost:8000/api/v1/customer/payments/process-appointment \
  -H "Authorization: Bearer CUSTOMER_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "appointment_id": "507f1f77bcf86cd799439011"
  }'

Expected Response:

{
  "payment_id": "507f1f77bcf86cd799439012",
  "status": "PENDING",
  "payment_url": "https://payper.id/short456",
  "invoice_url": "https://stg-v2.paper.id/abc123",
  "invoice_pdf_url": "https://stg-v2.paper.id/pdf/xyz789",
  "invoice_number": "INV-2025-001",
  "amount": 108000.00,
  "wallet_applied": null,
  "expires_at": "2025-01-17T10:30:00Z",
  "message": "Invoice created. Total: IDR 108,000.00 (Base: IDR 100,000.00 + Fee: IDR 8,000.00)"
}

Step 2: Complete Payment

  • Open payment_url in browser
  • Select payment method (QRIS, E-Wallet, etc.)
  • Complete payment using Paper.id test credentials

Step 3: Verify Webhook

  • Check server logs for webhook received: POST /api/v1/webhooks/paper-invoice/tenant/{tenant_id}
  • Verify payment status updated to COMPLETED
  • Verify appointment status updated to CONFIRMED

Step 4: Verify Results

curl -X GET http://localhost:8000/api/v1/customer/payments/history \
  -H "Authorization: Bearer CUSTOMER_JWT_TOKEN"

Expected: Payment with status COMPLETED, invoice linked


Test Scenario 2: Payment with Wallet Balance

Scenario: Customer has IDR 30,000 wallet balance, pays for IDR 100,000 appointment

Step 1: Check Wallet Balance

curl -X GET http://localhost:8000/api/v1/customer/payments/wallet/balance \
  -H "Authorization: Bearer CUSTOMER_JWT_TOKEN"

Expected Response:

{
  "balance": 30000.00,
  "currency": "IDR",
  "status": "ACTIVE",
  "platform_fee_percentage": 8.0
}

Step 2: Initiate Payment with Wallet

curl -X POST http://localhost:8000/api/v1/customer/payments/process-appointment \
  -H "Authorization: Bearer CUSTOMER_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "appointment_id": "507f1f77bcf86cd799439011",
    "use_wallet_balance": true
  }'

Expected Response:

{
  "payment_id": "507f1f77bcf86cd799439012",
  "status": "PENDING",
  "amount": 75600.00,
  "wallet_applied": 30000.00,
  "message": "Invoice created. Total: IDR 75,600.00 (Base: IDR 70,000.00 + Fee: IDR 5,600.00) - Wallet: IDR 30,000.00"
}

Calculation Breakdown:

  • Appointment base: IDR 100,000
  • Wallet applied: IDR 30,000
  • New base: IDR 70,000
  • Platform fee (8%): IDR 5,600
  • Customer pays: IDR 75,600

Step 3: Verify Wallet Deduction

curl -X GET http://localhost:8000/api/v1/customer/payments/wallet/balance \
  -H "Authorization: Bearer CUSTOMER_JWT_TOKEN"

Expected: Balance reduced to IDR 0.00 immediately


Test Scenario 3: Full Wallet Payment

Scenario: Customer has IDR 150,000 wallet balance, pays for IDR 100,000 appointment

Step 1: Initiate Payment

curl -X POST http://localhost:8000/api/v1/customer/payments/process-appointment \
  -H "Authorization: Bearer CUSTOMER_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "appointment_id": "507f1f77bcf86cd799439011",
    "use_wallet_balance": true
  }'

Expected Response:

{
  "payment_id": "wallet_payment",
  "status": "COMPLETED",
  "payment_url": null,
  "amount": 100000.00,
  "wallet_applied": 100000.00,
  "expires_at": null,
  "message": "Paid with wallet balance: IDR 100,000.00"
}

Key Observations:

  • No invoice generated (full wallet payment)
  • No payment URL (already completed)
  • Appointment status immediately CONFIRMED
  • No platform fee charged (wallet already includes fee)
  • Remaining wallet balance: IDR 50,000

Troubleshooting

Symptoms: Customer tries to pay but link shows "Invoice expired"

Checks:

  1. Check expires_at timestamp in payment response
  2. Verify current time < expiry time (24 hours from creation)

Fix: - Create new payment request for same appointment - Previous payment automatically cancelled - New invoice and payment URL generated

Webhook Not Received

Symptoms: Payment completed but appointment still PENDING

Checks:

  1. Verify ngrok is running: ngrok http 8000
  2. Check Paper.id webhook URL configuration includes tenant_id
  3. Review ngrok web interface: http://localhost:4040 for webhook requests
  4. Check server logs for webhook processing errors

Fix:

  • Manually trigger webhook from Paper.id dashboard (Resend Webhook button)
  • Or manually update appointment and payment status via admin endpoint

Wallet Not Refunded on Failure

Symptoms: Payment failed but wallet balance not restored

Checks:

  1. Check wallet transaction history for refund transaction
  2. Verify payment status is FAILED or CANCELLED
  3. Review server logs for rollback errors

Fix:

  • Contact support to manually issue wallet refund
  • Provide payment_id and customer_id for investigation

Platform Fee Incorrect

Symptoms: Fee amount doesn't match expected subscription tier rate

Checks:

  1. Verify tenant subscription plan: GET /api/v1/subscriptions/current
  2. Check subscription is active status
  3. Review payment metadata for subscription_plan field

Fix:

  • Ensure tenant subscription is active and not expired
  • Upgrade subscription if fee tier needs adjustment
  • Fee calculated at time of payment, not retroactively changed

API Reference Summary

Field Type Required Description
appointment_id string Yes 24-character ObjectId of appointment
payment_method enum No Payment method (default: QRIS)
use_wallet_balance boolean No Apply wallet balance (default: false)
return_url string No Redirect URL after payment

Response Fields:

Field Type Description
payment_id string Payment tracking ID
status enum Payment status
payment_url string Paper.id payment URL
invoice_url string Invoice page URL
invoice_pdf_url string PDF download URL
invoice_number string Invoice reference number
amount decimal Total payment amount
wallet_applied decimal Wallet balance used
expires_at datetime Payment link expiration
message string Payment breakdown message


Next Steps:

  1. Create customer appointment: Customer Booking
  2. Initiate payment: POST /api/v1/customer/payments/process-appointment
  3. Customer completes payment via payment_url
  4. System automatically confirms appointment via webhook
  5. View payment history: GET /api/v1/customer/payments/history
  6. Download invoice PDF from payment record