Skip to main content
Link Pay is a user-initiated, app-to-app or browser-to-app payment flow. The merchant backend creates a payment request and receives a redirect URL (or deep link) that sends the user to the Rebell SuperApp, where they authorize the payment. The user is then returned to the merchant application or website. This flow is ideal for mobile apps, web checkout, and hybrid experiences where the merchant wants Rebell to handle the payment UI.
Ideal use cases:
  • User interacts through a mobile app or mobile web flow
  • Merchant wants to offload the payment UI to Rebell
  • Flow requires strong user authentication within the SuperApp
  • Checkout should redirect seamlessly to Rebell and return afterward
Common scenarios:
  • App-based purchases
  • Web checkout (scan-to-app or auto redirect)
  • Subscription or recurring services (first-time payment)
  • On-demand services (mobility, taxis, ride-hailing)
  • Digital goods or top-up flows

Payment Flow

1

User Initiates Checkout

User initiates checkout in the merchant app or website
2

Create Link Pay Order

Merchant backend calls Rebell linkPayCreate API
3

Receive Redirect URLs

Rebell responds with:
  • A redirect URL (deep link)
  • App-to-app deep links (Android / iOS)
  • Optional fallback links (browser-based)
4

Redirect User

Merchant redirects the user to Rebell using the appropriate link
5

User Confirms Payment

User reviews and confirms payment inside the Rebell SuperApp
6

Process Payment

Rebell processes the transaction
7

Webhook Notification

Merchant receives webhook notification with the final payment status
8

Complete Order

Merchant app or website updates the UI and completes the order

Sequence Diagram

API Specification

Endpoint

POST /v1/payments/linkPayCreate

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.
paymentAmount
object
required
Payment amount details
order
object
Order details
settlementStrategy
object
Settlement configuration
Example Request:
{
  "productCode": "51051000101000100040",
  "paymentRequestId": "checkout-20240321-987",
  "paymentAmount": {
    "currency": "EUR",
    "value": 499
  },
  "order": {
    "orderDescription": "Monthly subscription - Premium plan",
    "merchant": {
      "store": {
        "externalStoreId": "STORE-77"
      }
    }
  },
  "settlementStrategy": {
    "settlementCurrency": "EUR"
  }
}

Response Parameters

result
object
required
Result details
redirectUrl
string
Deep link to open Rebell SuperApp directly
Platform-specific app link metadata
paymentId
string
Payment identifier to be used for inquiry or reconciliation
Example Response:
{
  "result": {
    "resultCode": "SUCCESS",
    "resultStatus": "S"
  },
  "redirectUrl": "rebell://pay?orderToken=abcedf123...",
  "appLinks": {
    "android": {
      "applicationId": "com.rebell.superapp",
      "targetPath": "pay",
      "shortUrl": "https://app.rebell.com/p/abc123"
    },
    "ios": {
      "bundleId": "com.rebell.superapp",
      "targetPath": "pay",
      "shortUrl": "https://app.rebell.com/p/abc123"
    }
  },
  "paymentId": "2024032100123456"
}

Redirect Logic

Critical Implementation DetailMerchant frontend must implement a structured redirect strategy based on the user’s device and context.
For users on native mobile apps:Use one of the following:
  • redirectUrl (deep link)
  • appLinks.android.shortUrl (Android)
  • appLinks.ios.shortUrl (iOS)
// React Native example
import { Linking, Platform } from 'react-native';

async function redirectToRebell(response) {
  const url = Platform.select({
    ios: response.appLinks.ios.shortUrl,
    android: response.appLinks.android.shortUrl,
    default: response.redirectUrl
  });

  const canOpen = await Linking.canOpenURL(url);
  if (canOpen) {
    await Linking.openURL(url);
  }
}

Merchant Behavior Rules

Merchant MUST

Merchant MUST NOT

Critical Don’ts:
  • ❌ Allow paymentRequestId reuse
  • ❌ Embed private keys in frontend code
  • ❌ Infer payment status from redirect return URL only
  • ❌ Treat the initial Link Pay API response as final

Handling Payment Completion

Upon Receiving Webhook SUCCESS

Payment completed successfullyActions to take:
  • Mark order as PAID in your system
  • Redirect user to success screen
  • Trigger fulfillment flow
  • Send confirmation to customer

Upon Receiving Webhook FAIL

Error Scenarios & Recovery

