Skip to content

Customer Pay Now Flow for Payment Integrators

This document focuses on the endpoints that needs to be called in the Purchase Order Service (POS) and Payment Service (PS) to make an immediate payment for a service. Calls to other related services are excluded. The flow documented here is based on the current Pay-Now feature within the Client Interface and are subject to change.

Pay-Now Load and Selection

To use the Pay-Now feature in Client Interface, the user must be logged in, have an existing service that is configured to accept immediate payments and have an amount payable on that service.

Either select the Pay-Now button on the relevant service card from the home screen or the Make Payment button from the service view screen to navigate to the Pay Now screen. All the requests to the POS/PS to populate the screen are listed below.

Get all Valid Mediums

This request is used to display all valid mediums for user selection.

GET https://stage.purchase-order-service.dev.aex.systems/payment-mediums?userId={userId}

file_type_swagger GetPaymentMediums

Note that the result will also include a medium of type “ProviderSelectedOpaque” that is a global medium available for all customers. This medium serves as a placeholder for the medium when paying via Peach Payments’ Checkout API, where a tokenized card is not used and listed as the “Add new payment method” option. The response of this medium is as follows:

Example Response
1
2
3
4
5
6
7
8
{
  "medium_detail_id": "aa8b416b-a7d9-4bc0-af81-041722e11ad4",
  "medium_type": "ProviderSelectedOpaque",
  "bank_account": "Add new payment method",
  "account_nr_partial": null,
  "is_linked": false,
  "medium_status": "Valid"
}

Details and Actions Call to POS

This call gets the full details and available actions from POS. If the account is in arrears, the current payable purchase will be found under must_pay_info, to be submitted for collection. If the account is paid up, then must_pay_info will be null.

GET https://stage.purchase-order-service.dev.aex.systems/services/E14C231D-5899-44BE-B7A1-AA46893C8D83/details-and-actions

file_type_swagger Get Service Details and Actions

Example Response
{
    "service_id": "E14C231D-5899-44BE-B7A1-AA46893C8D83",
    "service_status": "PendingIspApplication",
    "service_status_category": "PreActivationStatuses",
    "collector_id": "195ccad5-02fc-4dc2-8589-7d85e44ffe30",
    "service_type": "Recurring",
    "billing_status": "InArrears",
    "latest_period_end_date": null,
    "suspension_date": null,
    "collection_day": 15,
    "plan_id": "3e0ddf82-8912-459a-a6ec-f6640fdf8206",
    "mediums": [
        {
            "external_reference": "2903c73f-d075-4344-b034-888050375c1b",
            "customer_id": "2e15812f-34d7-4903-898e-ed3dcc6704a1",
            "medium_detail_id": "f3fe1a0a-c27b-4860-8159-6b94eb4c608d",
            "medium_type": "CreditCard",
            "medium_status": "Valid",
            "created_date": "2024-06-06T07:09:11.74847+00:00",
            "account_name": "test 4242",
            "account_number": "4242"
        },
        {
            "external_reference": "a8104184-86e0-4bb3-bf68-35197d916ed8",
            "customer_id": "2e15812f-34d7-4903-898e-ed3dcc6704a1",
            "medium_detail_id": "52db8e7c-bfbc-4e30-981b-c6477abdc59e",
            "medium_type": "PaymentLink",
            "medium_status": "Valid",
            "created_date": "2024-06-06T07:09:45.136321+00:00",
            "account_name": "konstandNet99@alpha.20240606.1",
            "account_number": ""
        },
        {
            "external_reference": "fa19f2f6-9737-4d0e-9c51-0234ae725940",
            "customer_id": "2e15812f-34d7-4903-898e-ed3dcc6704a1",
            "medium_detail_id": "58668902-5c08-45b0-b7ea-92fd760f1244",
            "medium_type": "OffSystem",
            "medium_status": "Valid",
            "created_date": "2024-06-06T07:09:45.204251+00:00",
            "account_name": "N/A",
            "account_number": null
        },
        {
            "external_reference": "Global PeachPayment provider selected opaque medium",
            "customer_id": null,
            "medium_detail_id": "aa8b416b-a7d9-4bc0-af81-041722e11ad4",
            "medium_type": "ProviderSelectedOpaque",
            "medium_status": "Valid",
            "created_date": "2023-10-12T04:36:37.252574+00:00",
            "account_name": "Add new payment method",
            "account_number": null
        }
    ],
    "must_pay_info": {
        "must_pay": true,
        "arrears_purchase": {
            "id": "62289f11-d7b4-4160-b51b-61c1a780be3b",
            "service_id": "7fe336c2-2dfd-4c3f-b9a4-14f76a828e53",
            "amount_excl": 329.70,
            "tax_amount": 49.20,
            "amount": 378.90,
            "medium_id": "f3fe1a0a-c27b-4860-8159-6b94eb4c608d",
            "purchase_date": "2024-06-06T07:09:45.250524+00:00",
            "purchase_status_id": 3,
            "payment_reference": null,
            "small_key": 1928142,
            "purchase_plan_id": null,
            "period_applied": false,
            "purchase_source_id": null,
            "purchase_creation_event_id": 1,
            "purchase_lines": [
                {
                    "id": "63eefe80-0ca9-431d-9105-65d56d1561c9",
                    "purchase_id": "62289f11-d7b4-4160-b51b-61c1a780be3b",
                    "original_purchase_line_id": null,
                    "purchase_line_type_id": 1,
                    "description": "On Order/Upfront Monthly",
                    "total_amount": 378.9000,
                    "amount_per_quantity": 10.9900,
                    "net_amount_excl": 329.70,
                    "tax_rate": 15.0,
                    "tax_amount": 49.20,
                    "quantity": 30,
                    "period_contribution_per_quantity": 1,
                    "product_price_id": "41d48ce6-753e-4678-96b2-7f2f08fee202"
                }
            ]
        }
    },
    "can_buy_info": null,
    "last_purchase_is_pending": false,
    "on_network_date": null
}

