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.

Points supports three independent earning channels. You can integrate one, two, or all three — each channel is opt-in and shares the same API key, lock, response shape, and pending-customer handling.
ChannelTriggerEndpoint
Order purchaseCustomer completes a purchasePOST /v1/orders/earning
Store ratingCustomer rates your storePOST /v1/orders/earning/store-rating
Product ratingCustomer rates a productPOST /v1/orders/earning/product-rating

How earning amounts are decided

The merchant controls the points amount, not the API caller. Each channel reads its configured rate from the merchant’s Points dashboard:
  • Order purchase — points scale with total_price and a per-merchant multiplier. Specific products can be assigned a custom point value that overrides the default.
  • Store rating — flat amount per accepted store rating.
  • Product rating — flat amount per accepted product rating.
This means your integration code never decides how many points are awarded. You only tell Points what happened, and Points applies the merchant’s current configuration.
A channel must be enabled and funded in the merchant’s dashboard before its endpoint will award points. If the channel is disabled, the API returns 403.

Shared behavior across all channels

All three earning endpoints share these guarantees so your integration logic stays uniform:
  • Authentication. Same x-api-key header (see API keys).
  • Concurrency. Each merchant is serialized through a distributed lock. Send earning calls sequentially per merchant; retry 429 with a short back-off.
  • Idempotency. Each request carries a merchant-side unique reference (order_number for purchases, review_reference for ratings). Reuse the same reference on retries — duplicates are rejected, not double-awarded.
  • Pending customers. If the customer’s Points account is not yet activated, the response returns a pending_client_activation payload instead of an approved order. The earning is queued and finalized when the customer activates.
  • Response shape. Same data.uuid, data.reference_number, data.order_status, and data.total_points fields. Store the uuid for later lookups, refunds, and reconciliation.

Pending-customer response (any channel)

{
  "status": true,
  "message": "",
  "appended_data": {},
  "data": {
    "pending_client_activation": true,
    "pending_earning_order": {
      "id": 99,
      "merchant_order_number": "SALE-2026-0021",
      "total_price": 115.0,
      "total_points": 1150
    }
  }
}

Order purchase

Award points to a customer for a completed purchase. This is the most common channel — use it when your checkout system runs entirely on your side and you want to reward the payment.

Flow

Required inputs

FieldRequiredNotes
phone_numberYesKSA mobile, normalised server-side to 5XXXXXXXX
total_priceYesTotal paid amount in SAR
order_numberYesYour merchant-side unique order reference
productsYesArray with at least one item
metadataNoUseful for channel, branch, POS context

Example request

curl -X POST https://business.papp.sa/api/v1/orders/earning \
  -H "x-api-key: $POINTS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "phone_number": "512345678",
    "total_price": 115.00,
    "order_number": "SALE-2026-0021",
    "products": [
      { "product_name": "Cappuccino", "product_price": 18.50, "quantity": 2 },
      { "product_name": "Croissant", "product_price": 39.00, "quantity": 2 }
    ],
    "metadata": {
      "channel": "web",
      "branch_code": "RUH-01"
    }
  }'

Successful response

{
  "status": true,
  "message": "",
  "appended_data": {},
  "data": {
    "id": 42,
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "reference_number": "REF-2026-001234",
    "order_status": "approved",
    "order_number": "SALE-2026-0021",
    "type": 1,
    "total_price": 115.0,
    "total_points": 2300,
    "metadata": {
      "channel": "web",
      "branch_code": "RUH-01"
    },
    "created_at": "2026-04-18T10:00:00Z"
  }
}

When to call the API

Call POST /v1/orders/earning only after the purchase is actually confirmed in your own system, such as:
  • successful PSP callback
  • order marked paid in POS
  • COD order marked collected
Do not call it before payment confirmation.

Store rating

Award points when a customer submits a rating for your store overall.

Flow

Required inputs

FieldRequiredNotes
phone_numberYesKSA mobile, normalised server-side to 5XXXXXXXX
review_referenceYesYour platform’s unique identifier for this rating — used for idempotency
ratingNoStar value (1–5). Stored for audit only — does not change the points awarded
commentNoFree-text review body. Stored for audit only
metadataNoFree-form object for channel, branch, source, etc.
The merchant configures the points amount in the Points dashboard under Earning methods → Store rating. Your request body does not carry the points value.

