Skip to main content
The Inquiry Payment API allows your backend to retrieve the current status of a payment previously created using Retail Pay, QR Order Pay, or Link Pay. This API is essential for handling PROCESSING states and ensuring order synchronization when webhook delivery is delayed or temporarily unavailable.
Important LimitationInquiry MUST NOT be used as a substitute for webhooks. Webhooks remain the source of truth; Inquiry is a supplementary polling mechanism.

When to Use Inquiry

Appropriate use cases:
  • Rebell returns PROCESSING for Retail Pay or QR Order
  • User initiated a Link Pay flow but the webhook has not yet arrived
  • Merchant needs to confirm payment status after network interruptions
  • Merchant receives ambiguous or delayed responses
  • Merchant needs status checks during POS timeout handling

Inquiry Flow Overview

1

Create Payment

Merchant creates a payment using Retail Pay, QR Order, or Link Pay
2

Receive Payment ID

Rebell returns a paymentId
3

Start Polling (if needed)

If the initial response is PROCESSING, merchant begins polling Inquiry
4

Poll at Intervals

Merchant calls Inquiry every 3-5 seconds, up to a defined timeout window
5

Receive Status

Inquiry returns one of: SUCCESS, FAIL, or PROCESSING
6

Webhook Delivery

Webhook eventually delivers the final status
7

Update Order

Merchant system updates the order state

Sequence Diagram

API Specification

Endpoint

POST /v1/payments/inquiryPayment

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

paymentId
string
required
The payment identifier returned during initial payment creation
paymentRequestId
string
Merchant’s internal order ID (recommended for validation)
Example Request:
{
  "paymentId": "2024032100123456",
  "paymentRequestId": "checkout-20240321-987"
}

Response Parameters

result
object
required
API call result details
paymentStatus
string
required
The current status of the payment: SUCCESS, FAIL, or PROCESSING
paymentId
string
The payment identifier
paymentAmount
object
Payment amount details (present on SUCCESS)
paymentTime
string
ISO 8601 timestamp of when payment was completed (present on SUCCESS)
failureReason
string
Reason for payment failure (present on FAIL)
Response Examples:
{
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S"
  },
  "paymentStatus": "SUCCESS",
  "paymentId": "2024032100123456",
  "paymentAmount": {
    "currency": "EUR",
    "value": 499
  },
  "paymentTime": "2024-03-21T10:15:33Z"
}

Payment Status Values

StatusMeaningFinal State
SUCCESSPayment fully authorized and finalYes
FAILPayment rejected or expiredYes
PROCESSINGTransaction is still being confirmedNo
Only SUCCESS or FAIL represent final states. PROCESSING means polling should continue until timeout or webhook arrival.

Handling Inquiry Responses

When Inquiry Returns SUCCESS

Payment completed - take action immediately
  • Immediately mark order as PAID
  • Stop polling
  • Do not retry the same payment
  • Wait for webhook to confirm integrity (but not required to proceed)

When Inquiry Returns FAIL

When Inquiry Returns PROCESSING

Payment pending - continue pollingMerchant SHOULD:
  • Continue polling every 3-5 seconds
  • Stop after a maximum of 30-45 seconds
  • Display pending UI to user
  • Wait for webhook if user is still active

Timeout Handling

If Inquiry returns PROCESSING for too long:
If webhooks active   → Stop polling and wait for webhook
If webhooks down     → Notify POS operator / user to retry

Polling Implementation

Here’s a recommended polling implementation:
Polling Logic
async function pollPaymentStatus(paymentId, paymentRequestId) {
  const MAX_ATTEMPTS = 10;        // 30-45 seconds total
  const POLL_INTERVAL = 3000;     // 3 seconds between polls
  let attempts = 0;

  while (attempts < MAX_ATTEMPTS) {
    const response = await rebellAPI.inquiryPayment({
      paymentId,
      paymentRequestId
    });

    switch (response.paymentStatus) {
      case 'SUCCESS':
        return {
          status: 'paid',
          paymentTime: response.paymentTime,
          amount: response.paymentAmount
        };

      case 'FAIL':
        return {
          status: 'failed',
          reason: response.failureReason
        };

      case 'PROCESSING':
        // Continue polling
        attempts++;
        await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL));
        break;
    }
  }

  // Timeout reached - wait for webhook
  return {
    status: 'pending',
    message: 'Polling timeout - waiting for webhook confirmation'
  };
}

