diff --git a/docs/az/docs/integrations/epoint/api-reference/client.md b/docs/az/docs/integrations/epoint/api-reference/client.md
index 83b8bea..412643b 100644
--- a/docs/az/docs/integrations/epoint/api-reference/client.md
+++ b/docs/az/docs/integrations/epoint/api-reference/client.md
@@ -39,3 +39,8 @@
- split_pay
- split_pay_with_saved_card
- split_pay_and_save_card
+ - create_widget
+ - create_token_payment
+ - apple_pay_session
+ - apple_pay
+ - google_pay
diff --git a/docs/az/docs/integrations/epoint/api-reference/response.md b/docs/az/docs/integrations/epoint/api-reference/response.md
index 61bfe79..ebdd091 100644
--- a/docs/az/docs/integrations/epoint/api-reference/response.md
+++ b/docs/az/docs/integrations/epoint/api-reference/response.md
@@ -16,6 +16,14 @@
::: integrify.epoint.schemas.response.SplitPayWithSavedCardResponseSchema
+## Apple Pay & Google Pay
+
+::: integrify.epoint.schemas.response.WidgetResponseSchema
+
+::: integrify.epoint.schemas.response.TokenPaymentResponseSchema
+
+::: integrify.epoint.schemas.response.TokenPayResponseSchema
+
## Extra
::: integrify.epoint.schemas.response.BaseWithCodeSchema
diff --git a/docs/az/docs/integrations/epoint/index.md b/docs/az/docs/integrations/epoint/index.md
index c4195e8..725c4e4 100644
--- a/docs/az/docs/integrations/epoint/index.md
+++ b/docs/az/docs/integrations/epoint/index.md
@@ -11,6 +11,11 @@
[Rusca](https://epointbucket.s3.eu-central-1.amazonaws.com/files/instructions/API%20Epoint%20ru.pdf)
+Markdown versiyaları (bu saytda):
+
+- [EPoint API (v1.0.3)](./official/api.md)
+- [Apple Pay & Google Pay (JS SDK)](./official/apple-google-pay.md)
+
## Sürətli başlanğıc { #quickstart }
Ödəniş yaratmaq, müştərini ödəniş səhifəsinə yönləndirmək və statusu yoxlamaq:
@@ -53,6 +58,122 @@ Asinxron istifadə üçün `EPointAsyncRequest` import edib, eyni metodları `aw
| [`split_pay`][integrify.epoint.client.EPointClientClass.split_pay] | Ödənişi başqa EPoint istifadəçisi ilə bölüb ödəmə | `/api/1/split-request` | :fontawesome-solid-check: |
| [`split_pay_with_saved_card`][integrify.epoint.client.EPointClientClass.split_pay_with_saved_card] | Saxlanılmış kartla ödənişi başqa EPoint istifadəçisi ilə bölüb ödəmə | `/api/1/split-execute-pay` | :x: |
| [`split_pay_and_save_card`][integrify.epoint.client.EPointClientClass.split_pay_and_save_card] | Ödənişi başqa EPoint istifadəçisi ilə bölüb ödəmə və kartı saxlamaq | `/api/1/split-card-registration-with-pay` | :fontawesome-solid-check: |
+| [`create_widget`][integrify.epoint.client.EPointClientClass.create_widget] | Apple Pay/Google Pay widget-i yaratmaq | `/api/1/token/widget` | :x: |
+| [`create_token_payment`][integrify.epoint.client.EPointClientClass.create_token_payment] | Apple Pay/Google Pay üçün token ödənişi yaratmaq | `/api/1/token/payment` | :x: |
+| [`apple_pay_session`][integrify.epoint.client.EPointClientClass.apple_pay_session] | Apple Pay session-u almaq | `/api/1/token/apple/session` | :x: |
+| [`apple_pay`][integrify.epoint.client.EPointClientClass.apple_pay] | Apple Pay ilə ödənişi tamamlamaq | `/api/1/token/apple/pay` | :x: |
+| [`google_pay`][integrify.epoint.client.EPointClientClass.google_pay] | Google Pay ilə ödənişi tamamlamaq | `/api/1/token/google/pay` | :x: |
+
+## Apple Pay & Google Pay { #apple-pay-google-pay }
+
+Apple Pay və Google Pay-i iki yolla qoşmaq olar:
+
+| Üsul | Nə vaxt | Backend sorğuları |
+| :--- | :------ | :---------------- |
+| **Widget** | Ən sadə yol: düymələr EPoint-in səhifəsində, iframe/webview daxilində göstərilir | [`create_widget`][integrify.epoint.client.EPointClientClass.create_widget] |
+| **JS SDK** | Düymələr birbaşa sizin səhifənizdə, öz dizaynınızla | [`create_token_payment`][integrify.epoint.client.EPointClientClass.create_token_payment], [`apple_pay_session`][integrify.epoint.client.EPointClientClass.apple_pay_session], [`apple_pay`][integrify.epoint.client.EPointClientClass.apple_pay], [`google_pay`][integrify.epoint.client.EPointClientClass.google_pay] |
+
+### Widget { #apple-google-pay-widget }
+
+```python
+from integrify.epoint import EPointRequest
+
+resp = EPointRequest.create_widget(amount=2.5, order_id='12345678', description='Ödəniş')
+widget_url = resp.body.widget_url # frontend-ə ötürün
+```
+
+`widget_url`-i saytda iframe, mobil tətbiqdə isə webview daxilində açın. Ödəniş bitdikdən sonra
+widget səhifəyə `message` event-i göndərir:
+
+```html
+
+
+
+```
+
+> **Qeyd**
+>
+> `event.data` brauzerdən gəldiyi üçün ona tam güvənməyin: ödənişin nəticəsini backend-də
+> [`get_transaction_status`][integrify.epoint.client.EPointClientClass.get_transaction_status] ilə yoxlayın.
+
+### JS SDK { #apple-google-pay-sdk }
+
+Bu üsulda düymələr EPoint-in JS SDK-sı (`epoint-token-pay`) vasitəsilə göstərilir.
+Axın belədir:
+
+1. **Backend:** [`create_token_payment`][integrify.epoint.client.EPointClientClass.create_token_payment] ilə EPoint-də token ödənişi yaradın.
+2. **Frontend:** SDK-nı qoşun, düymələri əlavə edin və `initTokenPay`-i 1-ci addımda gələn ödənişlə çağırın.
+3. **Apple Pay:** SDK sizin session endpoint-inizə müraciət edir → [`apple_pay_session`][integrify.epoint.client.EPointClientClass.apple_pay_session].
+4. **Ödəniş:** İstifadəçi ödənişi təsdiqlədikdən sonra SDK pay endpoint-inizə `id`, `token` və `billingContact` göndərir → [`apple_pay`][integrify.epoint.client.EPointClientClass.apple_pay] / [`google_pay`][integrify.epoint.client.EPointClientClass.google_pay].
+
+Session və pay endpoint-ləri EPoint-dən gələn cavabı **olduğu kimi** (`resp.body`) qaytarmalıdır.
+
+#### Frontend { #apple-google-pay-frontend }
+
+```html
+
+
+
+
+
+
+```
+
+#### Backend (FastAPI nümunəsi) { #apple-google-pay-backend }
+
+```python
+from fastapi import APIRouter, Request
+from integrify.epoint import EPointAsyncRequest
+
+router = APIRouter(prefix='/epoint')
+
+
+@router.post('/apple/session')
+async def apple_session(request: Request):
+ resp = await EPointAsyncRequest.apple_pay_session(origin=request.headers['origin'])
+ return resp.body
+
+
+@router.post('/apple')
+async def apple_pay(request: Request):
+ body = await request.json()
+ resp = await EPointAsyncRequest.apple_pay(
+ payment_id=body['id'],
+ token=body['token'],
+ billing_contact=body.get('billingContact'),
+ )
+ return resp.body.model_dump()
+
+
+@router.post('/google')
+async def google_pay(request: Request):
+ body = await request.json()
+ resp = await EPointAsyncRequest.google_pay(
+ payment_id=body['id'],
+ token=body['token'],
+ billing_contact=body.get('billingContact'),
+ )
+ return resp.body.model_dump()
+```
+
+> **Qeyd**
+>
+> `apple_pay`/`google_pay` sorğularının cavabında `redirect_url` gələ bilər (məs., 3DS üçün) — SDK bunu özü idarə edir.
+> Uğurlu ödənişdən sonra statusu [`get_transaction_status`][integrify.epoint.client.EPointClientClass.get_transaction_status] ilə də yoxlaya bilərsiniz.
## Callback Sorğusu { #callback-request }
diff --git a/docs/az/docs/integrations/epoint/official/api.md b/docs/az/docs/integrations/epoint/official/api.md
new file mode 100644
index 0000000..7b15d58
--- /dev/null
+++ b/docs/az/docs/integrations/epoint/official/api.md
@@ -0,0 +1,894 @@
+# EPoint API (v1.0.3)
+
+???+ info
+ Bu səhifə EPoint-in rəsmi API dokumentasiyasının (ingiliscə, v1.0.3) Markdown versiyasıdır.
+ Orijinal: [API Epoint en.pdf](https://epointbucket.s3.eu-central-1.amazonaws.com/files/instructions/API%20Epoint%20en.pdf).
+ Orijinalda kod nümunələri şəkil kimi verildiyi üçün, burada onlar parametr cədvəllərinə
+ əsasən yenidən yazılıb. Uyğunsuzluq olarsa, orijinal PDF əsas götürülür.
+
+**Epoint.az** — electronic payment platform. Solution for payment on site.
+
+## Contents
+
+- [Epoint payment page working principle](#working-principle)
+- [Formation of API request](#formation-of-api-request)
+- [Callback function processing](#callback-function-processing)
+- [Checking payment status](#checking-payment-status)
+- [Saving a card to make payments without entering card data](#card-registration)
+- [Executing a payment with a saved card](#execute-pay)
+- [Saving the card with the first payment made](#card-registration-with-pay)
+- [Request for disbursement of funds](#refund-request)
+- [Cancel operations](#reverse)
+- [Split payment request](#split-request)
+- [Executing a split payment with a stored card](#split-execute-pay)
+- [Saving the card with the first split payment](#split-card-registration-with-pay)
+- [Formation of API preauth request](#pre-auth-request)
+- [Apple Pay & Google Pay](#apple-pay-google-pay)
+- [Google Pay (integration for mobile applications)](#google-pay-mobile)
+- [Wallets](#wallets)
+- [Invoices](#invoices)
+- [Heartbeat API](#heartbeat)
+- [Bank Response Codes](#bank-response-codes)
+
+---
+
+Epoint system provides possibility to connect payment acceptance to your site. To add a payment
+button to your application you need to connect the payment service in your personal cabinet on our
+website.
+
+To set up a merchant in our system you will need to provide us with the following information:
+
+- your website address;
+- url of the page of successful payment — `success_url`;
+- url of the page for displaying information about unsuccessful payment — `error_url`;
+- url to send the result of payment — `result_url`.
+
+After checking this information, you will be given access keys: `public_key` — merchant ID in our
+system and `private_key` — secret API access key.
+
+## Epoint payment page working principle { #working-principle }
+
+1. It is necessary to form a request to the Epoint API according to the technical documentation.
+2. As a result of executing the request, the client will be redirected to the bank's payment page.
+3. The client fills in the card details and confirms the payment.
+4. In case of successful payment, the customer will be redirected to `success_url`, or `error_url` otherwise.
+5. The result of payment execution with payment details will be sent to the `result_url` specified by you.
+
+## Formation of API request { #formation-of-api-request }
+
+To call the Epoint API, you must send the `data` and `signature` parameters using the POST method to
+`https://epoint.az/api/1/request` or redirect the user using the POST method to
+`https://epoint.az/api/1/checkout`, where:
+
+- `data` — json string with API parameters encoded with base64 function, `base64_encode(json_string)`,
+- `signature` — unique signature for each request, `base64_encode(sha1(private_key + data + private_key, 1))`,
+- `base64_encode` — returns a string encoded in MIME base64 format,
+- `sha1` — returns a hash of a string of 20 characters (raw binary).
+
+### Formation of data and signature
+
+Parameters `json_string` of the api call:
+
+| Parameter | Required | Type | Description |
+| :--------------------- | :------- | :----- | :---------------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `amount` | Required | Number | The amount of the payment. For example: 100, 20.50 |
+| `currency` | Required | String | Payment currency. Possible values: `AZN` |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+| `order_id` | Required | String | The unique ID of the transaction in your application. Maximum length 255 characters. |
+| `description` | Optional | String | Payment description. No more than 1000 characters. |
+| `is_installment` | Optional | Number | Parameter defining the payment type. Possible values: `1` (installment) or `0` (standard) |
+| `success_redirect_url` | Optional | String | Redirection link in case of successful payment. |
+| `error_redirect_url` | Optional | String | Redirection link in case of unsuccessful payment. |
+| `other_attr` | Optional | Array | Additional payment options |
+
+`json_string` example:
+
+```json
+{
+ "public_key": "i000000001",
+ "amount": "30.75",
+ "currency": "AZN",
+ "description": "test payment",
+ "order_id": "1",
+ "language": "az"
+}
+```
+
+To form a signature, concatenate `private_key + data + private_key` and apply
+`base64_encode(sha1(sgn_string, 1))` to the resulting string:
+
+```php
+$data = base64_encode(json_encode($json_string));
+$signature = base64_encode(sha1($private_key . $data . $private_key, 1));
+```
+
+### Sending a request
+
+A form must be generated to send a request to the Epoint page:
+
+```html
+
+```
+
+Or send the received `data` and `signature` to `https://epoint.az/api/1/request`. In this case a
+json string will be returned with the value of `status` (`success|error`), `transaction` and
+`redirect_url` to which the user should be redirected to enter card data.
+
+After entering the card data, the user will be redirected to `success_redirect_url` or
+`error_redirect_url` depending on the payment status. Along with this, a POST request will be sent to
+`result_url` with payment details and transaction status.
+
+## Callback function processing { #callback-function-processing }
+
+After the transaction is processed by Epoint service and the payment status is received from the
+bank, a POST request with two parameters `data` and `signature` will be sent to your server
+(`result_url`).
+
+To authenticate a request from the Epoint server, you must:
+
+1. Generate a signature on your server side using the `data` received in the response from Epoint and your `private_key`.
+2. The received signature should be compared with the one received from Epoint. If the signatures
+ match, then you have received a genuine response from the Epoint server unmodified by a third party.
+
+To decode the `data` value you must execute:
+
+```php
+$result = json_decode(base64_decode($data), true);
+```
+
+Use the Payment Status API function to get the status of a transaction, which can be done at any time.
+
+Payment result parameters:
+
+| Parameter | Description |
+| :----------------- | :--------------------------------------------------------------------------------------------------- |
+| `order_id` | The unique ID of the transaction in your application. |
+| `status` | Operation result: `success` or `failed` |
+| `code` | Bank response code |
+| `message` | Payment execution status message |
+| `transaction` | Epoint service transaction |
+| `bank_transaction` | Bank payment transaction |
+| `bank_response` | Bank's response, with the result of payment processing |
+| `operation_code` | `001` — card registration, `100` — user payment |
+| `rrn` | Retrieval Reference Number — a unique transaction identifier. Present only for a successful transaction |
+| `card_name` | User name specified on the payment page |
+| `card_mask` | User card mask in the format: `123456******1234` |
+| `amount` | Payment amount |
+| `other_attr` | Additional parameters |
+
+## Checking payment status { #checking-payment-status }
+
+To invoke Epoint payment status check, you need to pass the `data` and `signature` parameters by POST
+method to `https://epoint.az/api/1/get-status`, where:
+
+- `data` — json string with API parameters encoded by function base64, `base64_encode(json_string)`,
+- `signature` — unique signature for each request, `base64_encode(sha1(private_key + data + private_key, 1))`.
+
+`json_string` example:
+
+```json
+{
+ "public_key": "i000000001",
+ "transaction": "te000000001"
+}
+```
+
+Response parameters:
+
+| Parameter | Description |
+| :----------------- | :--------------------------------------------------------------------------------------------------- |
+| `status` | Payment status |
+| `code` | Bank response code |
+| `message` | Payment execution status message |
+| `transaction` | Epoint service transaction |
+| `bank_transaction` | Bank payment transaction |
+| `bank_response` | Bank's response, with the result of payment processing |
+| `operation_code` | `001` — card registration, `100` — user payment |
+| `rrn` | Retrieval Reference Number — a unique transaction identifier. Present only for a successful transaction |
+| `card_name` | Username specified on the payment page |
+| `card_mask` | User card mask in `123456******1234` format |
+| `amount` | Payment amount |
+| `other_attr` | Additional parameters |
+
+Payment statuses:
+
+- `new` — payment is registered in the Epoint system;
+- `success` — successful payment;
+- `returned` — the payment has been refunded;
+- `error` — an error occurred during payment;
+- `server_error` — status check execution error.
+
+## Saving a card to make payments without entering card data { #card-registration }
+
+To call Epoint API you need to send `data` and `signature` parameters by POST method to
+`https://epoint.az/api/1/card-registration`.
+
+The `json_string` parameters of the api call:
+
+| Parameter | Required | Type | Description |
+| :--------------------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+| `refund` | Optional | Number | Card type: `0` — debit card; `1` — payout card. |
+| `description` | Optional | String | Payment description. No more than 1000 characters. |
+| `success_redirect_url` | Optional | String | Redirection link in case of successful payment. |
+| `error_redirect_url` | Optional | String | Redirection link in case of unsuccessful payment. |
+
+The request will return a json string with the `status` value (`success|error`) and `redirect_url` to
+which the user should be redirected to enter card data, and `card_id` — a unique card identifier
+that will be used to make payments.
+
+The client fills in the card information and confirms the payment. In case of success, the client
+will be redirected to `success_url`, or `error_url` otherwise (`success_redirect_url` and
+`error_redirect_url`, if specified).
+
+After the transaction is processed by Epoint service and the payment status is received from the
+bank, a POST request with two parameters `data` and `signature` will be sent to the `result_url`
+specified by you. Verify and decode it as described in
+[Callback function processing](#callback-function-processing).
+
+Response parameters:
+
+| Parameter | Description |
+| :----------------- | :--------------------------------------------------------------------------------------------------- |
+| `status` | Operation result: `success` or `failed` |
+| `code` | `000` — successful operation, `500` — error |
+| `message` | Operation progress status message |
+| `card_id` | The unique card identifier that will be used to make the payment |
+| `bank_transaction` | Bank payment transaction |
+| `bank_response` | Bank's response, with the result of payment processing |
+| `operation_code` | `001` — card registration, `100` — user payment |
+| `rrn` | Retrieval Reference Number — a unique transaction identifier. Present only for a successful transaction |
+| `card_name` | Username specified on the payment page |
+| `card_mask` | User card mask in `123456******1234` format |
+
+## Executing a payment with a saved card { #execute-pay }
+
+To make a payment with a stored card you need to send `data` and `signature` parameters by POST
+method to `https://epoint.az/api/1/execute-pay`.
+
+Parameters `json_string` of API call:
+
+| Parameter | Required | Type | Description |
+| :------------ | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+| `card_id` | Required | String | The card ID obtained by saving the card. |
+| `order_id` | Required | String | Unique transaction ID in your application. The maximum length is 255 characters. |
+| `amount` | Required | Number | Amount of payment. For example: 100, 20.50 |
+| `currency` | Required | String | Payment currency. Possible values: `AZN` |
+| `description` | Optional | String | Description of the payment. Not more than 1000 characters. |
+
+After processing the transaction by the Epoint service and receiving the payment status from the
+bank, a response will be returned with the following parameters:
+
+| Parameter | Description |
+| :----------------- | :--------------------------------------------------------------------------------------------------- |
+| `status` | Result of a `success` or `failed` operation |
+| `transaction` | Epoint transaction ID |
+| `bank_transaction` | Bank payment transaction |
+| `bank_response` | Bank response, with the result of payment processing |
+| `rrn` | Retrieval Reference Number — unique identifier of the transaction. Present only for successful transaction |
+| `card_name` | User name specified on the payment page |
+| `card_mask` | User card mask in `123456******1234` format |
+| `amount` | Amount of payment |
+| `message` | Error message |
+
+## Saving the card with the first payment made { #card-registration-with-pay }
+
+If you use this type of payment, you will be paid for the specified amount along with the card
+registration. To call the Epoint API, you need to pass the `data` and `signature` parameters by POST
+method to `https://epoint.az/api/1/card-registration-with-pay`.
+
+Parameters for the `json_string` call of the API:
+
+| Parameter | Required | Type | Description |
+| :--------------------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+| `order_id` | Required | String | Unique transaction ID in your application. The maximum length is 255 characters. |
+| `amount` | Required | Number | Amount of payment. For example: 100, 20.50 |
+| `currency` | Required | String | Payment currency. Possible values: `AZN` |
+| `description` | Optional | String | Description of the payment. Not more than 1000 characters. |
+| `success_redirect_url` | Optional | String | Redirection link in case of successful payment. |
+| `error_redirect_url` | Optional | String | Redirection link in case of failed payment. |
+
+As a result of the request, a json string with the `status` (`success|error`) value, `transaction`
+and `redirect_url` to which the user needs to be redirected to enter card data will be returned, and
+`card_id` — the unique identifier of the card that will need to be used to make payments.
+
+The customer fills in the card details and confirms payment. If the payment is successful, the client
+will be redirected to `success_url`, or `error_url` otherwise (`success_redirect_url` and
+`error_redirect_url` if specified).
+
+After processing the transaction, a POST request with `data` and `signature` parameters will be sent
+to the `result_url` indicated by you. Verify and decode it as described in
+[Callback function processing](#callback-function-processing).
+
+Response parameters:
+
+| Parameter | Description |
+| :----------------- | :--------------------------------------------------------------------------------------------------- |
+| `status` | Result of a `success` or `failed` operation |
+| `code` | `000` — successful operation |
+| `card_id` | Unique identifier of the card you want to use to make the payment |
+| `order_id` | Unique identifier of the payment in your application |
+| `transaction` | Epoint transaction ID |
+| `bank_transaction` | Bank payment transaction |
+| `bank_response` | Bank response, with the result of payment processing |
+| `operation_code` | `200` — card registration with the first payment |
+| `rrn` | Retrieval Reference Number — unique identifier of the transaction. Present only for successful transaction |
+| `card_mask` | User card mask in `123456******1234` format |
+| `card_name` | Name of the cardholder |
+| `amount` | Amount of payment |
+| `other_attr` | Advanced options |
+
+## Request for disbursement of funds { #refund-request }
+
+To request a payout of funds, you must send a POST request to `https://epoint.az/api/1/refund-request`
+with the `data` and `signature` parameters.
+
+API call `json_string` parameters:
+
+| Parameter | Required | Type | Description |
+| :------------ | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+| `card_id` | Required | String | The card ID received by the card saving method. |
+| `order_id` | Required | String | Unique transaction ID in your application. The maximum length is 255 characters. |
+| `amount` | Required | Number | Amount of payment. For example: 100, 20.50 |
+| `currency` | Required | String | Payment currency. Possible values: `AZN` |
+| `description` | Optional | String | Description of the payment. Not more than 1000 characters. |
+
+After processing the transaction by the Epoint service and receiving the payment status from the
+bank, a response will be returned with the following parameters:
+
+| Parameter | Description |
+| :----------------- | :--------------------------------------------------------------------------------------------------- |
+| `status` | Result of a `success` or `failed` operation |
+| `transaction` | Epoint transaction ID |
+| `bank_transaction` | Bank payment transaction |
+| `bank_response` | Bank response, with the result of payment processing |
+| `rrn` | Retrieval Reference Number — unique identifier of the transaction. Present only for successful transaction |
+| `card_mask` | User card mask in `123456******1234` format |
+| `card_name` | Name of the cardholder |
+| `amount` | Amount of payment |
+| `message` | Error message |
+
+## Cancel operations { #reverse }
+
+To cancel the operation, you must send a POST request to `https://epoint.az/api/1/reverse` with the
+`data` and `signature` parameters.
+
+API call `json_string` parameters:
+
+| Parameter | Required | Type | Description |
+| :------------ | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+| `transaction` | Required | String | Epoint transaction ID. |
+| `amount` | Optional | Number | Amount of payment. For example: 100, 20.50. You can specify a partial refund. |
+| `currency` | Required | String | Payment currency. Possible values: `AZN` |
+
+After processing, a response will be returned with the following parameters:
+
+| Parameter | Description |
+| :-------- | :------------------------------------------ |
+| `status` | Result of a `success` or `failed` operation |
+| `message` | Error message |
+
+## Split payment request { #split-request }
+
+To create a split payment, you need to pass the `data` and `signature` parameters by POST method to
+`https://epoint.az/api/1/split-request`.
+
+Parameters for the `json_string` call of the API:
+
+| Parameter | Required | Type | Description |
+| :--------------------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `amount` | Required | Number | Amount of payment. For example: 100, 20.50 |
+| `split_user` | Required | String | The ID of the second user in the Epoint system. |
+| `split_amount` | Required | Number | Payment amount for the second user. For example: 100, 20.50 |
+| `currency` | Required | String | Payment currency. Possible values: `AZN` |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+| `order_id` | Required | String | Unique transaction ID in your application. The maximum length is 255 characters. |
+| `description` | Optional | String | Description of the payment. Not more than 1000 characters. |
+| `success_redirect_url` | Optional | String | Redirection link in case of successful payment. |
+| `error_redirect_url` | Optional | String | Redirection link in case of failed payment. |
+| `other_attr` | Optional | Array | Additional payment options |
+
+In this case, a json string will be returned with the `status` (`success|error`) value, `transaction`
+and `redirect_url` to which the user must be redirected to enter card data.
+
+After processing the transaction, a POST request with `data` and `signature` parameters will be sent
+to your server (`result_url`). Verify and decode it as described in
+[Callback function processing](#callback-function-processing).
+
+Please note that the amount paid for the second merchant will only appear on their payment list.
+
+Payment result parameters:
+
+| Parameter | Description |
+| :----------------- | :--------------------------------------------------------------------------------------------------- |
+| `order_id` | Unique transaction ID in your application |
+| `status` | Result of a `success` or `failed` operation |
+| `code` | Bank response code |
+| `message` | Payment status message |
+| `transaction` | Epoint service transaction |
+| `bank_transaction` | Bank payment transaction |
+| `bank_response` | Bank response, with the result of payment processing |
+| `operation_code` | `001` — card registration, `100` — user payment |
+| `rrn` | Retrieval Reference Number — unique identifier of the transaction. Present only for successful transaction |
+| `card_name` | User name specified on the payment page |
+| `card_mask` | User card mask in `123456******1234` format |
+| `amount` | Amount of payment |
+| `split_amount` | Payment amount for the second user |
+| `other_attr` | Additional parameters |
+
+## Executing a split payment with a stored card { #split-execute-pay }
+
+To pay with a saved card, you must send the `data` and `signature` parameters by POST method to
+`https://epoint.az/api/1/split-execute-pay`.
+
+API call `json_string` parameters:
+
+| Parameter | Required | Type | Description |
+| :------------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+| `card_id` | Required | String | The card ID received by the card saving method. |
+| `order_id` | Required | String | Unique transaction ID in your application. The maximum length is 255 characters. |
+| `amount` | Required | Number | Amount of payment. For example: 100, 20.50 |
+| `split_user` | Required | String | The ID of the second user in the Epoint system. |
+| `split_amount` | Required | Number | Payment amount for the second user. For example: 100, 20.50 |
+| `currency` | Required | String | Payment currency. Possible values: `AZN` |
+| `description` | Optional | String | Description of the payment. Not more than 1000 characters. |
+
+After processing, a response will be returned with the following parameters:
+
+| Parameter | Description |
+| :----------------- | :--------------------------------------------------------------------------------------------------- |
+| `status` | Result of a `success` or `failed` operation |
+| `transaction` | Epoint transaction ID |
+| `bank_transaction` | Bank payment transaction |
+| `bank_response` | Bank response, with the result of payment processing |
+| `rrn` | Retrieval Reference Number — unique identifier of the transaction. Present only for successful transaction |
+| `card_mask` | User card mask in `123456******1234` format |
+| `card_name` | User name specified on the payment page |
+| `amount` | Amount of payment |
+| `message` | Error message |
+| `split_amount` | Payment amount for the second user |
+
+## Saving the card with the first split payment { #split-card-registration-with-pay }
+
+If you use this type of payment, you will be paid for the specified amount along with the card
+registration. To call the Epoint API, you need to pass the `data` and `signature` parameters by POST
+method to `https://epoint.az/api/1/split-card-registration-with-pay`.
+
+Parameters for the `json_string` call of the API:
+
+| Parameter | Required | Type | Description |
+| :--------------------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+| `order_id` | Required | String | Unique transaction ID in your application. The maximum length is 255 characters. |
+| `amount` | Required | Number | Amount of payment. For example: 100, 20.50 |
+| `split_user` | Required | String | The ID of the second user in the Epoint system. |
+| `split_amount` | Required | Number | Payment amount for the second user. For example: 100, 20.50 |
+| `currency` | Required | String | Payment currency. Possible values: `AZN` |
+| `description` | Optional | String | Description of the payment. Not more than 1000 characters. |
+| `success_redirect_url` | Optional | String | Redirection link in case of successful payment. |
+| `error_redirect_url` | Optional | String | Redirection link in case of failed payment. |
+
+As a result of the request, a json string with the `status` (`success|error`) value, `transaction`
+and `redirect_url` to which the user needs to be redirected to enter card data will be returned, and
+`card_id` — the unique identifier of the card that will need to be used to make payments.
+
+The customer fills in the card details and confirms payment. If the payment is successful, the client
+will be redirected to `success_url`, or `error_url` otherwise (`success_redirect_url` and
+`error_redirect_url` if specified). After processing, a POST request with `data` and `signature`
+parameters will be sent to the `result_url` indicated by you.
+
+Response parameters:
+
+| Parameter | Description |
+| :----------------- | :--------------------------------------------------------------------------------------------------- |
+| `status` | Result of a `success` or `failed` operation |
+| `code` | `000` — successful operation |
+| `card_id` | Unique identifier of the card you want to use to make the payment |
+| `order_id` | Unique identifier of the payment in your application |
+| `transaction` | Epoint transaction ID |
+| `bank_transaction` | Bank payment transaction |
+| `bank_response` | Bank response, with the result of payment processing |
+| `operation_code` | `200` — card registration with the first payment |
+| `rrn` | Retrieval Reference Number — unique identifier of the transaction. Present only for successful transaction |
+| `card_mask` | User card mask in `123456******1234` format |
+| `card_name` | Name of the cardholder |
+| `amount` | Payment amount |
+| `split_amount` | Payment amount for the second user |
+| `other_attr` | Advanced options |
+
+## Formation of API preauth request { #pre-auth-request }
+
+To call the Epoint API, you must send the `data` and `signature` parameters using the POST method to
+`https://epoint.az/api/1/pre-auth-request`. `data` and `signature` are formed the same way as in
+[Formation of API request](#formation-of-api-request).
+
+Parameters `json_string` of the api call:
+
+| Parameter | Required | Type | Description |
+| :--------------------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `amount` | Required | Number | The amount of the payment. For example: 100, 20.50 |
+| `currency` | Required | String | Payment currency. Possible values: `AZN` |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+| `order_id` | Required | String | The unique ID of the transaction in your application. Maximum length 255 characters. |
+| `description` | Optional | String | Payment description. No more than 1000 characters. |
+| `success_redirect_url` | Optional | String | Redirection link in case of successful payment. |
+| `error_redirect_url` | Optional | String | Redirection link in case of unsuccessful payment. |
+| `other_attr` | Optional | Array | Additional payment options |
+
+### Sending a preauth request
+
+Send the received `data` and `signature` to `https://epoint.az/api/1/pre-auth-request`. In this case a
+json string will be returned with the value of `status` (`success|error`), `transaction` and
+`redirect_url` to which user should be redirected to enter card data.
+
+After entering the card data, the user will be redirected to `success_redirect_url` or
+`error_redirect_url` depending on the payment status. Along with this, a POST request will be sent to
+`result_url` with payment details and transaction status.
+
+### Complete preauth request
+
+After the transaction is processed by Epoint service and the payment status is received from the
+bank, you should complete this payment, otherwise it will not be added to your Epoint balance. Until
+then, it will be shown on your pending balance in the business panel.
+
+Everything is the same when you want to complete the preauth request, only the body data differs.
+Use the endpoint `https://epoint.az/api/1/pre-auth-complete`.
+
+Parameters `json_string` of the api call:
+
+| Parameter | Required | Type | Description |
+| :------------ | :------- | :----- | :------------------------------------------------------------------------------------------------------------------ |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `amount` | Required | Number | The amount of the payment. For example: 100, 20.50 |
+| `transaction` | Required | String | Transaction id you got from Epoint (see [Callback function processing](#callback-function-processing)), e.g. `te001111111` |
+
+## Apple Pay & Google Pay { #apple-pay-google-pay }
+
+- **Google Pay:** for web integration.
+- **Apple Pay:** for both web and app integration.
+
+See also: [Apple Pay & Google Pay (JS SDK)](apple-google-pay.md) — the separate EPoint document for
+integrating the buttons directly into your page.
+
+### Create Widget Url (POST Request)
+
+You need to pass the `data` and `signature` to `https://epoint.az/api/1/token/widget`.
+
+| Parameter | Required | Type | Description |
+| :------------ | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `amount` | Required | Number | Amount of payment. For example: 100, 20.50 |
+| `order_id` | Required | String | Unique transaction ID in your application. The maximum length is 255 characters. |
+| `description` | Required | String | Description of the payment. Not more than 1000 characters. |
+
+```
+data = base64_encode(fields_in_json)
+```
+
+Fields in json:
+
+```json
+{
+ "public_key": "your_public_key_on_epoint",
+ "amount": 2.50,
+ "order_id": "order id generated by your system",
+ "description": "Test payment"
+}
+```
+
+```
+signature_string = private_key + data + private_key
+signature = base64_encode(sha1(signature_string))
+```
+
+Signature string:
+
+```
+signature_string = d3hjsl38sd8kdfhbcea0be04eafde9e8e2bad2fb092deyJwdWJsaWNfa2V5IjoiaTAwMDAwMDAwMSIsImFtb3VudCI6IjMwLjc1IiwiY3VycmVuY3kiOiJBWk4iLCJkZXNjcmlwdGlvbiI6InRlc3QgcGF5bWVudCIsIm9yZGVyX2lkIjoiMSJ9d3hjsl38sd8kdfhbcea0be04eafde9e8e2bad2fb092d
+```
+
+Example in PHP (Laravel):
+
+```php
+$payload = [
+ 'public_key' => 'public_key',
+ 'amount' => 2.50,
+ 'order_id' => 'order id generated by your system',
+ 'description' => 'Test payment',
+];
+
+$data = base64_encode(json_encode($payload));
+$private_key = 'your_private_key';
+$signature = base64_encode(sha1($private_key . $data . $private_key, 1));
+
+$request = Http::get("https://epoint.az/api/1/token/widget", [
+ 'data' => $data,
+ 'signature' => $signature
+]);
+
+$response = $request->json();
+```
+
+!!! note
+ The heading says POST, while the PHP example in the original uses `Http::get`. Integrify sends POST.
+
+Response:
+
+```json
+{
+ "status": "success",
+ "widget_url": "https://epointv1.test/api/1/token/widget/000001"
+}
+```
+
+When payment is finished inside of the iframe or webview you can listen to the iframe message:
+
+```javascript
+window.addEventListener('message', function(event) {
+ console.log(event.data); // {status: 'success', payment: {...}}
+});
+```
+
+## Google Pay (integration for mobile applications) { #google-pay-mobile }
+
+To integrate Google Pay into your mobile application, you must implement a native integration.
+
+1. Implement native integration following the official Google Pay documentation:
+
+2. Provide us with screenshots showing:
+ - the placement of the Google Pay button in your app interface;
+ - the appearance of the Google Pay button.
+3. After reviewing the submitted materials, we will provide you with a Merchant ID to complete the integration.
+
+## Wallets { #wallets }
+
+The Wallet API provides the following endpoints:
+
+1. `https://epoint.az/api/1/wallet/status` — to retrieve the list of wallets
+2. `https://epoint.az/api/1/wallet/payment` — to create a payment using a wallet
+
+### Wallet status
+
+To retrieve the list of wallets, the `public_key` parameter must be sent to
+`https://epoint.az/api/1/wallet/status` using the POST method.
+
+| Parameter | Required | Type | Description |
+| :----------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+
+!!! note
+ The original contains request submission and dynamic button creation examples (HTML/JS) only as
+ images; see the original PDF.
+
+### Wallet payment
+
+To create a payment using a wallet, the `data` and `signature` POST parameters must be sent to
+`https://epoint.az/api/1/wallet/payment`.
+
+| Parameter | Required | Type | Description |
+| :------------ | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `wallet_id` | Required | String | Selected wallet ID. |
+| `amount` | Required | Number | Amount of payment. For example: 100, 20.50 |
+| `currency` | Required | String | Payment currency. Possible values: `AZN` |
+| `order_id` | Required | String | Unique transaction ID in your application. The maximum length is 255 characters. |
+| `description` | Optional | String | Description of the payment. Not more than 1000 characters. |
+| `language` | Required | String | Page display language. Possible values: `az`, `en`, `ru` |
+
+## Invoices { #invoices }
+
+To call the Invoice API, you need to pass the `data` and `signature` parameters using the POST method
+to `https://epoint.az/api/1`. The Invoice API has the following endpoints:
+
+1. `/invoices/create` — creating an invoice
+2. `/invoices/update` — updating invoice information
+3. `/invoices/view` — viewing invoice information
+4. `/invoices/list` — viewing information on all invoices
+5. `/invoices/send-sms` — sending an SMS to the invoice recipient
+6. `/invoices/send-email` — sending an email to the invoice recipient
+
+Creating and updating an invoice has an additional optional parameter `invoice_images[]`, which
+contains images in jpg, png, jpeg, svg, bmp formats.
+
+### /invoices/create
+
+| Parameter | Required | Type | Description |
+| :------------------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `sum` | Required | Number | The amount of the payment. For example: 100, 20.50 |
+| `display` | Required | Number | Display invoice. Possible values: `1` or `0` |
+| `save_as_template` | Required | Number | Save invoice as template. Possible values: `1` or `0` |
+| `status_installment` | Optional | Number | Enables installment payments. Possible values: `1` or `0` |
+| `name` | Optional | String | Name |
+| `description` | Optional | String | Payment description. No more than 1000 characters. |
+| `phone` | Optional | String | Phone |
+| `email` | Optional | String | Email |
+| `inn` | Optional | String | TIN |
+| `contract_number` | Optional | String | Contract number |
+| `merchant_order_id` | Optional | String | Order ID |
+| `period_from` | Required | Date | Invoice start date |
+| `period_to` | Required | Date | Invoice end date |
+
+### /invoices/update
+
+| Parameter | Required | Type | Description |
+| :------------------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `id` | Required | Number | ID of the invoice being updated |
+| `sum` | Required | Number | The amount of the payment. For example: 100, 20.50 |
+| `display` | Required | Number | Display invoice. Possible values: `1` or `0` |
+| `save_as_template` | Required | Number | Save invoice as template. Possible values: `1` or `0` |
+| `status_installment` | Optional | Number | Enables installment payments. Possible values: `1` or `0` |
+| `name` | Optional | String | Name |
+| `description` | Optional | String | Payment description. No more than 1000 characters. |
+| `phone` | Optional | String | Phone |
+| `email` | Optional | String | Email |
+| `inn` | Optional | String | TIN |
+| `contract_number` | Optional | String | Contract number |
+| `merchant_order_id` | Optional | String | Order ID |
+| `period_from` | Required | Date | Invoice start date |
+| `period_to` | Required | Date | Invoice end date |
+
+### /invoices/view
+
+| Parameter | Required | Type | Description |
+| :----------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `id` | Required | Number | Invoice ID |
+
+### /invoices/list
+
+| Parameter | Required | Type | Description |
+| :----------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `type` | Optional | String | Invoice type — `incoming`, `outgoing`, `static` |
+| `order` | Optional | String | Sorting by ascending, descending |
+
+### /invoices/send-sms
+
+| Parameter | Required | Type | Description |
+| :----------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `id` | Required | Number | Invoice ID |
+| `phone` | Required | String | Phone |
+
+### /invoices/send-email
+
+| Parameter | Required | Type | Description |
+| :----------- | :------- | :----- | :---------------------------------------------------------------------------------- |
+| `public_key` | Required | String | The public key is the identifier of the created merchant. For example: `i000000001` |
+| `id` | Required | Number | Invoice ID |
+| `email` | Required | String | Email |
+
+## Heartbeat API { #heartbeat }
+
+To check the service availability, send a GET request to `https://epoint.az/api/heartbeat`.
+
+This endpoint is designed to verify if the service is operational. A successful response with
+`status: "ok"` indicates that the service is running properly.
+
+## Bank Response Codes { #bank-response-codes }
+
+| Code | Description |
+| :---- | :----------------------------------------------------------------------- |
+| `000` | Confirmed |
+| `100` | Rejected (general, no comment) |
+| `101` | Declined, your card has expired |
+| `102` | Rejected, suspected fraud |
+| `103` | Rejected, cardholder will contact acquirer |
+| `104` | Rejected, restricted card |
+| `105` | Rejected, card receiver will contact acquirer security |
+| `106` | Rejected, PIN attempts exceeded |
+| `107` | Declined, please contact your card issuer |
+| `108` | Declined, please refer to card issuer's special terms |
+| `109` | Rejected, invalid merchant |
+| `110` | Rejected, incorrect amount |
+| `111` | Rejected, incorrect card number |
+| `112` | Rejected, PIN required |
+| `113` | Denied, inappropriate payment |
+| `114` | Rejected, no account of the requested type |
+| `115` | Denied, requested function is not supported |
+| `116` | Declined, insufficient funds |
+| `117` | Rejected, incorrect PIN |
+| `118` | Rejected, no card data |
+| `119` | Rejected, transaction not allowed by cardholder |
+| `120` | Rejected, transaction not allowed to terminal |
+| `121` | Declined, withdrawal limit exceeded |
+| `122` | Rejected, safety violation |
+| `123` | Declined, withdrawal limit exceeded |
+| `124` | Rejected, violation of the law |
+| `125` | Rejected, card not valid |
+| `126` | Rejected, invalid PIN block |
+| `127` | Rejected, PIN length error |
+| `128` | Rejected, PIN key synchronization failed |
+| `129` | Rejected, suspected fake card |
+| `180` | Rejected, at the request of cardholders |
+| `200` | Pick-up (general, no comment) |
+| `201` | Pick-up, expired card |
+| `202` | Pick-up, suspected fraud |
+| `203` | Pick-up, the card receiver will contact the acquirer |
+| `204` | Pick-up, restricted card |
+| `205` | Pick-up, the cardholder will contact the acquirer's security department |
+| `206` | Pick-up, PIN limit exceeded |
+| `207` | Pick-up, special conditions |
+| `208` | Pick-up, lost card |
+| `209` | Pick-up, stolen card |
+| `210` | Pick-up, suspected fake card |
+| `300` | Status message: file action successful |
+| `301` | Status message: file action not supported by recipient |
+| `302` | Status message: could not find an entry in the file |
+| `303` | Status message: duplicate record, old record replaced |
+| `304` | Status message: file write field edit error |
+| `305` | Status message: file locked |
+| `306` | Status message: file action failed |
+| `307` | Status message: file data format error |
+| `308` | Status message: duplicate record, new record rejected |
+| `309` | Status message: unknown file |
+| `400` | Accepted (for cancellation) |
+| `499` | Confirmed, no original message data |
+| `500` | Status message: agreed, in the balance sheet |
+| `501` | Status message: agreed, out of balance |
+| `502` | Status message: amount not agreed, amount provided |
+| `503` | Status message: amount not available for negotiation |
+| `504` | Status message: not agreed, amount provided |
+| `600` | Accepted (for administrative information) |
+| `601` | Status message: original transaction cannot be tracked |
+| `602` | Status message: invalid transaction reference number |
+| `603` | Status message: link number/PANs are incompatible |
+| `604` | Status message: POS photo not available |
+| `605` | Status message: requested item provided |
+| `606` | Status message: request failed — required documentation unavailable |
+| `680` | The list is ready |
+| `681` | The list is not ready |
+| `700` | Accepted (for payment collection) |
+| `800` | Accepted (for network management) |
+| `900` | The recommendation has been taken into account, no financial obligations have been accepted |
+| `901` | Recommendations taken into account, financial liability accepted |
+| `902` | Rejection reason message: invalid transaction |
+| `903` | Status message: re-enter transaction |
+| `904` | Rejection reason message: format error |
+| `905` | Deviation cause message: acquirer not supported by switch |
+| `906` | Reason for deviation report: process reduction |
+| `907` | Reason for rejection message: card issuer or switch not in effect |
+| `908` | Rejection reason message: unable to find the destination of the routing transaction |
+| `909` | Cause of deviation report: system failure |
+| `910` | Reason for rejection message: card issuer disabled |
+| `911` | Reason for rejection message: card issuer expired |
+| `912` | Reason for rejection message: issuer unavailable |
+| `913` | Deviation cause message: duplicate transmission |
+| `914` | Rejection reason message: failed to track original transaction |
+| `915` | Deviation cause message: failure to disable negotiation or checkpoint |
+| `916` | Deviation cause message: MAC incorrect |
+| `917` | Reject cause message: MAC key synchronization error |
+| `918` | Rejection reason message: no binding keys available for use |
+| `919` | Reject cause message: encryption key synchronization error |
+| `920` | Cause of deviation message: software/hardware security error — try again |
+| `921` | Deviation cause message: software/hardware security error — no action |
+| `922` | Rejection reason message: incorrect message number sequence |
+| `923` | Status message: in-process query |
+| `950` | Reason for rejection message: business agreement violation |
+| `XXX` | Code to be replaced by card status code or stop list reason code |
+| `0Y1` | Confirmed, offline ICC |
+| `0Y3` | Confirmed, offline ICC |
+| `1Q1` | Rejected due to ICC offline mode |
+| `1Z1` | Rejected due to ICC offline mode |
+| `1Z3` | Rejected due to ICC offline mode |
diff --git a/docs/az/docs/integrations/epoint/official/apple-google-pay.md b/docs/az/docs/integrations/epoint/official/apple-google-pay.md
new file mode 100644
index 0000000..870ba62
--- /dev/null
+++ b/docs/az/docs/integrations/epoint/official/apple-google-pay.md
@@ -0,0 +1,291 @@
+# EPoint — Apple Pay & Google Pay (JS SDK)
+
+???+ info
+ Bu səhifə EPoint-in "Epoint.az - Apple Pay & Google Pay" sənədinin Markdown versiyasıdır
+ (ictimai linki yoxdur). Bu sənəd düymələrin birbaşa sizin səhifənizə, EPoint JS SDK-sı ilə
+ qoşulmasını izah edir. Daha sadə, iframe/webview əsaslı üsul üçün rəsmi API sənədindəki
+ [Apple Pay & Google Pay (widget)](api.md#apple-pay-google-pay) bölməsinə baxın.
+
+## Client
+
+To add Apple Pay and Google Pay buttons to your web page (site) or app, you can use the code below.
+
+HTML implementation:
+
+```html
+
+
+
+
+```
+
+## 1. Create Payment { #create-payment }
+
+After adding buttons to the view you need to initialize them, but before that you need to create a
+tokenized payment on Epoint, so all tokenized operations will be referenced to this payment. You can
+get payment information by sending a request to `/api/1/token/payment`.
+
+You need to add 2 parameters to the request: `data`, `signature`.
+
+- **data:** base64 encoded form of your json data like below.
+ Fields: `public_key`, `amount`, `currency`, `language`, `order_id`, `description`.
+ `data = base64_encode(fields_in_json)`
+
+Fields in json:
+
+```json
+{
+ "public_key": "your_public_key_on_epoint",
+ "amount": 2.50,
+ "currency": "AZN",
+ "language": "az",
+ "order_id": "order id generated by your system",
+ "description": "Test payment"
+}
+```
+
+```
+signature_string = private_key + data + private_key
+signature = base64_encode(sha1(signature_string))
+```
+
+Signature string:
+
+```
+signature_string = d3hjsl38sd8kdfhbcea0be04eafde9e8e2bad2fb092deyJwdWJsaWNfa2V5IjoiaTAwMDAwMDAwMSIsImFtb3VudCI6IjMwLjc1IiwiY3VycmVuY3kiOiJBWk4iLCJkZXNjcmlwdGlvbiI6InRlc3QgcGF5bWVudCIsIm9yZGVyX2lkIjoiMSJ9d3hjsl38sd8kdfhbcea0be04eafde9e8e2bad2fb092d
+```
+
+Example in PHP (Laravel):
+
+```php
+$payload = [
+ 'public_key' => 'public_key',
+ 'amount' => 2.50,
+ 'currency' => 'AZN',
+ 'language' => 'az',
+ 'order_id' => 'order id generated by your system',
+ 'description' => 'Test payment',
+];
+
+$data = base64_encode(json_encode($payload));
+$private_key = 'your_private_key';
+$signature = base64_encode(sha1($private_key . $data . $private_key, 1));
+
+$request = Http::post("https://epoint.az/api/1/token/payment", [
+ 'data' => $data,
+ 'signature' => $signature
+]);
+
+$response = $request->json();
+```
+
+Response sample:
+
+```json
+{
+ "id": 9998887,
+ "transaction": "12345",
+ "rrn": "123",
+ "short_link": "a1b2",
+ "bank_order_id": "aaa111",
+ "total": 2.36,
+ "card_name": "Name",
+ "card_mask": "4000********1234",
+ "description": "test description",
+ "merchant_order_id": "111222333",
+ "other_attr": "other attributes",
+ "created_at": "2024-10-16 12:09:10",
+ "updated_at": "2024-10-16 15:00:48"
+}
+```
+
+## 2. Initialize Token Payments { #initialize-token-payments }
+
+To initialize token payments you need to call the `initTokenPay` method with some parameters:
+
+- **payment**: payment information that you created and got from Epoint
+- **endpoints**: you need to implement Apple and Google Pay endpoints (see below)
+- **onError**: get any errors that happened while initializing or paying
+- **onSuccess**: get success result after payment
+
+```html
+
+```
+
+## Apple Pay implementation { #apple-pay }
+
+You need to implement 2 endpoints for the Epoint token pay SDK for Apple Pay:
+
+- **Session:** Apple Pay has an additional layer for which you must create an endpoint that gets a
+ session from Epoint and provides it to the Epoint token pay SDK.
+- **Pay:** you need to create an endpoint for completing the payment after the session is
+ successfully created and your user validates the Apple Pay popup (choose card, confirm pay).
+
+## 3. Apple Pay Session { #apple-pay-session }
+
+You can get a session by sending a request to `/api/1/token/apple/session`. Create a **POST**
+endpoint on your backend and just return the response from Epoint.
+
+You need to add 2 parameters to the request: `data`, `signature`.
+
+- **data:** base64 encoded form of your json data like below.
+ Fields: `public_key`, `origin`.
+ `data = base64_encode(fields_in_json)`
+
+Fields in json:
+
+```json
+{
+ "public_key": "your_public_key_on_epoint",
+ "origin": "https://yoursite.az"
+}
+```
+
+```
+signature_string = private_key + data + private_key
+signature = base64_encode(sha1(signature_string))
+```
+
+Example:
+
+```php
+$payload = [
+ 'public_key' => $public_key,
+ 'origin' => request()->header('origin')
+];
+
+$data = base64_encode(json_encode($payload));
+$signature = base64_encode(sha1($private_key . $data . $private_key, 1));
+
+$request = Http::post("$api_url/token/apple/session", [
+ 'data' => $data,
+ 'signature' => $signature
+]);
+```
+
+## 4. Apple Pay Payment { #apple-pay-payment }
+
+You can complete the payment by sending a request to `/api/1/token/apple/pay`. Create a **POST**
+endpoint on your backend and just return the response from Epoint.
+
+You need to add 2 parameters to the request: `data`, `signature`.
+
+- **data:** base64 encoded form of your json data like below.
+ Fields: `public_key`, `id`, `token`, `billingContact`.
+ You will just add `public_key` manually; other fields will come from the request (see example).
+ `data = base64_encode(fields_in_json)`
+
+Fields in json:
+
+```json
+{
+ "public_key": "your_public_key_on_epoint",
+ "id": "id_from_request",
+ "token": "token_from_request",
+ "billingContact": "billingContact_from_request"
+}
+```
+
+```
+signature_string = private_key + data + private_key
+signature = base64_encode(sha1(signature_string))
+```
+
+Example:
+
+```php
+$payload = [
+ 'public_key' => $public_key,
+ 'id' => $request->get('id'),
+ 'token' => $request->get('token'),
+ 'billingContact' => $request->get('billingContact'),
+];
+$data = base64_encode(json_encode($payload));
+$signature = base64_encode(sha1($private_key . $data . $private_key, 1));
+
+$request = Http::post("$api_url/token/apple/pay", [
+ 'data' => $data,
+ 'signature' => $signature
+]);
+```
+
+## 4.1. Google Pay Payment { #google-pay-payment }
+
+It is the same as with Apple Pay, just the endpoint changes.
+
+You can complete the payment by sending a request to `/api/1/token/google/pay`. Create a **POST**
+endpoint on your backend and just return the response from Epoint.
+
+You need to add 2 parameters to the request: `data`, `signature`.
+
+- **data:** base64 encoded form of your json data like below.
+ Fields: `public_key`, `id`, `token`, `billingContact`.
+ You will just add `public_key` manually; other fields will come from the request (see example).
+ `data = base64_encode(fields_in_json)`
+
+Fields in json:
+
+```json
+{
+ "public_key": "your_public_key_on_epoint",
+ "id": "id_from_request",
+ "token": "token_from_request",
+ "billingContact": "billingContact_from_request"
+}
+```
+
+```
+signature_string = private_key + data + private_key
+signature = base64_encode(sha1(signature_string))
+```
+
+Example:
+
+```php
+$payload = [
+ 'public_key' => $public_key,
+ 'id' => $request->get('id'),
+ 'token' => $request->get('token'),
+ 'billingContact' => $request->get('billingContact'),
+];
+$data = base64_encode(json_encode($payload));
+$signature = base64_encode(sha1($private_key . $data . $private_key, 1));
+
+$request = Http::post("$api_url/token/google/pay", [
+ 'data' => $data,
+ 'signature' => $signature
+]);
+```
+
+Finish payment response sample:
+
+```php
+{
+ 'status' => 'success',
+ 'message' => 'Payment is finished successfully',
+ 'result' => {}, // response from psp
+ 'redirect_url' => '' // optional -> sometimes not exists
+}
+```
diff --git a/docs/az/mkdocs.yml b/docs/az/mkdocs.yml
index 7b97279..550edc9 100644
--- a/docs/az/mkdocs.yml
+++ b/docs/az/mkdocs.yml
@@ -125,6 +125,9 @@ nav:
- Response: integrations/epoint/api-reference/response.md
- Callback: integrations/epoint/api-reference/callback.md
- integrations/epoint/api-reference/helper-functions.md
+ - Rəsmi Dokumentasiya:
+ - "API (v1.0.3)": integrations/epoint/official/api.md
+ - "Apple Pay & Google Pay (JS SDK)": integrations/epoint/official/apple-google-pay.md
- Kapital Bank:
- integrations/kapitalbank/index.md
- integrations/kapitalbank/env.md
diff --git a/packages/epoint/CHANGELOG.md b/packages/epoint/CHANGELOG.md
index 36372cc..09643aa 100644
--- a/packages/epoint/CHANGELOG.md
+++ b/packages/epoint/CHANGELOG.md
@@ -4,6 +4,14 @@ All notable changes to `integrify-epoint` are documented here. The format is bas
on [Keep a Changelog](https://keepachangelog.com/) and this project follows
[Semantic Versioning](https://semver.org/).
+## [1.3.0] - 2026-09-22
+
+### Added
+
+- Apple Pay & Google Pay widget: `create_widget` (`/api/1/token/widget`), returning a `widget_url` to embed in an iframe/webview.
+- Apple Pay & Google Pay via EPoint's JS SDK (token payment API): `create_token_payment`, `apple_pay_session`, `apple_pay`, `google_pay`.
+- `WidgetResponseSchema`, `TokenPaymentResponseSchema` and `TokenPayResponseSchema` response schemas.
+
## [1.2.0] - 2026-08-11
### Added
@@ -34,6 +42,7 @@ on [Keep a Changelog](https://keepachangelog.com/) and this project follows
- Initial release — refactored from the [old library](https://github.com/mmzeynalli/integrify) to the new style.
+[1.3.0]: https://github.com/integrify-sdk/integrify-python/compare/epoint-1.2.0...epoint-1.3.0
[1.2.0]: https://github.com/integrify-sdk/integrify-python/compare/epoint-1.1.0...epoint-1.2.0
[1.1.0]: https://github.com/integrify-sdk/integrify-python/compare/epoint-1.0.0...epoint-1.1.0
[1.0.0]: https://github.com/integrify-sdk/integrify-python/releases/tag/epoint-1.0.0
diff --git a/packages/epoint/README.md b/packages/epoint/README.md
index 74ecee0..a6f7926 100644
--- a/packages/epoint/README.md
+++ b/packages/epoint/README.md
@@ -65,6 +65,11 @@ Sorğular uğurlu və ya uğursuz olduqda, spesifik URL-ə yönləndirmək istə
| `split_pay` | Ödənişi başqa EPoint istifadəçisi ilə bölüb ödəmə | `/api/1/split-request` | ✅ |
| `split_pay_with_saved_card` | Saxlanılmış kartla ödənişi başqa EPoint istifadəçisi ilə bölüb ödəmə | `/api/1/split-execute-pay` | ❌ |
| `split_pay_and_save_card` | Ödənişi başqa EPoint istifadəçisi ilə bölüb ödəmə və kartı saxlamaq | `/api/1/split-card-registration-with-pay` | ✅ |
+| `create_widget` | Apple Pay/Google Pay widget-i yaratmaq | `/api/1/token/widget` | ❌ |
+| `create_token_payment` | Apple Pay/Google Pay üçün token ödənişi yaratmaq | `/api/1/token/payment` | ❌ |
+| `apple_pay_session` | Apple Pay session-u almaq | `/api/1/token/apple/session` | ❌ |
+| `apple_pay` | Apple Pay ilə ödənişi tamamlamaq | `/api/1/token/apple/pay` | ❌ |
+| `google_pay` | Google Pay ilə ödənişi tamamlamaq | `/api/1/token/google/pay` | ❌ |
### Callback Sorğusu
diff --git a/packages/epoint/pyproject.toml b/packages/epoint/pyproject.toml
index 304e733..20d7c14 100644
--- a/packages/epoint/pyproject.toml
+++ b/packages/epoint/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "integrify-epoint"
-version = "1.2.0"
+version = "1.3.0"
description = "Integrify API inteqrasiyalarını rahatlaşdıran sorğular kitabaxanasıdır. Bu kitabxana Epoint inteqrasiyası üçün nəzərdə tutulmuşdur."
authors = [{ name = "mmzeynalli", email = "miradil.zeynalli@gmail.com" }]
requires-python = ">=3.10"
diff --git a/packages/epoint/src/integrify/epoint/client.py b/packages/epoint/src/integrify/epoint/client.py
index 1b3cff3..29e2ae7 100644
--- a/packages/epoint/src/integrify/epoint/client.py
+++ b/packages/epoint/src/integrify/epoint/client.py
@@ -5,7 +5,12 @@
from integrify.api import APIClient, _Async, _Mode, _Sync
from integrify.epoint import env
from integrify.epoint.handlers import (
+ ApplePayPayloadHandler,
+ ApplePaySessionPayloadHandler,
+ CreateTokenPaymentPayloadHandler,
+ CreateWidgetPayloadHandler,
GetTransactionStatusPayloadHandler,
+ GooglePayPayloadHandler,
PayAndSaveCardPayloadHandler,
PaymentPayloadHandler,
PayoutPayloadHandler,
@@ -22,7 +27,10 @@
RedirectUrlResponseSchema,
RedirectUrlWithCardIdResponseSchema,
SplitPayWithSavedCardResponseSchema,
+ TokenPaymentResponseSchema,
+ TokenPayResponseSchema,
TransactionStatusResponseSchema,
+ WidgetResponseSchema,
)
from integrify.schemas import APIResponse
from integrify.utils import UNSET, Unset
@@ -73,6 +81,22 @@ def __init__(
self.add_url('split_pay_and_save_card', env.API.SPLIT_PAY_AND_SAVE_CARD, verb='POST')
self.add_handler('split_pay_and_save_card', SplitPayAndSaveCardPayloadHandler)
+ # Apple Pay & Google Pay
+ self.add_url('create_widget', env.API.CREATE_WIDGET, verb='POST')
+ self.add_handler('create_widget', CreateWidgetPayloadHandler)
+
+ self.add_url('create_token_payment', env.API.CREATE_TOKEN_PAYMENT, verb='POST')
+ self.add_handler('create_token_payment', CreateTokenPaymentPayloadHandler)
+
+ self.add_url('apple_pay_session', env.API.APPLE_PAY_SESSION, verb='POST')
+ self.add_handler('apple_pay_session', ApplePaySessionPayloadHandler)
+
+ self.add_url('apple_pay', env.API.APPLE_PAY, verb='POST')
+ self.add_handler('apple_pay', ApplePayPayloadHandler)
+
+ self.add_url('google_pay', env.API.GOOGLE_PAY, verb='POST')
+ self.add_handler('google_pay', GooglePayPayloadHandler)
+
if TYPE_CHECKING:
# pylint: disable=missing-function-docstring,unused-argument
@@ -497,6 +521,227 @@ def split_pay_and_save_card(
) -> Coroutine[Any, Any, APIResponse[RedirectUrlWithCardIdResponseSchema]]: ...
def split_pay_and_save_card(self, *args: Any, **kwds: Any) -> Any: ...
+ @overload
+ def create_widget(
+ self: 'EPointClientClass[_Sync]',
+ amount: Numeric,
+ order_id: str,
+ description: str,
+ ) -> APIResponse[WidgetResponseSchema]:
+ """Apple Pay və Google Pay widget-i yaratma sorğusu
+
+ **Endpoint:** */api/1/token/widget*
+
+ Example:
+ ```python
+ from integrify.epoint import EPointRequest
+
+ EPointRequest.create_widget(amount=2.5, order_id='12345678', description='Ödəniş')
+ ```
+
+ **Cavab formatı**: [`WidgetResponseSchema`][integrify.epoint.schemas.response.WidgetResponseSchema]
+
+ Apple Pay/Google Pay-i qoşmağın ən sadə yolu. Cavabda gələn `widget_url`-i saytınızda
+ iframe, mobil tətbiqdə isə webview daxilində açın: düymələr və ödəniş axını EPoint
+ tərəfindən idarə olunur, əlavə backend endpoint-lərinə ehtiyac yoxdur. Ödəniş bitdikdən
+ sonra widget səhifəyə `message` event-i göndərir (`event.data`:
+ `{status: 'success', payment: {...}}`). Ödənişin nəticəsini backend-də
+ [`get_transaction_status`][integrify.epoint.client.EPointClientClass.get_transaction_status]
+ ilə yoxlamaq tövsiyə olunur.
+
+ Düymələri öz dizaynınızla göstərmək istəyirsinizsə,
+ [`create_token_payment`][integrify.epoint.client.EPointClientClass.create_token_payment]
+ ilə başlayan SDK axınından istifadə edin.
+
+ Args:
+ amount: Ödəniş miqdarı. Numerik dəyər.
+ order_id: Unikal ID. Maksimal uzunluq: 255 simvol.
+ description: Ödənişin təsviri. Maksimal uzunluq: 1000 simvol.
+ """ # noqa: E501
+
+ @overload
+ def create_widget(
+ self: 'EPointClientClass[_Async]',
+ amount: Numeric,
+ order_id: str,
+ description: str,
+ ) -> Coroutine[Any, Any, APIResponse[WidgetResponseSchema]]: ...
+ def create_widget(self, *args: Any, **kwds: Any) -> Any: ...
+
+ @overload
+ def create_token_payment(
+ self: 'EPointClientClass[_Sync]',
+ amount: Numeric,
+ currency: str,
+ order_id: str,
+ description: Unset[str] = UNSET,
+ ) -> APIResponse[TokenPaymentResponseSchema]:
+ """Apple Pay/Google Pay üçün token ödənişi yaratma sorğusu
+
+ **Endpoint:** */api/1/token/payment*
+
+ Example:
+ ```python
+ from integrify.epoint import EPointRequest
+
+ EPointRequest.create_token_payment(amount=2.5, currency='AZN', order_id='12345678', description='Ödəniş')
+ ```
+
+ **Cavab formatı**: [`TokenPaymentResponseSchema`][integrify.epoint.schemas.response.TokenPaymentResponseSchema]
+
+ Apple Pay/Google Pay düymələrini işə salmazdan əvvəl, EPoint-də token ödənişi
+ yaradılmalıdır: bütün sonrakı token əməliyyatları bu ödənişə istinad edir. Cavabda gələn
+ ödəniş obyektini (ən azı `id` və məbləği) frontend-də `initTokenPay`-ə `payment`
+ parametri kimi ötürün. Sonra SDK sizin backend-inizdəki
+ [`apple_pay_session`][integrify.epoint.client.EPointClientClass.apple_pay_session],
+ [`apple_pay`][integrify.epoint.client.EPointClientClass.apple_pay] və
+ [`google_pay`][integrify.epoint.client.EPointClientClass.google_pay] sorğularını
+ çağıran endpoint-lərə müraciət edəcək.
+
+ Args:
+ amount: Ödəniş miqdarı. Numerik dəyər.
+ currency: Ödəniş məzənnəsi. Mümkün dəyərlər: AZN
+ order_id: Unikal ID. Maksimal uzunluq: 255 simvol.
+ description: Ödənişin təsviri. Məcburi arqument deyil.
+ """ # noqa: E501
+
+ @overload
+ def create_token_payment(
+ self: 'EPointClientClass[_Async]',
+ amount: Numeric,
+ currency: str,
+ order_id: str,
+ description: Unset[str] = UNSET,
+ ) -> Coroutine[Any, Any, APIResponse[TokenPaymentResponseSchema]]: ...
+ def create_token_payment(self, *args: Any, **kwds: Any) -> Any: ...
+
+ @overload
+ def apple_pay_session(
+ self: 'EPointClientClass[_Sync]',
+ origin: str,
+ ) -> APIResponse[dict]:
+ """Apple Pay session-u almaq sorğusu
+
+ **Endpoint:** */api/1/token/apple/session*
+
+ Example:
+ ```python
+ from integrify.epoint import EPointRequest
+
+ EPointRequest.apple_pay_session(origin='https://yoursite.az')
+ ```
+
+ **Cavab formatı**: `dict` (Apple merchant session obyekti, olduğu kimi)
+
+ Apple Pay-in əlavə təhlükəsizlik qatı var: SDK ödəniş pəncərəsini açmazdan əvvəl
+ sizin backend-inizdəki session endpoint-inə (məs., `/epoint/apple/session`) POST
+ sorğusu göndərir. Həmin endpoint bu sorğunu çağırıb, `resp.body`-ni olduğu kimi
+ geri qaytarmalıdır.
+
+ Args:
+ origin: Ödəniş səhifəsinin açıldığı saytın origin-i (məs., `https://yoursite.az`).
+ Adətən daxil olan sorğunun `Origin` header-indən götürülür.
+ """ # noqa: E501
+
+ @overload
+ def apple_pay_session(
+ self: 'EPointClientClass[_Async]',
+ origin: str,
+ ) -> Coroutine[Any, Any, APIResponse[dict]]: ...
+ def apple_pay_session(self, *args: Any, **kwds: Any) -> Any: ...
+
+ @overload
+ def apple_pay(
+ self: 'EPointClientClass[_Sync]',
+ payment_id: int | str,
+ token: Any,
+ billing_contact: Any = None,
+ ) -> APIResponse[TokenPayResponseSchema]:
+ """Apple Pay ilə ödənişi tamamlama sorğusu
+
+ **Endpoint:** */api/1/token/apple/pay*
+
+ Example:
+ ```python
+ from integrify.epoint import EPointRequest
+
+ # body: SDK-nın sizin `/epoint/apple` endpoint-inə göndərdiyi JSON
+ EPointRequest.apple_pay(
+ payment_id=body['id'],
+ token=body['token'],
+ billing_contact=body.get('billingContact'),
+ )
+ ```
+
+ **Cavab formatı**: [`TokenPayResponseSchema`][integrify.epoint.schemas.response.TokenPayResponseSchema]
+
+ Session uğurla yaradıldıqdan və istifadəçi Apple Pay pəncərəsində ödənişi
+ təsdiqlədikdən sonra (kart seçimi, təsdiq), SDK sizin backend-inizdəki pay
+ endpoint-inə (məs., `/epoint/apple`) `id`, `token` və `billingContact` göndərir.
+ Həmin endpoint bu sorğunu çağırıb, `resp.body`-ni olduğu kimi geri qaytarmalıdır.
+ `public_key` avtomatik əlavə olunur.
+
+ Args:
+ payment_id: Token ödənişinin IDsi (SDK sorğusundakı `id`).
+ token: Apple Pay token-i (SDK sorğusundakı `token`).
+ billing_contact: Ödəyicinin billing məlumatı (SDK sorğusundakı `billingContact`).
+ """ # noqa: E501
+
+ @overload
+ def apple_pay(
+ self: 'EPointClientClass[_Async]',
+ payment_id: int | str,
+ token: Any,
+ billing_contact: Any = None,
+ ) -> Coroutine[Any, Any, APIResponse[TokenPayResponseSchema]]: ...
+ def apple_pay(self, *args: Any, **kwds: Any) -> Any: ...
+
+ @overload
+ def google_pay(
+ self: 'EPointClientClass[_Sync]',
+ payment_id: int | str,
+ token: Any,
+ billing_contact: Any = None,
+ ) -> APIResponse[TokenPayResponseSchema]:
+ """Google Pay ilə ödənişi tamamlama sorğusu
+
+ **Endpoint:** */api/1/token/google/pay*
+
+ Example:
+ ```python
+ from integrify.epoint import EPointRequest
+
+ # body: SDK-nın sizin `/epoint/google` endpoint-inə göndərdiyi JSON
+ EPointRequest.google_pay(
+ payment_id=body['id'],
+ token=body['token'],
+ billing_contact=body.get('billingContact'),
+ )
+ ```
+
+ **Cavab formatı**: [`TokenPayResponseSchema`][integrify.epoint.schemas.response.TokenPayResponseSchema]
+
+ Apple Pay ilə eynidir, yalnız endpoint fərqlidir və session mərhələsi yoxdur.
+ İstifadəçi Google Pay pəncərəsində ödənişi təsdiqlədikdən sonra, SDK sizin
+ backend-inizdəki pay endpoint-inə (məs., `/epoint/google`) `id`, `token` və
+ `billingContact` göndərir. Həmin endpoint bu sorğunu çağırıb, `resp.body`-ni
+ olduğu kimi geri qaytarmalıdır. `public_key` avtomatik əlavə olunur.
+
+ Args:
+ payment_id: Token ödənişinin IDsi (SDK sorğusundakı `id`).
+ token: Google Pay token-i (SDK sorğusundakı `token`).
+ billing_contact: Ödəyicinin billing məlumatı (SDK sorğusundakı `billingContact`).
+ """ # noqa: E501
+
+ @overload
+ def google_pay(
+ self: 'EPointClientClass[_Async]',
+ payment_id: int | str,
+ token: Any,
+ billing_contact: Any = None,
+ ) -> Coroutine[Any, Any, APIResponse[TokenPayResponseSchema]]: ...
+ def google_pay(self, *args: Any, **kwds: Any) -> Any: ...
+
EPointRequest: 'EPointClientClass[_Sync]' = EPointClientClass(sync=True)
EPointAsyncRequest: 'EPointClientClass[_Async]' = EPointClientClass(sync=False)
diff --git a/packages/epoint/src/integrify/epoint/env.py b/packages/epoint/src/integrify/epoint/env.py
index 115f00d..8f933fa 100644
--- a/packages/epoint/src/integrify/epoint/env.py
+++ b/packages/epoint/src/integrify/epoint/env.py
@@ -36,6 +36,13 @@ class API(str, Enum):
SPLIT_PAY_WITH_SAVED_CARD = '/api/1/split-execute-pay'
SPLIT_PAY_AND_SAVE_CARD = '/api/1/split-card-registration-with-pay'
+ # Apple Pay & Google Pay
+ CREATE_WIDGET = '/api/1/token/widget'
+ CREATE_TOKEN_PAYMENT = '/api/1/token/payment' # nosec: B105
+ APPLE_PAY_SESSION = '/api/1/token/apple/session'
+ APPLE_PAY = '/api/1/token/apple/pay'
+ GOOGLE_PAY = '/api/1/token/google/pay'
+
__all__ = [
'VERSION',
diff --git a/packages/epoint/src/integrify/epoint/handlers.py b/packages/epoint/src/integrify/epoint/handlers.py
index 477dc3f..7fe2b87 100644
--- a/packages/epoint/src/integrify/epoint/handlers.py
+++ b/packages/epoint/src/integrify/epoint/handlers.py
@@ -7,7 +7,12 @@
from integrify.epoint.helpers import generate_signature
from integrify.epoint.schemas.enums import TransactionStatus, TransactionStatusExtended
from integrify.epoint.schemas.request import (
+ ApplePayRequestSchema,
+ ApplePaySessionRequestSchema,
+ CreateTokenPaymentRequestSchema,
+ CreateWidgetRequestSchema,
GetTransactionStatusRequestSchema,
+ GooglePayRequestSchema,
PayAndSaveCardRequestSchema,
PaymentRequestSchema,
PayoutRequestSchema,
@@ -24,7 +29,10 @@
RedirectUrlResponseSchema,
RedirectUrlWithCardIdResponseSchema,
SplitPayWithSavedCardResponseSchema,
+ TokenPaymentResponseSchema,
+ TokenPayResponseSchema,
TransactionStatusResponseSchema,
+ WidgetResponseSchema,
)
from integrify.schemas import APIResponse, _ResponseT
@@ -106,3 +114,62 @@ class SplitPayWithSavedCardPayloadHandler(BasePayloadHandler):
class SplitPayAndSaveCardPayloadHandler(BasePayloadHandler):
req_model = SplitPayAndSaveCardRequestSchema
resp_model = RedirectUrlWithCardIdResponseSchema
+
+
+##############################################################################
+# Apple Pay & Google Pay
+_ERROR_STATUSES = {
+ TransactionStatus.ERROR.value,
+ TransactionStatus.SERVER_ERROR.value,
+ TransactionStatus.FAILED.value,
+}
+
+
+class BaseTokenPayloadHandler(BasePayloadHandler):
+ """Apple/Google Pay sorğuları üçün baza handler: data-ya yalnız `public_key` əlavə olunur"""
+
+ def pre_handle_payload(self, *args, **kwds):
+ return {'public_key': env.EPOINT_PUBLIC_KEY}
+
+
+class CreateWidgetPayloadHandler(BaseTokenPayloadHandler):
+ req_model = CreateWidgetRequestSchema
+ resp_model = WidgetResponseSchema
+
+
+class CreateTokenPaymentPayloadHandler(BasePayloadHandler):
+ req_model = CreateTokenPaymentRequestSchema
+ resp_model = TokenPaymentResponseSchema
+
+ def handle_response(self, resp: httpx.Response) -> APIResponse[_ResponseT]:
+ # Uğurlu cavabda `status` field-i yoxdur, ödəniş obyekti birbaşa qayıdır
+ api_resp: APIResponse[TokenPaymentResponseSchema] = APIPayloadHandler.handle_response(
+ self, resp
+ )
+ api_resp.ok = (
+ api_resp.ok
+ and api_resp.body.id is not None
+ and api_resp.body.status not in _ERROR_STATUSES
+ )
+ return api_resp
+
+
+class ApplePaySessionPayloadHandler(BaseTokenPayloadHandler):
+ req_model = ApplePaySessionRequestSchema
+ resp_model = dict
+
+ def handle_response(self, resp: httpx.Response) -> APIResponse[_ResponseT]:
+ # Apple merchant session obyekti olduğu kimi qaytarılır (SDK-ya ötürmək üçün)
+ api_resp: APIResponse[dict] = APIPayloadHandler.handle_response(self, resp)
+ api_resp.ok = api_resp.ok and api_resp.body.get('status') not in _ERROR_STATUSES
+ return api_resp
+
+
+class ApplePayPayloadHandler(BaseTokenPayloadHandler):
+ req_model = ApplePayRequestSchema
+ resp_model = TokenPayResponseSchema
+
+
+class GooglePayPayloadHandler(BaseTokenPayloadHandler):
+ req_model = GooglePayRequestSchema
+ resp_model = TokenPayResponseSchema
diff --git a/packages/epoint/src/integrify/epoint/schemas/request.py b/packages/epoint/src/integrify/epoint/schemas/request.py
index 7bfff0c..3653e47 100644
--- a/packages/epoint/src/integrify/epoint/schemas/request.py
+++ b/packages/epoint/src/integrify/epoint/schemas/request.py
@@ -1,8 +1,9 @@
from decimal import Decimal
+from typing import Any
from integrify.epoint import env
from integrify.schemas import PayloadBaseModel
-from pydantic import Field
+from pydantic import AliasChoices, Field
class MinimalPaymentRequestSchema(PayloadBaseModel):
@@ -66,3 +67,40 @@ class SplitPayAndSaveCardRequestSchema(BasePaymentRequestSchema):
split_user: str = Field(validation_alias='split_user_id')
split_amount: Decimal
description: str | None = None
+
+
+##############################################################################
+# Apple Pay & Google Pay
+class CreateWidgetRequestSchema(PayloadBaseModel):
+ amount: Decimal
+ order_id: str
+ description: str
+
+
+class CreateTokenPaymentRequestSchema(PayloadBaseModel):
+ amount: Decimal
+ currency: str
+ order_id: str
+ description: str | None = None
+
+
+class ApplePaySessionRequestSchema(PayloadBaseModel):
+ origin: str
+
+
+class BaseTokenPayRequestSchema(PayloadBaseModel):
+ id: int | str = Field(validation_alias=AliasChoices('payment_id', 'id'))
+ token: Any
+ billing_contact: Any = Field(
+ default=None,
+ validation_alias=AliasChoices('billing_contact', 'billingContact'),
+ serialization_alias='billingContact',
+ )
+
+
+class ApplePayRequestSchema(BaseTokenPayRequestSchema):
+ pass
+
+
+class GooglePayRequestSchema(BaseTokenPayRequestSchema):
+ pass
diff --git a/packages/epoint/src/integrify/epoint/schemas/response.py b/packages/epoint/src/integrify/epoint/schemas/response.py
index e03bc6f..f459a36 100644
--- a/packages/epoint/src/integrify/epoint/schemas/response.py
+++ b/packages/epoint/src/integrify/epoint/schemas/response.py
@@ -1,4 +1,6 @@
+from datetime import datetime
from decimal import Decimal
+from typing import Any
from integrify.epoint.schemas.enums import Code, TransactionStatus, TransactionStatusExtended
from pydantic import BaseModel, field_validator
@@ -96,3 +98,87 @@ class TransactionStatusResponseSchema(BaseWithCodeSchema):
class SplitPayWithSavedCardResponseSchema(BaseResponseSchema):
split_amount: Decimal | None = None
"""İkinci istifadəçi üçün ödəniş məbləği."""
+
+
+#################################################################
+# Apple Pay & Google Pay
+class WidgetResponseSchema(BaseModel):
+ """`/api/1/token/widget` sorğusunun cavabı"""
+
+ status: str
+ """Əməliyyatın nəticəsi: `success` və ya `error`"""
+
+ message: str | None = None
+ """Xəta baş verdikdə, xəta mesajı"""
+
+ widget_url: str | None = None
+ """Apple Pay/Google Pay düymələrinin olduğu widget-in URL-i.
+ iframe və ya webview daxilində açılmalıdır."""
+
+
+class TokenPaymentResponseSchema(BaseModel):
+ """`/api/1/token/payment` sorğusunun cavabı: EPoint-də yaradılmış token ödənişi.
+ Bu obyekt frontend-də `initTokenPay`-ə `payment` parametri kimi ötürülür."""
+
+ # if error
+ status: str | None = None
+ """Xəta baş verdikdə, əməliyyatın statusu"""
+
+ message: str | None = None
+ """Xəta baş verdikdə, xəta mesajı"""
+
+ # if success
+ id: int | None = None
+ """Token ödənişinin EPoint-dəki IDsi. Apple/Google Pay sorğularında istifadə olunur."""
+
+ transaction: str | None = None
+ """EPoint xidmətinin əməliyyat IDsi"""
+
+ rrn: str | None = None
+ """Retrieval Reference Number - unikal əməliyyat identifikatoru"""
+
+ short_link: str | None = None
+ """Ödənişin qısa linki"""
+
+ bank_order_id: str | None = None
+ """Bank tərəfindəki sifariş IDsi"""
+
+ total: Decimal | None = None
+ """Ödənişin yekun məbləği"""
+
+ card_name: str | None = None
+ """Ödəniş səhifəsində göstərilən istifadəçi adı"""
+
+ card_mask: str | None = None
+ """123456******1234 formatında əks edilən kart maskası"""
+
+ description: str | None = None
+ """Ödənişin təsviri"""
+
+ merchant_order_id: str | None = None
+ """Tətbiqinizdə unikal əməliyyat ID (sorğuda göndərdiyiniz `order_id`)"""
+
+ other_attr: Any = None
+ """Əlavə göndərdiyiniz seçimlər"""
+
+ created_at: datetime | None = None
+ """Ödənişin yaradılma tarixi"""
+
+ updated_at: datetime | None = None
+ """Ödənişin son yenilənmə tarixi"""
+
+
+class TokenPayResponseSchema(BaseModel):
+ """Apple Pay/Google Pay ödənişinin tamamlanması sorğusunun cavabı"""
+
+ status: str
+ """Əməliyyatın nəticəsi. Uğurlu olduqda: `success`"""
+
+ message: str | None = None
+ """Ödənişin icra statusu haqqında mesaj"""
+
+ result: Any = None
+ """Ödəniş provayderindən (PSP) gələn cavab"""
+
+ redirect_url: str | None = None
+ """Yönləndirmə URL-i (məs., 3DS üçün). Hər zaman gəlmir."""
diff --git a/packages/epoint/tests/mocks.py b/packages/epoint/tests/mocks.py
index 792c33c..d7ddec4 100644
--- a/packages/epoint/tests/mocks.py
+++ b/packages/epoint/tests/mocks.py
@@ -200,3 +200,99 @@ def epoint_mock_split_pay_and_save_card_response():
'card_id': 'cexxxxxxxxxx',
},
)
+
+
+##############################################################################
+# Apple Pay & Google Pay
+@pytest.fixture(scope='package')
+def epoint_mock_create_widget_response():
+ return Response(
+ status_code=200,
+ json={
+ 'status': TransactionStatus.SUCCESS,
+ 'widget_url': 'https://epoint.az/api/1/token/widget/000001',
+ },
+ )
+
+
+@pytest.fixture(scope='package')
+def epoint_mock_create_widget_failed_response():
+ return Response(
+ status_code=200,
+ json={'status': TransactionStatus.ERROR, 'message': MESSAGE_SERVER_ERROR},
+ )
+
+
+@pytest.fixture(scope='package')
+def epoint_mock_create_token_payment_response():
+ return Response(
+ status_code=200,
+ json={
+ 'id': 9998887,
+ 'transaction': '12345',
+ 'rrn': '123',
+ 'short_link': 'a1b2',
+ 'bank_order_id': 'aaa111',
+ 'total': 2.36,
+ 'card_name': 'Name',
+ 'card_mask': '4000********1234',
+ 'description': 'test description',
+ 'merchant_order_id': '111222333',
+ 'other_attr': 'other attributes',
+ 'created_at': '2024-10-16 12:09:10',
+ 'updated_at': '2024-10-16 15:00:48',
+ },
+ )
+
+
+@pytest.fixture(scope='package')
+def epoint_mock_create_token_payment_failed_response():
+ return Response(
+ status_code=200,
+ json={'status': TransactionStatus.SERVER_ERROR, 'message': MESSAGE_SERVER_ERROR},
+ )
+
+
+@pytest.fixture(scope='package')
+def epoint_mock_apple_pay_session_response():
+ return Response(
+ status_code=200,
+ json={
+ 'epochTimestamp': 1729080550000,
+ 'expiresAt': 1729084150000,
+ 'merchantSessionIdentifier': 'SSH...',
+ 'nonce': 'abc123',
+ 'merchantIdentifier': 'merchant.az.epoint',
+ 'domainName': 'yoursite.az',
+ 'displayName': 'Your Site',
+ 'signature': 'base64signature',
+ },
+ )
+
+
+@pytest.fixture(scope='package')
+def epoint_mock_apple_pay_session_failed_response():
+ return Response(
+ status_code=200,
+ json={'status': TransactionStatus.SERVER_ERROR, 'message': MESSAGE_SERVER_ERROR},
+ )
+
+
+@pytest.fixture(scope='package')
+def epoint_mock_token_pay_response():
+ return Response(
+ status_code=200,
+ json={
+ 'status': TransactionStatus.SUCCESS,
+ 'message': 'Payment is finished successfully',
+ 'result': {'code': '000'},
+ },
+ )
+
+
+@pytest.fixture(scope='package')
+def epoint_mock_token_pay_failed_response():
+ return Response(
+ status_code=200,
+ json={'status': TransactionStatus.ERROR, 'message': MESSAGE_TRANSACTION_FAIL},
+ )
diff --git a/packages/epoint/tests/test_token_pay.py b/packages/epoint/tests/test_token_pay.py
new file mode 100644
index 0000000..a20c9b7
--- /dev/null
+++ b/packages/epoint/tests/test_token_pay.py
@@ -0,0 +1,191 @@
+import base64
+import json
+from datetime import datetime
+from decimal import Decimal
+
+import pytest
+from httpx import Response
+from integrify.epoint.client import EPointClientClass
+from pytest_mock import MockerFixture
+
+
+def _decode(dry_resp: dict) -> dict:
+ return json.loads(base64.b64decode(dry_resp['data']['data']))
+
+
+@pytest.fixture(scope='module')
+def epoint_dry_client():
+ yield EPointClientClass(dry=True)
+
+
+def test_create_widget_payload(epoint_dry_client: EPointClientClass, mocker: MockerFixture):
+ mocker.patch('integrify.epoint.env.EPOINT_PUBLIC_KEY', 'pub')
+ resp = epoint_dry_client.create_widget(amount=2.5, order_id='123', description='Test payment')
+
+ assert resp['url'].endswith('/api/1/token/widget')
+ assert resp['data']['signature']
+ assert _decode(resp) == {
+ 'public_key': 'pub',
+ 'amount': '2.5',
+ 'order_id': '123',
+ 'description': 'Test payment',
+ }
+
+
+def test_create_widget_request(
+ epoint_client: EPointClientClass,
+ epoint_mock_create_widget_response: Response,
+ mocker: MockerFixture,
+):
+ mocker.patch('httpx.Client.request', return_value=epoint_mock_create_widget_response)
+ resp = epoint_client.create_widget(amount=2.5, order_id='123', description='Test payment')
+
+ assert resp.ok
+ assert resp.body.widget_url == 'https://epoint.az/api/1/token/widget/000001'
+
+
+def test_create_widget_failed_request(
+ epoint_client: EPointClientClass,
+ epoint_mock_create_widget_failed_response: Response,
+ mocker: MockerFixture,
+):
+ mocker.patch('httpx.Client.request', return_value=epoint_mock_create_widget_failed_response)
+ resp = epoint_client.create_widget(amount=2.5, order_id='123', description='Test payment')
+
+ assert not resp.ok
+ assert resp.body.widget_url is None
+
+
+def test_create_token_payment_payload(epoint_dry_client: EPointClientClass, mocker: MockerFixture):
+ mocker.patch('integrify.epoint.env.EPOINT_PUBLIC_KEY', 'pub')
+ resp = epoint_dry_client.create_token_payment(
+ amount=2.5, currency='AZN', order_id='123', description='Test payment'
+ )
+
+ assert resp['url'].endswith('/api/1/token/payment')
+ assert resp['data']['signature']
+ data = _decode(resp)
+ assert data['public_key'] == 'pub'
+ assert data['language']
+ assert data['order_id'] == '123'
+ assert data['description'] == 'Test payment'
+
+
+def test_apple_pay_session_payload(epoint_dry_client: EPointClientClass, mocker: MockerFixture):
+ mocker.patch('integrify.epoint.env.EPOINT_PUBLIC_KEY', 'pub')
+ resp = epoint_dry_client.apple_pay_session(origin='https://yoursite.az')
+
+ assert resp['url'].endswith('/api/1/token/apple/session')
+ assert _decode(resp) == {'public_key': 'pub', 'origin': 'https://yoursite.az'}
+
+
+@pytest.mark.parametrize(
+ 'method, endpoint',
+ [('apple_pay', '/api/1/token/apple/pay'), ('google_pay', '/api/1/token/google/pay')],
+)
+def test_token_pay_payload(
+ epoint_dry_client: EPointClientClass,
+ mocker: MockerFixture,
+ method: str,
+ endpoint: str,
+):
+ mocker.patch('integrify.epoint.env.EPOINT_PUBLIC_KEY', 'pub')
+ token = {'paymentData': {'data': 'xxx'}}
+ contact = {'givenName': 'Name'}
+
+ resp = getattr(epoint_dry_client, method)(payment_id=1, token=token, billing_contact=contact)
+ assert resp['url'].endswith(endpoint)
+ assert _decode(resp) == {
+ 'public_key': 'pub',
+ 'id': 1,
+ 'token': token,
+ 'billingContact': contact,
+ }
+
+ # SDK-dan gələn body birbaşa ötürülə bilər (id/billingContact açarları ilə)
+ resp2 = getattr(epoint_dry_client, method)(
+ **{'id': 1, 'token': token, 'billingContact': contact}
+ )
+ assert _decode(resp2) == _decode(resp)
+
+
+def test_create_token_payment_request(
+ epoint_client: EPointClientClass,
+ epoint_mock_create_token_payment_response: Response,
+ mocker: MockerFixture,
+):
+ mocker.patch('httpx.Client.request', return_value=epoint_mock_create_token_payment_response)
+ resp = epoint_client.create_token_payment(amount=2.5, currency='AZN', order_id='111222333')
+
+ assert resp.ok
+ assert resp.body.id == 9998887
+ assert resp.body.total == Decimal('2.36')
+ assert resp.body.created_at == datetime(2024, 10, 16, 12, 9, 10)
+
+
+def test_create_token_payment_failed_request(
+ epoint_client: EPointClientClass,
+ epoint_mock_create_token_payment_failed_response: Response,
+ mocker: MockerFixture,
+):
+ mocker.patch(
+ 'httpx.Client.request', return_value=epoint_mock_create_token_payment_failed_response
+ )
+ resp = epoint_client.create_token_payment(amount=2.5, currency='AZN', order_id='111222333')
+
+ assert not resp.ok
+ assert resp.body.id is None
+ assert resp.body.message
+
+
+def test_apple_pay_session_request(
+ epoint_client: EPointClientClass,
+ epoint_mock_apple_pay_session_response: Response,
+ mocker: MockerFixture,
+):
+ mocker.patch('httpx.Client.request', return_value=epoint_mock_apple_pay_session_response)
+ resp = epoint_client.apple_pay_session(origin='https://yoursite.az')
+
+ assert resp.ok
+ assert resp.body['merchantSessionIdentifier']
+
+
+def test_apple_pay_session_failed_request(
+ epoint_client: EPointClientClass,
+ epoint_mock_apple_pay_session_failed_response: Response,
+ mocker: MockerFixture,
+):
+ mocker.patch('httpx.Client.request', return_value=epoint_mock_apple_pay_session_failed_response)
+ resp = epoint_client.apple_pay_session(origin='https://yoursite.az')
+
+ assert not resp.ok
+
+
+@pytest.mark.parametrize('method', ['apple_pay', 'google_pay'])
+def test_token_pay_request(
+ epoint_client: EPointClientClass,
+ epoint_mock_token_pay_response: Response,
+ mocker: MockerFixture,
+ method: str,
+):
+ mocker.patch('httpx.Client.request', return_value=epoint_mock_token_pay_response)
+ resp = getattr(epoint_client, method)(payment_id=1, token='token')
+
+ assert resp.ok
+ assert resp.body.status == 'success'
+ assert resp.body.result == {'code': '000'}
+ assert resp.body.redirect_url is None
+
+
+@pytest.mark.parametrize('method', ['apple_pay', 'google_pay'])
+def test_token_pay_failed_request(
+ epoint_client: EPointClientClass,
+ epoint_mock_token_pay_failed_response: Response,
+ mocker: MockerFixture,
+ method: str,
+):
+ mocker.patch('httpx.Client.request', return_value=epoint_mock_token_pay_failed_response)
+ resp = getattr(epoint_client, method)(payment_id=1, token='token')
+
+ assert not resp.ok
+ assert resp.body.status == 'error'
diff --git a/uv.lock b/uv.lock
index 246eb5f..e9127ce 100644
--- a/uv.lock
+++ b/uv.lock
@@ -516,7 +516,7 @@ requires-dist = [
[[package]]
name = "integrify-epoint"
-version = "1.2.0"
+version = "1.3.0"
source = { editable = "packages/epoint" }
dependencies = [
{ name = "integrify-core" },