Example request

curl -X POST https://business.papp.sa/api/v1/orders/earning/store-rating \
  -H "x-api-key: $POINTS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "phone_number": "512345678",
    "review_reference": "STORE-REVIEW-2026-0001",
    "rating": 5,
    "comment": "Great experience, fast delivery.",
    "metadata": {
      "channel": "web",
      "branch_code": "RUH-01"
    }
  }'

Successful response

{
  "status": true,
  "message": "",
  "appended_data": {},
  "data": {
    "id": 88,
    "uuid": "9c4b1d2e-7f8a-4b3c-9e2d-1a2b3c4d5e6f",
    "reference_number": "REF-2026-002088",
    "order_status": "approved",
    "order_number": "STORE-REVIEW-2026-0001",
    "type": 1,
    "total_price": 0,
    "total_points": 25,
    "created_at": "2026-04-18T10:00:00Z"
  }
}

When to call the API

Call the endpoint only after the rating is accepted in your own system — i.e. it has passed moderation, spam checks, or any minimum-content rules. Do not call it for drafts, deleted reviews, or duplicate submissions. If the customer edits or deletes their rating later, the awarded points are not automatically reversed. Treat the API call as a one-shot reward at submission time.

Product rating

Award points when a customer submits a rating for a specific product they purchased.

Flow

Required inputs

FieldRequiredNotes
phone_numberYesKSA mobile, normalised server-side to 5XXXXXXXX
review_referenceYesYour platform’s unique identifier for this rating — used for idempotency
product_idYesYour platform’s product identifier (SKU or internal ID)
product_nameNoHuman-readable product name. Stored for audit
ratingNoStar value (1–5). Stored for audit only
commentNoFree-text review body. Stored for audit only
metadataNoFree-form object for channel, branch, source, etc.
The merchant configures the points amount in the Points dashboard under Earning methods → Product rating. Your request body does not carry the points value.

Example request

curl -X POST https://business.papp.sa/api/v1/orders/earning/product-rating \
  -H "x-api-key: $POINTS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "phone_number": "512345678",
    "review_reference": "PRODUCT-REVIEW-2026-0001",
    "product_id": "SKU-CAPPUCCINO-250G",
    "product_name": "Cappuccino 250g",
    "rating": 4,
    "comment": "Good aroma, smooth taste.",
    "metadata": {
      "channel": "mobile_app"
    }
  }'

Successful response

{
  "status": true,
  "message": "",
  "appended_data": {},
  "data": {
    "id": 91,
    "uuid": "1f2e3d4c-5b6a-7e8d-9c0b-1a2b3c4d5e6f",
    "reference_number": "REF-2026-002091",
    "order_status": "approved",
    "order_number": "PRODUCT-REVIEW-2026-0001",
    "type": 1,
    "total_price": 0,
    "total_points": 10,
    "created_at": "2026-04-18T10:00:00Z"
  }
}

When to call the API

Call the endpoint only after the rating is accepted in your own system — i.e. it has passed moderation, the customer is verified to have purchased the product, and the rating is not a draft. Do not call it for deleted or duplicate submissions. If the customer edits or deletes their rating later, the awarded points are not automatically reversed.

Common errors (all channels)

HTTP statusMeaningWhat to do
400Missing or invalid API keyVerify x-api-key and environment
403Merchant unverified/unpublished or this earning channel disabledAsk the merchant to enable the channel in the dashboard
422Validation errorCheck required fields for that channel
429Concurrent earning requests for the same merchantRetry with back-off
  1. Create the earning record after the upstream event (payment / rating) is confirmed on your side.
  2. Store the returned uuid against your own record.
  3. If your worker crashes between the upstream event and the Points call, use your stored merchant reference (order_number or review_reference) to detect the partially completed step on retry.
  4. For disputes or support, fetch the order later with GET /v1/orders/{uuid}.

Next

Quick start

Make your first earning call end-to-end.

Refunds & cancellations

What happens when an awarded order is later refunded.

Order lifecycle

State transitions, statuses, and webhooks.

Go-live checklist

Verify production readiness before launch.