Error Scenarios & Recovery

Cause: Inquiry called with invalid or unknown paymentIdRecovery:
  • Check mapping between paymentRequestId and paymentId
  • Ensure correct environment (sandbox vs production)
  • Verify the payment was actually created
Cause: Request body invalidRecovery:
  • Ensure correct JSON serialization
  • Validate presence of paymentId
  • Check for malformed request body
Cause: Credentials do not match payment’s merchantRecovery:
  • Verify Client-Id used in signing
  • Ensure key rotation did not switch to wrong key
  • Confirm the payment belongs to your merchant account
Cause: Inquiry called too frequentlyRecovery:
  • Limit polling interval to minimum 3 seconds
  • Never exceed 10-15 attempts per transaction
  • Implement exponential backoff if needed

Security Considerations

Security Best Practices:
  • ✅ Inquiry does not replace secure webhooks
  • ✅ Use request signing for every Inquiry call
  • ✅ Validate that paymentId belongs to your merchant
  • ✅ Verify paymentRequestId matches expected order
  • ✅ Set strict rate limits on Inquiry endpoints on merchant backend
  • ✅ Log all PROCESSINGSUCCESS / FAIL transitions
  • ✅ Never expose Inquiry endpoints directly to frontend

UX Recommendations

For point-of-sale and merchant applications:
  • Display “Waiting for confirmation…” for PROCESSING
  • Auto-refresh UI on SUCCESS or FAIL
  • Do not block cashiers with long waits (max 30-45 seconds)
  • If timeout occurs, show: “We are verifying your payment. Please wait or try again.”
  • Provide manual “Check Status” button for retries

Complete Integration Example

Full Example
// Backend: Inquiry endpoint wrapper
app.post('/api/payments/:paymentId/status', async (req, res) => {
  const { paymentId } = req.params;
  const order = await getOrderByPaymentId(paymentId);

  if (!order) {
    return res.status(404).json({ error: 'Order not found' });
  }

  // If already resolved, return cached status
  if (order.status === 'paid' || order.status === 'failed') {
    return res.json({
      status: order.status,
      paymentId: order.paymentId
    });
  }

  // Query Rebell for current status
  try {
    const response = await rebellAPI.inquiryPayment({
      paymentId: order.paymentId,
      paymentRequestId: order.paymentRequestId
    });

    // Update order if status changed
    if (response.paymentStatus === 'SUCCESS') {
      await updateOrder(order.id, {
        status: 'paid',
        paymentTime: response.paymentTime
      });
    } else if (response.paymentStatus === 'FAIL') {
      await updateOrder(order.id, {
        status: 'failed',
        failureReason: response.failureReason
      });
    }

    res.json({
      status: response.paymentStatus.toLowerCase(),
      paymentId: response.paymentId,
      ...(response.paymentAmount && { amount: response.paymentAmount }),
      ...(response.failureReason && { reason: response.failureReason })
    });
  } catch (error) {
    console.error('Inquiry failed:', error);
    res.status(500).json({ error: 'Unable to check payment status' });
  }
});

// Frontend: Poll for status after payment initiation
async function waitForPaymentCompletion(paymentId) {
  const maxAttempts = 10;
  let attempts = 0;

  updateUI('processing', 'Verifying payment...');

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

    const { status, reason } = await fetch(`/api/payments/${paymentId}/status`)
      .then(r => r.json());

    if (status === 'paid' || status === 'success') {
      updateUI('success', 'Payment completed!');
      return true;
    }

    if (status === 'failed' || status === 'fail') {
      updateUI('error', `Payment failed: ${reason || 'Please try again'}`);
      return false;
    }

    attempts++;
    updateUI('processing', `Verifying payment... (${attempts}/${maxAttempts})`);
  }

  // Timeout - rely on webhook
  updateUI('pending', 'Still verifying. You will be notified when complete.');
  return null;
}

Testing Checklist

Test these scenarios in sandbox before going live:

Next Steps