JeelPay Items Checkout

Jeel Pay

Jeel Pay is a “Study Now Pay Later” platform that allows educational entities to offer its services in installments for parents and other beneficiaries making it easy to pay and track tuition fees. Jeel Pay allows schools to focus on the educational and academic domain while the collection and of fees is handled by Jeel. The platform provides APIs for schools and school marketplace platforms to utilize the features thus increasing growth and expand business operations completely hassle-free.

If the plan’s total cost is 5,000 SAR or less, it will be divided into four payments. For plans exceeding 5,000 SAR, the number of payments will be determined according to our agreement with the entity.

Features

  1. Request an installment request for a customer.

  2. Redirects to merchant websites after confirmation with result.

  3. Webhooks “Notifications” when the request status changes (Approved, Rejected, ...) by customer.

  4. View the details of a specific checkout.

Items Checkout

API Checkout

The API checkout is a checkout initiated from the API integration. API checkouts receive webhooks for the whole cycle of the checkout process.

In the webhook body, the checkoutType property will have the value of: ITEMS

Business Flow

This section explains the sequence and business flow between the systems in the API checkout phase:

  1. Merchant website will display the cost breakdown and installment details to the customer if they wish to choose JeelPay as an installment provider.

  2. The customer selects JeelPay then the merchant server create a checkout with Jeel.

  3. The merchant site redirects the customer to JeelPay checkout platform to (login/register) in JeelPay and finish the KYC and completes the downpayment.

  4. JeelPay Site will redirect the customer to the merchant site with the result.

  5. JeelPay Server will also send a webhook to merchant server to confirm the same result.

Below is a sequence diagram that illustrates the above

At any step, you can get the status of the request using the endpoint /v3/checkout/{id} - GET a checkout by ID

{
  // REQUIRED: Buyer object (must be present and valid)
  "buyer": {
    "first_name": "أحمد",                 // Required. String
    "last_name": "محمد",                  // Required. String
    "mobile_number": "501234567",         // Required. (9 digits starting with 5)
    "email": "[email protected]",         // Optional? String
    "national_id": "1234567890"           // Optional? if provided it must be must be 10 digits starting with 1 or 2
  },

  // REQUIRED: items (non-empty list)
  "items": [
    {
      "item_name": "My New Course",                   // Required. String
      "quantity": 1,                                  // Required. Integer >= 1
      "unitPrice": 25000.00,                          // OPTIONAL in validation (will be recalculated server-side) — include only if you want to show unit price
      "total_cost": 25000.00,                         // Required. Decimal with 2 fraction digits, >= 0
      "reference_id": "REF123456",                    // Required. String
      "entity_id": "123e4567-e89b-12d3-a456-426614174000" // Optional?
      Required only if each item is from a differant entity
    },
    {
      "item_name": "The Advanced Course",             // Required 
      "quantity": 2,                                  // Required
      "unitPrice": 3500.00,                           // Optional
      "total_cost": 7000.00,                          // Required
      "reference_id": "REF789012",                    // Required
      "entity_id": "123e4567-e89b-12d3-a456-426614174001" // Optional
    }
  ],

  // REQUIRED: urls object (both fields required, must be HTTPS)
  "urls": {
    "redirect_url": "https://website.com/jeel/confirm",    // Required. Must be valid https URL
    "notification_url": "https://website.com/webhook/jeel" // Required. Must be valid https URL
  },

  // OPTIONAL: metadata
  "metadata": {
    //below are just random examples
    "customer_secret_coder": "CUST12345",      // Optional
    "source": "mobile_app",                   // Optional
    "additional_info": "Special promotion applied" // Optional
  }
}

Checkout Statuses

The status of the checkout request changes throughout the lifetime of the request. The below diagrams explains the statuses requests go through.

PENDING: This is the status of a newly created checkout. The customer has reached the checkout and the request is active, awaiting payment or finalization.