Get Active Medium for Service

This request is used to retrieve and display the active medium of the service, indicated on the UI with a check icon next to the name. This medium is the active medium on the purchase plan and will be used for future recurring purchases. Only valid credit card and bank account mediums can be set as the active medium.

GET https://stage.purchase-order-service.dev.aex.systems/active-payment-medium-for-service?serviceId={serviceId}

file_type_swagger GetActiveMediumForService

Get Default Provider for Medium Type

This request retrieves the default provider for a specified mediumTypeId (1=BankAccount, 2=CreditCard).

GET https://stage.payment-service.dev.aex.systems/default?mediumType=1

file_type_swagger GetDefaultProvider

Pay Now

This request triggers an immediate purchase to the POS using the medium selected.

Submit Arrears Purchase For Collection Call to POS using an Existing Medium

This request is done using an existing valid BankAccount or CreditCard medium, like the one created during signup. After again calling 'Get Service Details and Actions', use the purchase contained in must_pay_info and submit it to POS for collection.

POST https://stage.purchase-order-service.dev.aex.systems/purchases/submit-for-collection

file_type_swagger Submit Purchase For Collection

Payload
1
2
3
4
5
6
7
8
{
  "service_id":"E14C231D-5899-44BE-B7A1-AA46893C8D83",
  "medium_id":"f3fe1a0a-c27b-4860-8159-6b94eb4c608d",
  "success_url":null,
  "failure_url":null,
  "process_immediate_purchase":true,
  "purchase_id":"62289f11-d7b4-4160-b51b-61c1a780be3b"
}
Example Response (failure)
1
2
3
4
5
6
7
{
  "type": "https://tools.ietf.org/html/rfc7235#section-3.1",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Unauthorized",
  "instance": "/purchases/submit-for-collection"
}
Example Response (success)
1
2
3
{
  "payment_link_url":null
}

Checkout Medium Selected

"Add new payment method" option

