Skip to main content
Retail Pay is a merchant-initiated payment flow in which the merchant scans a dynamic code displayed by the user inside the Rebell SuperApp. The merchant backend uses the scanned paymentAuthCode to create and authorize a payment request through Rebell’s Payment API. This flow is designed for in-store payments, POS systems, kiosks, and any physical checkout environment where the merchant initiates the transaction.

When to Use Retail Pay

Ideal use cases:
  • In-store POS systems with barcode scanners
  • Mobile POS applications
  • Self-service kiosks
  • Physical checkout counters
  • Fast, real-time authorization flows
  • Alipay/WeChat “scan-to-pay” style experience

Payment Flow

1

User Displays Code

Customer opens the Rebell SuperApp and displays their dynamic payment code (QR or barcode)
2

Merchant Scans

Merchant POS or terminal scans the code to capture the paymentAuthCode
3

API Call

Merchant backend receives the paymentAuthCode and calls Rebell’s Retail Pay API
4

Process Payment

Rebell processes the payment and returns:
  • SUCCESS (final)
  • PROCESSING (requires polling)
  • FAIL (rejected or invalid code)
5

Webhook Notification

Rebell sends a webhook notification with the final payment result
6

Complete Transaction

Merchant backend updates the POS and completes the sale

Sequence Diagram

API Specification

Endpoint

POST /v1/payments/retailPay

Request Headers

Include standard authentication headers:
Client-Id: your-client-id
Request-Time: 2024-01-10T12:22:30Z
Signature: algorithm=SHA256withRSA, keyVersion=1, signature=...
Content-Type: application/json

Request Body

productCode
string
required
Payment product type assigned by Rebell
paymentRequestId
string
required
Merchant-generated unique ID (idempotency key). Must be unique per transaction.
paymentAuthCode
string
required
Dynamic code scanned from the user’s app
paymentAmount
object
required
Payment amount details
order
object
Order details
Example Request:
{
  "productCode": "51051000101000100040",
  "paymentRequestId": "pos-20240321-0001",
  "paymentAuthCode": "281012020262467128",
  "paymentAmount": {
    "currency": "EUR",
    "value": 1250
  },
  "order": {
    "orderDescription": "Cappuccino and croissant",
    "merchant": {
      "store": {
        "externalStoreId": "STORE-001"
      }
    }
  }
}

Response Parameters

result
object
required
Payment result details
paymentId
string
Rebell’s unique payment identifier (present on SUCCESS or PROCESSING)
Response Examples:
{
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S"
  },
  "paymentId": "20240321000123456789"
}

Handling Response Status

When Rebell Returns SUCCESS

Payment is authorized and final
  • Payment is complete and settled
  • You may immediately print receipt and deliver goods
  • No need to wait for webhook (though you’ll still receive one)

When Rebell Returns PROCESSING

Payment is pending - action requiredMerchant MUST:
  • Start polling inquiryPayment API every 3-5 seconds
  • Continue polling for up to 30 seconds or until webhook is received
  • Treat the payment as PENDING until resolved
  • Display “Awaiting confirmation…” message on POS
Example Polling Logic
async function handleProcessingPayment(paymentId) {
  const maxAttempts = 10; // 30 seconds with 3-second intervals
  let attempts = 0;

  while (attempts < maxAttempts) {
    await new Promise(resolve => setTimeout(resolve, 3000)); // Wait 3 seconds

    const status = await inquiryPayment(paymentId);

    if (status.resultStatus === 'S') {
      return 'SUCCESS';
    } else if (status.resultStatus === 'F') {
      return 'FAILED';
    }

    attempts++;
  }

  return 'TIMEOUT'; // Webhook will provide final status
}

When Rebell Returns FAIL

Error Scenarios & Recovery

ResultCode: INVALID_CODECause: The scanned paymentAuthCode is invalid or expiredRecovery:
  • Ask the user to refresh their payment code in the SuperApp
  • Retry by scanning the new code
  • Payment codes typically expire after 60 seconds
ResultCode: NEED_RISK_CHALLENGECause: Rebell requires additional risk verificationRecovery:
  • Display on POS: “Please confirm the payment in your app”
  • Wait for webhook notification or poll inquiry API
  • User must approve payment in their SuperApp
ResultCode: PAYMENT_REJECTEDCause: User explicitly denied the transaction in the appRecovery:
  • Inform customer that payment was declined
  • Request alternative payment method
  • Do not retry automatically
Cause: Network error or timeout during API callRecovery:
  • Retry the request (safe due to paymentRequestId idempotency)
  • Never create a new paymentRequestId for the same transaction
  • If retries fail, wait for webhook notification

Security Considerations

Critical Security Requirements:
  • ✅ Always use HTTPS between POS → backend and backend → Rebell
  • ✅ Never expose paymentAuthCode in logs publicly
  • ✅ Use short paymentRequestId TTLs in your database
  • ✅ Validate webhook signatures (see Webhooks)
  • ✅ Implement fraud checks (store/device mapping, rate limits)
  • ✅ Ensure POS devices are in secure environments

Best Practices

  • Store paymentAuthCode only temporarily during transaction
  • Log transaction attempts without exposing sensitive codes
  • Implement device authentication for POS terminals
  • Monitor for unusual scanning patterns or high failure rates
  • Set transaction amount limits per merchant policy

UX Recommendations

Create a smooth checkout experience:

Visual Confirmation

POS should visually confirm when scanning succeeded with clear feedback

Processing Indicator

If PROCESSING, show a spinner with “Awaiting confirmation…” message

Error Messages

Display clear, actionable error messages when codes are expired or unreadable

Timeout Handling

Avoid blocking the cashier longer than 30-40 seconds. Offer alternatives.
Optional enhancements:
  • Sound/vibration feedback when payment succeeds
  • Automatic receipt printing on success
  • Display payment amount before scanning for verification

Testing Checklist

Before going live, test these scenarios in sandbox:

Next Steps