REJECTED: The checkout was closed without success (for example: the customer rejected the agreement, customer wasn't eligible, the customer cancelled, or the merchant/system cancelled the request).

EXPIRED: The checkout was closed because no action occurred for 4 hours (timeout due to inactivity).

SUCCEEDED: The customer paid the required down payment and the installment plan was created; the checkout is completed successfully.

API Authentication

Jeel APIs follows OAuth 2.1 for API authentication and authorization. Client Credentials flow will be used to authenticate by providing the authorization server with client id and secret to obtain a token for API usage.

The diagram below explains the flow

A sample HTTP request to get an access token:

Sandbox:

POST /oauth2/token HTTP/1.1
Host: auth.sandbox.jeel.co
Content-Type: application/x-www-form-urlencoded
 
client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&grant_type=client_credentials

Production:

POST /oauth2/token HTTP/1.1
Host: auth.jeel.co
Content-Type: application/x-www-form-urlencoded
 
client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&grant_type=client_credentials

A sample response:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
 
{"access_token":"eyJraWQiOiJkMWZhOWEwOS0wOGIxLTRlMTktYWUzNC1kZGU0OWQ2MmNlNzkiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIwNDJkMzAzYy1kZGVlLTQ1YjgtYTNmNy1kZDc1ZWUyMjY0ZjciLCJhdWQiOiJFQ1dzdUtXWkh2ZFNZQnlVdFp3NGI2YjNRNVlJSjVSQ2RyXzdsTFFra0g4IiwibmJmIjoxNjkyNDgyMDcyLCJtb2JpbGVOdW1iZXIiOiJTeXN0ZW0iLCJyb2xlcyI6WyJFWFRFUk5BTF9BUEkiXSwiaXNzIjoiaHR0cHM6Ly9hdXRoLnNhbmRib3guamVlbC5jbyIsImNsaWVudCI6IkplZWwgZGVtbyIsImV4cCI6MTY5MjQ4MjM3MiwiaWF0IjoxNjkyNDgyMDcyfQ.smuItOKuE-pR5AO8xhXc8E9tTmJA0rq4y3lyc7vIJKgsaNGatX4nUDAY3nc-5jHS0VQjUHzVAG0nagxsgVMnwWcMDwsCqJKoKW0GcBO0P3ZxXmrSRahvgY2oUivCGzXpNbypwmK9N8WdaBb_9saH9k2dZWsCxkcXxNAkOdEpJWg1ZG12OI_o2bJ9ziQYzuPz4ExpqN6A0SW4vfiwb8ST3O6ib8cioUIIeUpoPedtWTgkehxJSLJ6DVhs3nyBCNhgfKeX7U3F5iSfXSlN7T0VgDC4oJ_HokeoBDgINzp1mH6CMpEJFCS-WpzJI1rLyCeVEd6PLytJnzR-Qp557KwVRQ","token_type":"Bearer","expires_in":299}

Webhooks Signature

The X-Jeel-Signature header is a security measure used in webhook responses to guarantee that the data received is from our platform and has not been tampered with during transit. It is created using the HMAC (Hash-based Message Authentication Code) algorithm with base64 encoding, using the clientSecretKey as the secret key and the webhook body json as the message. The header is then added to each webhook request, allowing you to verify the integrity of the received data.

Webhook Body

The webhook body you'll receive contains the request ID and the new status of it.

Checkout type: ITEMS

{
  "checkout_id": "9e79d502-231d-449b-b419-a674b687df51",
  "status": "SUCCEEDED",
  "checkoutType": "ITEMS"
}

Examples on Calculating the Signature:

Java:

private String calculateSignature(String clientSecretKey, WebhookDto webhookBody) {
  Gson gson = new Gson();
  return Base64Utils.encodeToString(
      new HmacUtils(HmacAlgorithms.HMAC_SHA_256, clientSecretKey).hmac(gson.toJson(webhookBody))
    );
}

PHP:

function calculateSignature($clientSecretKey, $webhookBody) {
  $jsonData = json_encode($webhookBody);
  $signature = base64_encode(hash_hmac('sha256', $jsonData, $clientSecretKey, true));
  return $signature;
}

JavaScript:

function calculateSignature(clientSecretKey, webhookBody) {
  const hmac = crypto.createHmac('sha256', clientSecretKey);
  hmac.update(JSON.stringify(webhookBody));
  return Base64.encode(hmac.digest());
}

Checkout

Testing Card

Card Number
Date
CVV

Visa

4111111111111111

05/30

123

Last updated