This request is done using the Peach Payments Checkout API. Notice that it is the same end point as mentioned above, but the payload will contain the checkout medium (id aa8b416b-a7d9-4bc0-af81-041722e11ad4") and success and failure urls.

POST https://stage.purchase-order-service.dev.aex.systems/purchases/submit-for-collection

file_type_swagger Submit Purchase For Collection

Payload
1
2
3
4
5
6
7
8
{
  "service_id": "B687E259-FF63-4FAD-81B8-DFDF4CB726AC",
  "medium_id": "aa8b416b-a7d9-4bc0-af81-041722e11ad4",
  "process_immediate_purchase": true,
  "success_url": "https://stage.purchase-order-service.dev.aex.systems/peach-redirect/195ccad5-02fc-4dc2-8589-7d85e44ffe30?url=https://stage.netninenine.client-interface.dev.aex.systems/ext-pay/a40efeb6-7f8f-42c2-ba57-5f08328b1c28/5a41b6fe/1",
  "failure_url": "https://stage.purchase-order-service.dev.aex.systems/peach-redirect/195ccad5-02fc-4dc2-8589-7d85e44ffe30?url=https://stage.netninenine.client-interface.dev.aex.systems/ext-pay/a40efeb6-7f8f-42c2-ba57-5f08328b1c28/5a41b6fe/0",
  "purchase_id":"62289f11-d7b4-4160-b51b-61c1a780be3b"
}

The response will contain a payment_link_url property that the UI should redirect to where the user will complete their payment. On completion, Peach Payments will redirect to either the originally passed success_url or the failure_url. Note that redirecting to the failure_url is currently failing at Peach Payments, a known issue to them, and subsequently they always redirect to the success URL.

Also, since their redirect is a POST request which Angular does not allow, the redirect URLs are both redirected to the POS, with the intended UI URL passed as a parameter. POS then alters this UI URL parameter to end with a 1 or a 0 depending on success or failure.

When the operator has payment links enabled as a payment option, the payment link is generated by the POS so that when this medium is selected for payment, the user is redirected to the payment page to complete their payment. This payment link medium is automatically generated for the customer after placing an order.

The POST call mentioned above (Submit Purchase For Collection) will contain a URL in the response, similar to Peach Payments Checkout API, that the user can be redirected to for payment:

Example Response
1
2
3
{
  "payment_link_url": "https://sandbox.payfast.co.za/eng/process/payment/123456ab-1234-ab12-907b-821e62f56789#cc"
}

Buy Now - Buying day bundles into the future

Day bundle type products do not have a monthly purchase and the only "Must Pay" purchase will be the upfront that follows the same flow as above.

After that purchase, new bundles are bought as "Buy Now". Since there are options for the customer to choose from, the purchase cannot be created in the backend automatically. Therefore a purchase creation call to POS is required before submitting it for collection. In this case, the 'Get Service Details and Actions' call would contain a can_buy_info object that contains the available options that the user can select. This is passed to the following endpoint that will return the purchase with its id to submit in the same chain.

POST https://stage.purchase-order-service.dev.aex.systems/purchases/buy-now

file_type_swagger CreateBuyNowPurchase

Payload
{
  "service_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "purchase_lines": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "purchase_line_type_id": 1,
      "description": "7 Day bundle",
      "total_amount": 34.50,
      "amount_per_quantity": 10,
      "net_amount_excl": 30,
      "tax_rate": 15,
      "tax_amount": 4.50,
      "quantity": 3,
      "period_contribution_per_quantity": 7,
      "product_price_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  ],
  "customer_statement_ref": "string",
  "purchase_date": "2024-06-06T11:00:31.338Z"
}

Buy Now - Buying recurring months into the future

Recurring type products have a monthly purchase and so additional months can be purchased as required. The "Must Pay" purchase can either be the upfront that follows the same flow as above, or when the service is in arrears.

Additional months are bought as "Buy Now". Since the amount to pay is variable, the purchase cannot be created in the backend automatically, therefore a purchase creation call to POS is required before submitting it for collection. In this case, the 'Get Service Details and Actions' call would contain a can_buy_info object that contains the options that the user can select. This is passed to the following endpoint that will return the purchase with its id to submit in the same chain.

POST https://stage.purchase-order-service.dev.aex.systems/purchases/buy-now

file_type_swagger CreateBuyNowPurchase

Payload
{
    "customer_statement_ref": "",
    "purchase_date": "2024-11-26T09:33:07.601Z",
    "purchase_lines": [
        {
            "description": "Monthly Recurring 20/10",
            "amount_per_quantity": 10.985506666666668,
            "amount_per_quantity_incl": 12.633333333333333,
            "net_amount_excl": 867.8550266666667,
            "purchase_line_type_id": 1,
            "total_amount": 1000,
            "tax_rate": 15,
            "tax_amount": 132.14497333333327,
            "quantity": 79,
            "period_contribution_per_quantity": 1
        }
    ],
    "service_id": "2afddac4-dfd8-40e6-ba4c-250b4926a4a8",
    "purchase_source_id": "e8cc35b7-192c-412e-9f1f-755c9835a0e8",
    "comment": "Test comment"
}
Response
{
    "id": "64aa0235-0990-4e63-8136-a2d7aca5c3cc",
    "service_id": "2afddac4-dfd8-40e6-ba4c-250b4926a4a8",
    "amount_excl": 867.86,
    "tax_amount": 132.14,
    "amount": 1000.0,
    "medium_id": null,
    "purchase_date": "2024-11-26T09:33:07.601+00:00",
    "purchase_status_id": 6,
    "payment_reference": null,
    "small_key": 2046235,
    "purchase_plan_id": null,
    "period_applied": false,
    "purchase_source_id": "e8cc35b7-192c-412e-9f1f-755c9835a0e8",
    "purchase_creation_event_id": 6,
    "purchase_lines": [
        {
            "id": "a46fc439-3e91-42f2-95d1-8777842da61c",
            "purchase_id": "64aa0235-0990-4e63-8136-a2d7aca5c3cc",
            "original_purchase_line_id": null,
            "purchase_line_type_id": 1,
            "description": "Monthly Recurring 20/10",
            "total_amount": 1000.0,
            "amount_per_quantity": 10.985506666666668,
            "net_amount_excl": 867.8550266666667,
            "tax_rate": 15.0,
            "tax_amount": 132.14497333333327,
            "quantity": 79,
            "period_contribution_per_quantity": 1,
            "product_price_id": "00000000-0000-0000-0000-000000000000"
        }
    ]
}
purchase_line_type_id: 1 = Day 2 = Monthly 3 = Installation/Once-off

The response of this call will be a purchase (quote) that can be submitted as usual for collection using the purchaseId in this response.

Submit Buy-Now Purchase For Collection Call to POS using an Existing Medium

This request is done using an existing valid BankAccount, CreditCard or Off-System medium. After again calling 'Get Service Details and Actions', use the purchase contained in can_buy_info and submit it to POS for collection using submit-for-collection.

Note: that if an off-system allocation is required, please ensure that the off-system medium id is used from the details-and-actions response. If a credit card medium for example is used here then the customer will be debited. ~~~~ POST https://stage.purchase-order-service.dev.aex.systems/purchases/submit-for-collection

file_type_swagger Submit Purchase For Collection

json title="Payload" { "failure_url": null, "medium_id": "fcffc5e9-052a-47b0-b41d-0ef647a84e08", "process_immediate_purchase": true, "service_id": "2afddac4-dfd8-40e6-ba4c-250b4926a4a8", "success_url": null, "purchase_id": "64aa0235-0990-4e63-8136-a2d7aca5c3cc", "purchase_source_id": "e8cc35b7-192c-412e-9f1f-755c9835a0e8", "comment": "Test comment" } json title="Example Response (failure)" { "type": "https://tools.ietf.org/html/rfc7235#section-3.1", "title": "Unauthorized", "status": 401, "detail": "Unauthorized", "instance": "/purchases/submit-for-collection" } json title="Example Response (success)" { "payment_link_url":null }

Get list of purchase sources for use with off-system payments (allocations)

POST https://stage.purchase-order-service.dev.aex.systems/purchases/sources?collectorId={collectorId}&offSystem=true json title="Example Response" [ { "id": "45eccc98-3247-43c9-a398-3c3c2c5ad39d", "name": "Shop 2 Shop" }, { "id": "73a0f701-6a19-4146-ae90-2af6c1f14c7a", "name": "EFT" }, { "id": "906e5f88-6c5e-4a30-8044-74f8549632bc", "name": "Yoco" }, { "id": "95bfcea4-7fa6-494a-8def-11fd940763da", "name": "Cash" }, { "id": "e8cc35b7-192c-412e-9f1f-755c9835a0e8", "name": "Payment Link" }~~~~ ]

Update PayFast credit card

Hybrid day bundle type products have the auto-recharge property set on their billing schemes. This means that every time a purchase is fulfilled, a future dated purchase is automatically created to auto-recharge the service before the bundle runs out. Since this purchase is handled in a similar fashion as recurring purchases, it requires a tokenized credit card medium to process the payment. For these products, the credit card entered from the client interface for the upfront payment during sign-up is automatically tokenized by PayFast for this purpose.

If this credit card expires or needs to be replaced, the user can update it using the endpoint below. This call is made to Payment Service to initiate updating the medium, which will return a url to redirect the user to PayFast to enter their new credit card details.

GET https://stage.payment-service.dev.aex.systems/payfast-payments/card-medium-update/{mediumDetailId}

file_type_swagger GetCardMediumUpdateUrl

The response of this call will be a url that the caller should redirect to where the user will enter their new credit card details. Example of response: json title="Example Response" { "pay_fast_url": "https://www.payfast.co.za/eng/recurring/update/{token}" } The following query parameters should be added to the URL to redirect as required on completion of the PayFast card capturing: ?return={returnUrl}

For more information on the PayFast card update process, refer to the PayFast documentation.

Additional Requests for Configuration

The following requests are also made for relevant configuration options

Get Billing Scheme

Request to POS for the relevant product’s billing scheme, passing the previously selected productId.

GET https://purchase-order-service.national-za.aex.systems/configurations/billingScheme/Product/{productId}

file_type_swagger GetConfigurationTypeBillingScheme

Get Config

In process of being replaced by billing scheme

Request to POS for the relevant product’s billing scheme. No input parameters are passed and only the Operator ID contained within the token is used. Optionally productId can be passed, but it is not currently in use.

GET https://stage.purchase-order-service.dev.aex.systems/config

file_type_swagger GetRulesConfig