Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.papp.sa/llms.txt

Use this file to discover all available pages before exploring further.

The Checkout flow lets your customers redeem Points during your checkout for a direct discount on the order, and earn Points on whatever portion they pay in cash. It is the full Points experience — the right choice when you want customers to feel they can spend the balance they’ve built up across the network. If you only need to award points after events on your side (purchase, store rating, product rating) without redirecting the customer, see Earning methods instead.

What “redeem” means in Points

In a redeem-during-checkout flow:
  1. your backend creates a checkout session
  2. the customer is redirected to the Points-hosted checkout
  3. the customer sees their eligible balance
  4. they apply some or all of the balance
  5. they pay any remaining amount
  6. Points notifies your backend by webhook

Responsibilities

Your sidePoints side
Creating the checkout session with the correct total_priceIdentifying the customer
Passing a stable order_numberShowing the redeemable balance
Storing your own cart/order context in metadataApplying redemption inside the hosted checkout
Handling the browser return via callback_urlFinishing the payment flow and order settlement
Treating the webhook as the source of truth

High-level picture

Prerequisites

  • Public key (for creating the checkout session) — see API keys
  • Private key (for the post-redirect verification call)
  • Webhook endpoint — registered in the dashboard, receives order events (Webhooks overview)
  • Callback URL — a page on your storefront where Points redirects the customer after checkout completes

Step 1 — Create the checkout session

When the customer clicks Pay on your checkout page, your backend calls the public checkout endpoint with the Public key in the URL.
curl -X POST https://business.papp.sa/api/v1/orders/checkout/YOUR_PUBLIC_KEY \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "phone_number": "512345678",
    "total_price": 150.75,
    "order_number": "ORD-2024-0001",
    "callback_url": "https://merchant.example.com/checkout/callback?order=ORD-2024-0001",
    "products": [
      { "product_name": "Cappuccino", "product_price": 18.50, "quantity": 2 },
      { "product_name": "Croissant",  "product_price": 39.00, "quantity": 2 }
    ],
    "metadata": { "source": "web", "cart_id": "cart_abc123" }
  }'
The Checkout endpoint does not require the x-api-key header — the Public key in the URL is sufficient. Do not include the Private key on this call.

Response

{
  "status": true,
  "message": "",
  "appended_data": {},
  "data": {
    "checkout_url": "https://pay.papp.sa/session/abcd1234"
  }
}

Customer identity behavior

The checkout endpoint accepts phone_number. Current runtime behavior is:
  • if the phone belongs to a known Points customer, the checkout continues to verification
  • if the phone is not found, the response still returns a checkout_url, but the customer lands on an onboarding / phone-change path before completing checkout
That means your frontend should never make assumptions from the phone lookup alone. Always redirect the user to the returned checkout_url.

Step 2 — Redirect the customer

Redirect the customer’s browser to checkout_url. Inside Points checkout, the customer can:
  1. Confirm their phone number (one-time OTP if not yet verified).
  2. See their redeemable Points balance.
  3. Choose how many points to apply as discount.
  4. Pay the remaining amount via your configured PSP.
The exact UX may evolve, but your backend integration contract does not change: create checkout, redirect, listen to webhook, reconcile the order state.

Step 3 — Receive the webhook

As soon as Points settles the checkout, your registered webhook endpoint receives the terminal event. The most common sequence is:
EventMeaning
approvedCheckout completed and payment confirmed. Points redeemed + earned.
capturedFunds captured (if you use an authorize-then-capture PSP).
cancelledCustomer abandoned the checkout or payment failed.
See Webhook events for full payload schemas.
{
  "event": "approved",
  "order": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "reference_number": "REF-2024-001234",
    "order_number": "ORD-2024-0001",
    "type": "replacing",
    "total_price": 150.75,
    "total_points": 500,
    "payment_status": "fully_paid",
    "order_status": "approved",
    "metadata": { "source": "web", "cart_id": "cart_abc123" },
    "created_at": "2026-04-18T10:00:00Z",
    "updated_at": "2026-04-18T10:05:12Z"
  },
  "timestamp": "2026-04-18T10:05:12Z"
}
Treat the webhook — not the callback_url landing — as the source of truth. The customer may close the browser before redirect, but the webhook still fires.

Step 4 — Handle the browser redirect

Points redirects the customer’s browser to the callback_url you supplied. The URL is appended with query parameters identifying the order so your frontend can show the right confirmation page. The callback_url is for user experience only. Use it to show:
  • order confirmation
  • pending state
  • payment failure / retry page
Do not use the browser redirect as proof of payment. The authoritative signal is the webhook plus, if needed, GET /v1/orders/{uuid}. Your callback handler should:
  1. Look up the order in your database by order_number.
  2. If the webhook hasn’t landed yet, call GET /v1/orders/{uuid} to confirm state before showing success.
  3. Display the appropriate confirmation (or failure) page.
curl https://business.papp.sa/api/v1/orders/550e8400-e29b-41d4-a716-446655440000 \
  -H "x-api-key: $POINTS_API_KEY" \
  -H "Accept: application/json"

Step 5 — Fulfilment & shipping updates (optional)

For physical-goods orders, as you fulfil the order you can update the shipping status so Points reflects the right state on the customer’s transaction history:
curl -X POST https://business.papp.sa/api/v1/orders/{uuid}/status \
  -H "x-api-key: $POINTS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "ready_shipping" }'
Allowed values: new, license_in_progress, ready_shipping, delivery_is_in_progress, delivered, cancelled. Each call fires a shipping_status_updated webhook.

Refunds & cancellations

See the dedicated page: Refunds & cancellations.

Edge cases

The webhook still fires. Use it as your source of truth. Your callback-handler page should be resilient to a missing query parameter — fall back to querying the order by order_number.
The session remains valid until it expires or is completed. A stale checkout_url returns a friendly error page from Points.
Common. Your database should be updated by the webhook handler; the callback page reads from the database, not from query params.
Cancel the existing checkout session (the customer can retry) and create a new one with the updated amount. Do not mutate an already-approved order — refund/re-charge instead.

What’s next

Order lifecycle

Understand state transitions (authorize → capture → refund).

Webhooks overview

Receive and process real-time order events.

Refunds & cancellations

Full and partial refunds, cancellation windows.

Go-live checklist

Everything to verify before production traffic.