Cause: Order in invalid or closed stateRecovery:
  • Generate a new paymentRequestId
  • Ensure backend order lifecycle is correct
  • Verify order hasn’t already been paid or canceled
Cause: Another payment is already processing for the same requestRecovery:
  • Use inquiry API to check existing payment status
  • Prevent duplicate link generation
  • Wait for the current payment to complete or fail
Cause: User must complete additional verification inside RebellRecovery:
  • Display: “Please complete verification in Rebell”
  • Wait for webhook notification
  • Do not retry or create new payment request
Cause: Internal processing failureRecovery:
  • Retry with the same paymentRequestId (idempotent)
  • If retries fail, wait and try again later
  • Contact support if issue persists
Cause: User closed the app or navigated away before completingRecovery:
  • Check payment status via inquiry API
  • If still pending, allow user to retry redirect
  • Payment may still complete via webhook

Security Considerations

Security Best Practices:
  • ✅ Do not expose backend logic in redirect URLs
  • ✅ Always verify webhook signatures before updating order status
  • ✅ Keep redirect URL tokens confidential
  • ✅ Ensure environment separation (sandbox vs production)
  • ✅ Validate user session before creating Link Pay order
  • ✅ Never store or log sensitive payment tokens
  • ✅ Use HTTPS for all communications

UX Recommendations

Create optimal experiences based on the user’s context:
For merchant mobile apps:
  • Auto-redirect without confirmation prompt
  • Show loading spinner until redirect is handled
  • After return, display pending state until webhook arrives
  • Handle app-not-installed gracefully

Implementation Example

Here’s a complete implementation example:
Complete Flow Example
// Backend: Create Link Pay order
app.post('/api/checkout/link-pay', async (req, res) => {
  const { orderId } = req.body;
  const order = await getOrder(orderId);

  const response = await rebellAPI.linkPayCreate({
    productCode: process.env.REBELL_PRODUCT_CODE,
    paymentRequestId: `checkout-${order.id}-${Date.now()}`,
    paymentAmount: {
      currency: 'EUR',
      value: order.totalCents
    },
    order: {
      orderDescription: order.description,
      merchant: {
        store: {
          externalStoreId: process.env.STORE_ID
        }
      }
    },
    settlementStrategy: {
      settlementCurrency: 'EUR'
    }
  });

  // Store payment reference
  await updateOrder(order.id, {
    paymentId: response.paymentId,
    paymentRequestId: `checkout-${order.id}-${Date.now()}`,
    status: 'pending_payment'
  });

  res.json({
    redirectUrl: response.redirectUrl,
    appLinks: response.appLinks,
    paymentId: response.paymentId
  });
});

// Frontend: Handle redirect
async function initiatePayment(orderId) {
  const response = await fetch('/api/checkout/link-pay', {
    method: 'POST',
    body: JSON.stringify({ orderId })
  }).then(r => r.json());

  // Detect platform and redirect
  const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent);
  const isIOS = /iPhone|iPad/i.test(navigator.userAgent);

  if (isMobile) {
    const url = isIOS
      ? response.appLinks.ios.shortUrl
      : response.appLinks.android.shortUrl;
    window.location.href = url;
  } else {
    // Show QR code for desktop users
    showQRCode(response.appLinks.android.shortUrl);
  }

  // Start polling for status
  pollPaymentStatus(orderId);
}

// Frontend: Poll for payment completion
async function pollPaymentStatus(orderId) {
  const maxAttempts = 60; // 5 minutes with 5-second intervals
  let attempts = 0;

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

    const order = await fetch(`/api/orders/${orderId}`).then(r => r.json());

    if (order.status === 'paid') {
      showSuccess('Payment completed!');
      return;
    } else if (order.status === 'failed') {
      showError('Payment failed. Please try again.');
      return;
    }

    attempts++;
  }
}

// Webhook handler
app.post('/webhooks/rebell', async (req, res) => {
  // Verify signature
  if (!verifySignature(req)) {
    return res.status(401).send('Invalid signature');
  }

  const { paymentRequestId, result } = req.body;

  if (result.resultStatus === 'S') {
    await updateOrderByPaymentRequestId(paymentRequestId, { status: 'paid' });
    await fulfillOrder(paymentRequestId);
  } else {
    await updateOrderByPaymentRequestId(paymentRequestId, { status: 'failed' });
  }

  res.status(200).send('OK');
});

Testing Checklist

Test these scenarios in sandbox before going live:

Next Steps