# Fawaterak API

> API v2 reference — For the previous v2 documentation, see fawaterak-api.readme.io/reference/overview.

OpenAPI: https://staging.fawaterk.com/documentation/api/openapi.json
Human reference: https://staging.fawaterk.com/documentation

## Get started

To get started you need to create a business account from here appUrl/regsiter.
 

To complete your integrations setup, login to your created account > Integrations tab:

- OAuth client credentials (API) - to create client id and secret.

- Integrations - to setup your redirection URLs / Iframe domains / Webhook URLs (paid, failed, cancel, refund).

## Auth token

Obtain and renew Bearer access tokens for `/api/v3/*` OAuth-protected endpoints (transactions, refunds, e-invoicing).

| Step | Endpoint | `grant_type` | Purpose |
|------|----------|--------------|--------|
| 1 | `POST /oauth/token` | `client_credentials` | Exchange client ID + secret for an access token (and refresh token when enabled) |
| 2 | `POST /oauth/token` | `refresh_token` | Renew the access token using a stored refresh token + client ID + secret |

Create OAuth credentials in the vendor dashboard → Integrations → OAuth client credentials.

### POST /oauth/token — Obtain access token (client credentials)

Exchange the client ID and client secret (vendor dashboard → Integrations → OAuth client credentials) for a Bearer access token used on `/api/v3/*` OAuth-protected endpoints.

When refresh tokens are enabled for your OAuth client, the response also includes `refresh_token`. Store it securely and use Refresh access token to renew access without repeating the full client-credentials exchange.

Request example:

```json
{
    "grant_type": "client_credentials",
    "client_id": "9d4e2c1a-b3f5-4e8a-9c1d-2a3b4c5d6e7f",
    "client_secret": "YOUR_CLIENT_SECRET"
}
```

### POST /oauth/token#refresh — Refresh access token

Exchange a valid refresh token (from a previous `client_credentials` token response) for a new Bearer access token.

Send the same client ID and client secret that were used to obtain the refresh token. A new `refresh_token` is returned when token rotation is enabled — replace the stored value with the new one.

Request example:

```json
{
    "grant_type": "refresh_token",
    "refresh_token": "def50200a1b2c3d4e5f6...",
    "client_id": "9d4e2c1a-b3f5-4e8a-9c1d-2a3b4c5d6e7f",
    "client_secret": "YOUR_CLIENT_SECRET"
}
```

## Transactions overview

Transactions let you process a single one-time payment with a clear lifecycle status: success, fail, or pending.

There are two ways to create a transaction:

1. Hosted checkout (redirection link) — Do not send `payment_method_id`. The API creates a transaction link and returns a hosted checkout URL in `data.url`. Redirect the customer to it (or open it inside an iframe / WebView); the customer selects a payment method and pays on the Fawaterak-hosted page. This is a single payment attempt — the link is not meant to be reused for multiple tries.

2. Direct payment — Send `payment_method_id` (from `GET /api/v3/getTrPaymentmethods`). The API initiates payment immediately with that specific method and returns the provider response in `data.payment_data` (for example a Fawry reference code, a Meeza wallet request, or a card 3-D Secure redirect).

| Mode | Send `payment_method_id`? | Use from response |
|------|---------------------------|-------------------|
| Hosted checkout | No | `data.url` |
| Direct payment | Yes | `data.payment_data` |

Authenticate every call with `Authorization: Bearer {access_token}` from `POST /oauth/token`. Always confirm the final paid status from your webhook, not only from the customer redirect.

## API integration

This is server to server APIs integtatoins enables you to list active payment methods / create trasaction link / get transaction data. Requires OAuth client credentials.

### GET /api/v3/getTrPaymentmethods — List payment methods

Returns integration-enabled payment methods for the vendor linked to the OAuth client.

 Important hint: This API list the payment options has "Integration status" enabled in - Business settings > Payment method.

Call after `POST /oauth/token` with `Authorization: Bearer {access_token}`. Use each item's `payment_method_id` as `payment_method_id` when calling `createTransaction`.

| `redirect` | Behavior |
|------------|----------|
| `"true"` | Link mode — customer completes payment on hosted checkout (`data.url` from createTransaction) |
| `"false"` | Direct-dispatch — provider reference or RTP returned synchronously from createTransaction |

### POST /api/v3/createTransaction — Create transaction

Transaction types:
- Hosted checkout: do not send `payment_method_id`. This creates a transaction link and returns a hosted checkout URL in `data.url`.
- Direct payment: send `payment_method_id`. This initiates payment directly using that specific payment method and returns the method response in `data.payment_data`.

Creates a TR payment intent. No `transactions` row until the customer pays or direct-dispatch runs.

Use `payment_method_id` from `getTrPaymentmethods` only when you want to initiate payment with a specific payment method.

| Mode | When | Action |
|------|------|--------|
| Hosted checkout | No `payment_method_id` | Create a transaction link and redirect the customer to `data.url` hosted checkout. |
| Direct payment | `payment_method_id` is provided | Pay/initiate the transaction using that selected method and return `data.payment_data`. |

Hosted checkout (default): returns hosted URLs (`/transactions/{intent_key}`).

Direct-dispatch: when `payment_method_id` has `apiRedirect = "false"` and no `resource` / truthy `redirectOption`, returns provider response synchronously inside `data.payment_data`.

Request example:

```json
{
    "payment_method_id": 3,
    "cartTotal": 100,
    "currency": "EGP",
    "customer": {
        "first_name": "Ahmed",
        "last_name": "Ali",
        "email": "ahmed@example.com",
        "phone": "01000000000",
        "address": "Cairo",
        "customer_number": "CUST-1001",
        "customer_unique_id": "user_12345"
    },
    "cartItems": [
        {
            "name": "Order total",
            "price": 100,
            "quantity": 1
        }
    ],
    "pay_load": {
        "order_id": "ORD-1001",
        "customer_reference": "CUST-1001"
    },
    "redirectionUrls": {
        "successUrl": "https://yoursite.com/success",
        "failUrl": "https://yoursite.com/fail",
        "pendingUrl": "https://yoursite.com/pending",
        "backUrl": "https://yoursite.com/checkout",
        "webhookUrl": "https://yoursite.com/webhooks/fawaterak_json"
    },
    "sendEmail": true,
    "sendSMS": false,
    "due_date": "2026-06-06T12:00:00Z",
    "tr_number": "TR-1001",
    "redirectOption": false,
    "authAndCapture": 0,
    "taxData": {
        "title": "VAT",
        "value": 14
    },
    "discountData": {
        "type": "pcg",
        "value": 10
    },
    "list_style": "h",
    "lang": "en",
    "mobileWalletNumber": "01000000000"
}
```

### POST /api/v3/getTransactionData — Get transaction data

Returns the current TR transaction details for the vendor linked to the OAuth client using `intent_key`. Cache-only intents and persisted transaction rows are both supported.

Request example:

```json
{
    "intent_key": "550e8400-e29b-41d4-a716-446655440000"
}
```

### GET /api/v3/getTransactionsData — List transactions

Date-range paginated export of persisted TR rows. Similar to v2 `getInvoicesData`.

## Iframe integration

Embed Fawaterak checkout on your website with fawaterkPlugin.js (`/fawaterkPlugin/fawaterkPlugin.js`). Both flows open the same hosted checkout page (`/transactions/{intent_key}`) inside an iframe.

---

## Integration types

| You have | Approach | Auth |
|----------|----------|------|
| Frontend — HTML/JavaScript only, no server | Plugin creates the session from the browser via domain hash | Domain HMAC (`FAWATERAK-HASH-KEY` + `FAWATERAK-DOMAIN`) |
| Backend — a server that can call APIs securely (recommended) | Server creates the checkout session; the page only receives a checkout URL | OAuth client credentials |

Prerequisite (both types): Register your site domain under Integrations → iframe domains in the vendor dashboard.

---

## Frontend integration (browser-only)

Use when you cannot call Fawaterak APIs from a server. Do not embed your API key in the page — use a domain-bound hash key instead.

1. Register your domain — Vendor dashboard → Integrations → iframe domains (e.g. `https://shop.example.com`).
2. Compute the hash key — Prefer a small server script or build step (not hand-calculated in production):

```
ProviderKey = "FAWATERAK.{your_vendor_id}"
StringToSign = "Domain={your_domain}&ProviderKey={ProviderKey}" 
hashKey = HMAC-SHA256(StringToSign, your_vendor_api_key)
```

Send `hashKey` as header `FAWATERAK-HASH-KEY` and your domain as `FAWATERAK-DOMAIN`. The hash only works from registered domains.

3. Add the plugin — Pass `hashKey` and `requestBody` (same cart fields as `createTransaction`). The plugin initializes the session automatically, then loads checkout in the iframe:

```html



 fawaterkCheckoutV2({
 envType: "live",
 hashKey: "YOUR_DOMAIN_HASH_KEY",
 requestBody: {
 "cartTotal": "150.00",
 "currency": "EGP",
 "list_style": "h",
 "customer": {
 "first_name": "Ahmed",
 "last_name": "Ali",
 "email": "ahmed@example.com",
 "phone": "01000000000"
 },
 "cartItems": [
 { "name": "Product A", "price": "150.00", "quantity": "1" }
 ],
 "redirectionUrls": {
 "successUrl": "https://yoursite.com/success",
 "failUrl": "https://yoursite.com/fail",
 "webhookUrl": "https://yoursite.com/webhooks/fawaterak_json"
 }
 }
 });

```

`list_style` controls payment-method layout on the hosted checkout page: `"h"` (default) horizontal, `"v"` vertical.

Frontend limitations: A user could change `cartTotal` in the browser before payment. Always verify the paid amount in your webhook and compare it to your order total.

---

## Backend integration

Your server creates the payment session. The customer's browser never receives OAuth credentials or your API key.

1. Get OAuth credentials — Vendor dashboard → Integrations → OAuth client credentials. Create a client and note the client ID, client secret, and token URL (`POST /oauth/token`).
2. Create a payment session (server-side) — Obtain an access token (client credentials grant), then call `POST /api/v3/createTransaction` with `Authorization: Bearer {access_token}` and your cart JSON. Include `list_style` when you want a vertical payment-method list (`"v"`; default is `"h"`). Use `data.url` (or `data.short_url`) from the response as the checkout address.

Example request body:

```json
{
 "cartTotal": 150.00,
 "currency": "EGP",
 "list_style": "h",
 "customer": {
 "first_name": "Ahmed",
 "last_name": "Ali",
 "email": "ahmed@example.com",
 "phone": "01000000000"
 },
 "cartItems": [
 { "name": "Product A", "price": "150.00", "quantity": "1" }
 ],
 "redirectionUrls": {
 "successUrl": "https://yoursite.com/success",
 "failUrl": "https://yoursite.com/fail",
 "webhookUrl": "https://yoursite.com/webhooks/fawaterak_json"
 }
}
```

3. Add the plugin to your page — Render a fresh `intentUrl` per order from your server:

```html



 fawaterkCheckoutV2({
 envType: "live",
 intentUrl: "CHECKOUT_URL_FROM_YOUR_SERVER"
 });

```

Do not hard-code one checkout link for all orders unless the amount is fixed.

---

## After payment

Configure success, fail, and webhook URLs (dashboard and/or `red…

## Tokenization and recurring

Tokenization allows you to store card payment details in exchange for a token. The token replaces raw card data in later payment requests, so you can charge the saved card for tokenized or recurring payments without asking for the card details again.

---

## How it works

1. Call `POST /api/v2/createCardTokenScreen` to generate a Fawaterak-hosted card collection URL. Open the URL in an iframe or redirect the customer to it.
2. After the customer saves the card, Fawaterak creates the token and sends it to your tokenization webhook.
3. Use the returned `customerCardToken` / token later with `POST /api/v2/createTokenizationPayRequest`.

## Payment types

- Tokenization payment — send `tokenAction: "tokenization"`; response contains `redirectTo` for the 3DS/authentication flow.
- Recurring payment — do not send `tokenAction`; response contains `transaction_id` after successful processing.

The generated card screen link expires after about 10 minutes. If the screen expires or saving the card fails, the link cannot be reused.

---

## Created token webhook

When a token is created, your webhook receives data similar to:

```json
{
 "customerUniqueId": "222111333",
 "customerCard": "512345xxxxxx0008",
 "customerCardToken": "9731673377207107",
 "hashKey": "f59665d4077...ea2",
 "cardBrand": "MASTERCARD",
 "cardTokenUniqueId": "2345"
}
```

Validate `hashKey` with HMAC SHA256 using your vendor API key:

```php
$queryParam = "customerUniqueId=XYZ&customerCardToken=XYZ";
$hash = hash_hmac('sha256', $queryParam, 'FAWATERAK_VENDOR_KEY', false);
```

These are legacy v2 endpoints protected by `ValidateVendorToken`. Send `Authorization: Bearer {vendor_api_key}` and `Content-Type: application/json`.

### POST /api/v2/createCardTokenScreen — Create card data screen

Generates a Fawaterak-hosted URL containing the collect-card-data form. Use it in an iframe or redirect the customer to it. The link expires after about 10 minutes.

Request example:

```json
{
    "deduct_total_amount": true,
    "order": {
        "cartTotal": 100,
        "currency": "EGP",
        "cartItems": [
            {
                "name": "order total",
                "price": 100,
                "quantity": 1
            }
        ]
    },
    "customerData": {
        "customer_unique_id": "222111333",
        "customer_first_name": "Fname",
        "customer_last_name": "Lname",
        "customer_email": "customer@example.com",
        "customer_phone": "01111111111"
    },
    "redirectionUrls": {
        "success_url": "https://domain.com/success",
        "fail_url": "https://domain.com/fail",
        "webhook_url": "https://domain.com/token-webhook"
    },
    "allowedCardTypes": []
}
```

### POST /api/v2/createTokenizationPayRequest — Pay with tokenization

Processes a saved-card payment when `tokenAction: "tokenization"` is present. This flow returns a `redirectTo` URL for 3DS/authentication.

Request example:

```json
{
    "tokenAction": "tokenization",
    "order": {
        "amount": "10",
        "currency": "USD"
    },
    "payload": {
        "merchant_reference": "123",
        "trasaction_data": "transaction data"
    },
    "customerData": {
        "customer_token": "8lvfHBZC3n7lmTRO"
    }
}
```

### POST /api/v2/createTokenizationPayRequest#recurring — Pay with recurring

Processes a recurring saved-card payment when `tokenAction` is not sent. This flow returns a successful `transaction_id` when payment is captured.

Request example:

```json
{
    "order": {
        "amount": "1000",
        "currency": "EGP"
    },
    "customerData": {
        "customer_token": "UFZiaC98572rKZGZ"
    },
    "payload": {
        "merchant_reference": "123",
        "trasaction_data": "transaction data"
    }
}
```

### POST /api/v2/deleteCustomerToken — Delete customer token

Deletes a saved customer card token.

Request example:

```json
{
    "customerUniqueId": "222111333",
    "cardTokenUniqueId": "2345"
}
```

## Webhooks

Fawaterak sends server-to-server POST notifications to your endpoints. These are not Fawaterak API routes — implement the handlers on your server and register the URLs in the vendor dashboard (Integrations) or per transaction via `redirectionUrls`.

| Webhook | When | Configure URL |
|---------|------|----------------|
| Paid / pending | Payment succeeds or is pending (Fawry, Aman, …) | `webhookUrl` (per transaction) or dashboard Webhook |
| Failed | Card/gateway payment fails | Dashboard Failed webhook |
| Cancel | Reference expires or is canceled (Aman, Masary, Meeza, …) | Dashboard Cancellation webhook |
| Refund | Refund request is approved | Dashboard Refund webhook |

Use `_json` in the URL path for paid and failed webhooks to receive `application/json`; otherwise the body is `application/x-www-form-urlencoded`. Cancel and refund webhooks are always JSON.

See the POST operations below for request and response examples. Verify `transactionHashKey` on paid webhooks; verify `hashKey` on failed and cancel webhooks.

### POST /webhooks/fawaterak/paid — Paid / pending payment webhook

Fawaterak POSTs to your webhook URL when a payment completes or is pending (async methods such as Fawry, Aman, Masary).

Configure: `redirectionUrls.webhookUrl` on `createTransaction` / iframe `requestBody`, or the default Webhook URL in Integrations.

API payload: `transaction_key` = transaction `intent_key`; `transaction_id` = `transactions.id`; `status` = `paid` or `pending`.

Verify `transactionHashKey`:
```
StringToSign = "TransactionId=" + transaction_id + "&TransactionKey=" + transaction_key + "&PaymentMethod=" + payment_method
expectedHash = HMAC-SHA256(StringToSign, your_vendor_api_key)
```

Legacy v2 TR payloads may also include `hashKey` signed with `InvoiceId` / `InvoiceKey` instead of `TransactionId` / `TransactionKey`.

Return HTTP 200 promptly. Fulfill orders only when `status` is `paid`.

Request example:

```json
{
    "transaction_key": "550e8400-e29b-41d4-a716-446655440000",
    "transaction_id": 12345,
    "payment_method": "Visa-Mastercard",
    "status": "paid",
    "pay_load": "{\"order_id\":\"ORD-1001\"}",
    "paidAmount": "150.00",
    "paidCurrency": "EGP",
    "paidAt": "2026-06-01 14:30:00",
    "customerData": {
        "customer_unique_id": "cust-42",
        "customer_first_name": "Ahmed",
        "customer_last_name": "Ali",
        "customer_email": "ahmed@example.com",
        "customer_phone": "01000000000"
    },
    "transactionHashKey": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"
}
```

### POST /webhooks/fawaterak/failed — Failed payment webhook

Fawaterak POSTs to your Failed webhook URL when a payment attempt fails (e.g. card declined, gateway error).

Configure: Integrations → Failed webhook (`failedWebhook`).

API payload: `transaction_key` = transaction `intent_key`; `transaction_id` = `transactions.id`.

Verify `hashKey`:
```
StringToSign = "TransactionId=" + transaction_id + "&TransactionKey=" + transaction_key + "&PaymentMethod=" + payment_method
expectedHash = HMAC-SHA256(StringToSign, your_vendor_api_key)
```
For IN (invoice) payloads, replace `TransactionId`/`TransactionKey` with `InvoiceId`/`InvoiceKey`.

Request example:

```json
{
    "transaction_key": "550e8400-e29b-41d4-a716-446655440000",
    "transaction_id": 12345,
    "payment_method": "Visa-Mastercard",
    "pay_load": "{\"order_id\":\"ORD-1001\"}",
    "amount": "150.00",
    "paidCurrency": "EGP",
    "errorMessage": "Payment declined by issuer",
    "response": "{\"gatewayCode\":\"DECLINED\"}",
    "hashKey": "a3b4c5d6e7f8901234567890abcdef1234567890abcdef1234567890abcdef12"
}
```

### POST /webhooks/fawaterak/cancel — Cancel / expired reference webhook

Fawaterak POSTs to your Cancellation webhook when a payment reference expires or is canceled (Aman, Masary, Meeza, and similar async references).

Configure: Integrations → Cancellation webhook (`cancellationWebhook`).

Content-Type: always `application/json`.

Verify `hashKey`:
```
StringToSign = "referenceId=" + referenceId + "&PaymentMethod=" + paymentMethod
expectedHash = HMAC-SHA256(StringToSign, your_vendor_api_key)
```

Request example:

```json
{
    "referenceId": 998877,
    "status": "EXPIRED",
    "paymentMethod": "Aman",
    "pay_load": "{\"order_id\":\"ORD-1001\"}",
    "transactionId": 12345,
    "transactionKey": "550e8400-e29b-41d4-a716-446655440000",
    "hashKey": "d4e5f6789012345678901234567890abcdef1234567890abcdef1234567890abcde"
}
```

### POST /webhooks/fawaterak/refund — Refund webhook

Fawaterak POSTs to your Refund webhook when a refund request is approved.

Configure: Integrations → Refund webhook (`refundWebhook`).

Content-Type: always `application/json`.

Verify `hashKey`:
```
StringToSign = "transactionId=" + transactionId + "&amount=" + amount + "&currency=" + currency
expectedHash = HMAC-SHA256(StringToSign, your_vendor_api_key)
```

Request example:

```json
{
    "transactionId": 12345,
    "amount": "50.00",
    "currency": "EGP",
    "status": 1,
    "reason": "Customer requested partial refund",
    "approvedAt": "2026-06-02 10:15:00",
    "hashKey": "f1e2d3c4b5a6987654321098765432109876543210fedcba9876543210fedcba98"
}
```

## E-Commerce Plugins

We provide multiple ready-made plugins to accept Fawaterak payments on popular e-commerce platforms.

---

## Plugins

1. WooCommerce — [Download the plugin](https://wordpress.org/plugins/fawaterk-for-woocommerce/)
2. ExpandCart — Through our executive partnership with ExpandCart you can create your own store and accept online payments through Expand Pay, powered by Fawaterak.
3. OpenCart — Download from the official OpenCart marketplace: [click here](https://www.opencart.com/index.php?route=marketplace/extension/info&extension_id=43750&filter_search=fawaterk&filter_category_id=3)
4. Shopify (redirect — all payment methods) — Log in to Shopify and Fawaterak in separate tabs, then install: [click here](https://apps.shopify.com/fawaterak)
5. Shopify (embedded card payment only) — Log in to Shopify and Fawaterak in separate tabs, then install: [click here](https://apps.shopify.com/fawaterak-credit-card)
6. WHMCS — [Download the plugin](https://drive.google.com/drive/folders/111-ZMLJ3LxFMkusaKkXga475E2fUYtOF?usp=sharing)
7. CS-Cart — [Download the plugin](https://drive.google.com/drive/folders/1BCGhzsrMbrMpWB4XY7t0gGniuoy7bj62?usp=sharing)
8. Magento — [Download the plugin](https://drive.google.com/drive/folders/1VhjQfDZ3WbjMZjX8NO4HYQAfEyLLlhOv?usp=sharing)

---

## Important note (Cloudflare)

If you use Cloudflare with the WooCommerce plugin, add a path-based WAF skip rule so Fawaterak webhooks are not blocked:

Security → WAF → Custom Rules

| Setting | Value |
|---------|-------|
| IF URI Path equals | `/wc-api/fawaterak_webhook_json` |
| THEN Skip | Browser Integrity Check, Bot Fight Mode, JS Challenge |

## Overview

E-invoicing lets you create an invoice and share it with your customers via email, SMS, or manually (copy the payment link). The customer can pay the invoice at any time within the due date (if a due date is set), and can try multiple payment methods for the same invoice link until the payment succeeds.

Invoices are persisted in the `invoices` table with `create_source = API.v3.EI.IN` and return a hosted payment link (`/in/{invoice_key}`).

Requires `Authorization: Bearer {access_token}` from `POST /oauth/token`.

## E-invoicing

Create and manage e-invoices via OAuth client credentials. Invoices are persisted in the `invoices` table with `create_source = API.v3.EI.IN`. Returns a hosted payment link (`/in/{invoice_key}`) for the customer to pay.

Requires `Authorization: Bearer {access_token}` from `POST /oauth/token`.

### POST /api/v3/createEinvoice — Create e-invoice

Creates a new e-invoice in the `invoices` table with `create_source = API.v3.EI.IN` and returns a hosted payment link.

### POST /api/v3/invoice/index — List e-invoices

Paginated list of e-invoices created via this API (`create_source = API.v3.EI.IN`) for the authenticated vendor.

### POST /api/v3/invoice/get — Get e-invoice

Returns full details for a single e-invoice owned by the authenticated vendor.

### POST /api/v3/invoice/update — Update e-invoice

Updates an existing e-invoice. When `hasHistory` is not set, `currency` and `products` are required and line items are replaced.

### POST /api/v3/invoice/delete — Delete e-invoice

Soft-deletes an unpaid e-invoice after verifying no active payment references block deletion.

## Mobile integrations

Easy integration with your mobile app (React Native, Flutter, Kotlin, Java, Swift) using API v3 and TR (cache-based transactions).

---

## Overview

The mobile flow has two steps:

| Step | Endpoint | Purpose |
|------|----------|--------|
| 1 | `GET /api/v3/getTrPaymentmethods` | List enabled payment methods for your account |
| 2 | `POST /api/v3/createTransaction` | Create a TR intent and pay (direct-dispatch or hosted link) |

---

## Authentication

Use OAuth client credentials (not the legacy vendor API key):

1. Create credentials in the vendor dashboard → Integrations → OAuth client credentials.
2. Call `POST /oauth/token` to obtain a Bearer access token.
3. Send `Authorization: Bearer {access_token}` on all `/api/v3/*` mobile calls.

---

## How payment methods behave

| `redirect` value | Mobile handling |
|------------------|-----------------|
| `"true"` | Link mode — response includes `data.url`; open in a WebView / in-app browser |
| `"false"` | Direct-dispatch — provider reference or RTP returned synchronously (Fawry, Meeza, …) |

Important: Meeza (mobile wallets) is validated with real payments in production. Pass `mobileWalletNumber` when required.

Mark orders as paid from webhooks (`redirectionUrls.webhookUrl`) — see Webhooks.

## Mobile — List payment methods

Step 1 — Retrieve payment methods assigned to your vendor account.

Endpoint: `GET /api/v3/getTrPaymentmethods`

Present the `data` array in your app UI. Each item includes `payment_method_id`, localized names, `redirect`, and `logo`.

Mobile (step 1): Call this after `POST /oauth/token`. Use `payment_method_id` when calling `createTransaction`. If `redirect` is `"true"`, open the returned checkout `url` in a WebView; if `"false"`, expect a synchronous provider response from direct-dispatch.

React Native:
```javascript
const apiUrl = 'https://app.fawaterk.com/api/v3/getTrPaymentmethods';
const accessToken = 'YOUR_OAUTH_ACCESS_TOKEN';

fetch(apiUrl, {
 method: 'GET',
 headers: {
 'Content-Type': 'application/json',
 Authorization: `Bearer ${accessToken}`,
 },
})
 .then((r) => r.json())
 .then(console.log)
 .catch(console.error);
```

Kotlin:
```kotlin
val apiUrl = "https://app.fawaterk.com/api/v3/getTrPaymentmethods"
val accessToken = "YOUR_OAUTH_ACCESS_TOKEN"

val client = OkHttpClient()
val request = Request.Builder()
 .url(apiUrl)
 .addHeader("Content-Type", "application/json")
 .addHeader("Authorization", "Bearer $accessToken")
 .build()

client.newCall(request).execute().use { response ->
 if (response.isSuccessful) {
 println(response.body?.string())
 } else {
 println("Request failed: ${response.code}")
 }
}
```

Java:
```java
String apiUrl = "https://app.fawaterk.com/api/v3/getTrPaymentmethods";
String accessToken = "YOUR_OAUTH_ACCESS_TOKEN";

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
 .url(apiUrl)
 .addHeader("Content-Type", "application/json")
 .addHeader("Authorization", "Bearer " + accessToken)
 .build();

try (Response response = client.newCall(request).execute()) {
 if (response.isSuccessful() && response.body() != null) {
 System.out.println(response.body().string());
 } else {
 System.out.println("Request failed: " + response.code());
 }
}
```

Swift:
```swift
let apiUrl = "https://app.fawaterk.com/api/v3/getTrPaymentmethods"
let accessToken = "YOUR_OAUTH_ACCESS_TOKEN"

if let url = URL(string: apiUrl) {
 var request = URLRequest(url: url)
 request.setValue("application/json", forHTTPHeaderField: "Content-Type")
 request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")

 URLSession.shared.dataTask(with: request) { data, _, error in
 if let error = error {
 print("Error: \(error)")
 return
 }
 if let data = data, let body = String(data: data, encoding: .utf8) {
 print(body)
 }
 }.resume()
}
```

Flutter:
```dart
import 'dart:convert';
import 'package:http/http.dart' as http;

Future fetchPaymentMethods() async {
 const apiUrl = 'https://app.fawaterk.com/api/v3/getTrPaymentmethods';
 const accessToken = 'YOUR_OAUTH_ACCESS_TOKEN';

 final response = await http.get(
 Uri.parse(apiUrl),
 headers: {
 'Content-Type': 'application/json',
 'Authorization': 'Bearer $accessToken',
 },
 );
 print(json.encode(json.decode(response.body)));
}
```

### GET /api/v3/getTrPaymentmethods — List payment methods

Returns integration-enabled payment methods for the vendor linked to the OAuth client.

 Important hint: This API list the payment options has "Integration status" enabled in - Business settings > Payment method.

Call after `POST /oauth/token` with `Authorization: Bearer {access_token}`. Use each item's `payment_method_id` as `payment_method_id` when calling `createTransaction`.

| `redirect` | Behavior |
|------------|----------|
| `"true"` | Link mode — customer completes payment on hosted checkout (`data.url` from createTransaction) |
| `"false"` | Direct-dispatch — provider reference or RTP returned synchronously from createTransaction |

## Mobile — Process transaction

Step 2 — Create a TR transaction and initiate payment on the selected method.

Endpoint: `POST /api/v3/createTransaction`

Include `payment_method_id` from step 1 plus cart/customer fields. Response shape depends on the method:

- Card / redirect methods — hosted checkout URL in `data.url` (open in WebView)
- Fawry — direct-dispatch reference code
- Meeza — wallet RTP / reference in provider response

Use `intent_key` from the response to correlate with webhooks and `POST /api/v3/getTransactionData`.

Mobile (step 2): Include `payment_method_id` from step 1.

| Mode | When | Mobile action |
|------|------|---------------|
| Link | `redirect` = `"true"` (e.g. Visa/Mastercard) | Open `data.url` in WebView |
| Direct-dispatch | `redirect` = `"false"` (e.g. Fawry, Meeza) | Show reference / handle RTP from provider body |

React Native:
```javascript
const API_URL = 'https://app.fawaterk.com/api/v3/createTransaction';
const accessToken = 'YOUR_OAUTH_ACCESS_TOKEN';
const PAYMENT_ID = 4; // from getTrPaymentmethods

fetch(API_URL, {
 method: 'POST',
 headers: {
 Authorization: `Bearer ${accessToken}`,
 'Content-Type': 'application/json',
 },
 body: JSON.stringify({
 payment_method_id: PAYMENT_ID,
 cartTotal: '100',
 currency: 'EGP',
 customer: {
 first_name: 'Ahmed',
 last_name: 'Ali',
 email: 'ahmed@example.com',
 phone: '01000000000',
 address: 'Cairo',
 },
 redirectionUrls: {
 successUrl: 'https://yoursite.com/success',
 failUrl: 'https://yoursite.com/fail',
 pendingUrl: 'https://yoursite.com/pending',
 webhookUrl: 'https://yoursite.com/webhooks/fawaterak_json',
 },
 cartItems: [{ name: 'Order total', price: '100', quantity: '1' }],
 }),
})
 .then((r) => r.json())
 .then(console.log)
 .catch(console.error);
```

Kotlin:
```kotlin
val apiUrl = "https://app.fawaterk.com/api/v3/createTransaction"
val accessToken = "YOUR_OAUTH_ACCESS_TOKEN"
val payment_method_id = 4

val requestData = """
{"payment_method_id":$payment_method_id,"cartTotal":"100","currency":"EGP",
"customer":{"first_name":"Ahmed","last_name":"Ali","email":"ahmed@example.com","phone":"01000000000","address":"Cairo"},
"redirectionUrls":{"successUrl":"https://yoursite.com/success","failUrl":"https://yoursite.com/fail","pendingUrl":"https://yoursite.com/pending","webhookUrl":"https://yoursite.com/webhooks/fawaterak_json"},
"cartItems":[{"name":"Order total","price":"100","quantity":"1"}]}
""".trimIndent()

val client = OkHttpClient()
val body = requestData.toRequestBody("application/json".toMediaType())
val request = Request.Builder()
 .url(apiUrl)
 .addHeader("Authorization", "Bearer $accessToken")
 .addHeader("Content-Type", "application/json")
 .post(body)
 .build()

client.newCall(request).execute().use { response ->
 println(if (response.isSuccessful) response.body?.string() else "Failed: ${response.code}")
}
```

Java:
```java
String apiUrl = "https://app.fawaterk.com/api/v3/createTransaction";
String accessToken = "YOUR_OAUTH_ACCESS_TOKEN";
int payment_method_id = 4;

String requestData = "{\"payment_method_id\":" + payment_method_id
 + ",\"cartTotal\":\"100\",\"currency\":\"EGP\","
 + "\"customer\":{\"first_name\":\"Ahmed\",\"last_name\":\"Ali\","
 + "\"email\":\"ahmed@example.com\",\"phone\":\"01000000000\",\"address\":\"Cairo\"},"
 + "\"redirectionUrls\":{\"successUrl\":\"https://yoursite.com/success\","
 + "\"failUrl\":\"https://yoursite.com/fail\",\"pendingUrl\":\"https://yoursite.com/pending\","
 + "\"webhookUrl\":\"https://yoursite.com/webhooks/fawaterak_json\"},"
 + "\"cartItems\":[{\"name\":\"Order total\",\"price\":\"100\",\"quantity\":\"1\"}]}";

OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(requestData, MediaType.get("application/json"));
Request request = new Request.Builder()
 .url(apiUrl)
 .addHeader("Authorization", "Bearer " + accessToken)
 .addHeader("Content-Type", "application/json")
 .post(body)
 .build();

try (Response response = client.newCall(request).execute()) {
 if (response.body() != null) {
 System.out…

### POST /api/v3/createTransaction — Create transaction

Transaction types:
- Hosted checkout: do not send `payment_method_id`. This creates a transaction link and returns a hosted checkout URL in `data.url`.
- Direct payment: send `payment_method_id`. This initiates payment directly using that specific payment method and returns the method response in `data.payment_data`.

Creates a TR payment intent. No `transactions` row until the customer pays or direct-dispatch runs.

Use `payment_method_id` from `getTrPaymentmethods` only when you want to initiate payment with a specific payment method.

| Mode | When | Action |
|------|------|--------|
| Hosted checkout | No `payment_method_id` | Create a transaction link and redirect the customer to `data.url` hosted checkout. |
| Direct payment | `payment_method_id` is provided | Pay/initiate the transaction using that selected method and return `data.payment_data`. |

Hosted checkout (default): returns hosted URLs (`/transactions/{intent_key}`).

Direct-dispatch: when `payment_method_id` has `apiRedirect = "false"` and no `resource` / truthy `redirectOption`, returns provider response synchronously inside `data.payment_data`.

Request example:

```json
{
    "payment_method_id": 3,
    "cartTotal": 100,
    "currency": "EGP",
    "customer": {
        "first_name": "Ahmed",
        "last_name": "Ali",
        "email": "ahmed@example.com",
        "phone": "01000000000",
        "address": "Cairo",
        "customer_number": "CUST-1001",
        "customer_unique_id": "user_12345"
    },
    "cartItems": [
        {
            "name": "Order total",
            "price": 100,
            "quantity": 1
        }
    ],
    "pay_load": {
        "order_id": "ORD-1001",
        "customer_reference": "CUST-1001"
    },
    "redirectionUrls": {
        "successUrl": "https://yoursite.com/success",
        "failUrl": "https://yoursite.com/fail",
        "pendingUrl": "https://yoursite.com/pending",
        "backUrl": "https://yoursite.com/checkout",
        "webhookUrl": "https://yoursite.com/webhooks/fawaterak_json"
    },
    "sendEmail": true,
    "sendSMS": false,
    "due_date": "2026-06-06T12:00:00Z",
    "tr_number": "TR-1001",
    "redirectOption": false,
    "authAndCapture": 0,
    "taxData": {
        "title": "VAT",
        "value": 14
    },
    "discountData": {
        "type": "pcg",
        "value": 10
    },
    "list_style": "h",
    "lang": "en",
    "mobileWalletNumber": "01000000000"
}
```

## Refund APIs

Manage refund requests for paid transactions via OAuth client credentials.

Legacy v2: Existing integrations may continue using `/api/v2/refund/*` with the vendor API key (`ValidateVendorToken`). Those routes are unchanged.

Flow (v3):
1. `POST /api/v3/refund/refundTypes` — get `refund_type` keys (`0` = invoice, `1` = payment link transaction, `2` = collection link transaction).
2. `POST /api/v3/refund/refundReasons` — list allowed refund reasons.
3. `POST /api/v3/refund/create` — submit a refund using `refund_type` + `refund_id` (invoice id or payment-request transaction id).
4. `POST /api/v3/refund/index` / `GET /api/v3/refund/details/{id}` — list and inspect requests.
5. `POST /api/v3/refund/delete` — cancel a pending (non-approved) request.

Requires `Authorization: Bearer {access_token}` from `POST /oauth/token`.

### POST /api/v3/refund/index — List refund requests

Returns a paginated list of refund requests for the vendor linked to the OAuth client (10 per page).

### GET /api/v3/refund/details/{id} — Get refund request details

### POST /api/v3/refund/refundTypes — List refund types

Returns refund type keys used as `refund_type` when creating a refund.

| Key | Meaning |
|-----|--------|
| `0` | Invoice |
| `1` | Payment link transaction |
| `2` | Collection link transaction |
| `3` | Integration transaction |

Pass optional `lang` (`en` / `ar`) to localize labels.

### POST /api/v3/refund/refundReasons — List refund reasons

Returns allowed refund reason strings. Pass `lang: "ar"` for Arabic labels.

### POST /api/v3/refund/create — Create refund request

Submit a refund for a paid transaction.

`refund_type` — from `POST /api/v3/refund/refundTypes` (`0` = invoice, `1` = payment link transaction, `2` = collection link transaction, `3` = integration transaction).

`refund_id` — the id of the invoice or payment-request transaction to refund (must belong to your vendor account).

`refundable_amount` — partial or full amount; must not exceed the remaining refundable balance.

`reason` — one of the strings from `POST /api/v3/refund/refundReasons`.

Request example:

```json
{
    "refund_type": "0",
    "refund_id": 12345,
    "reason": "Customer changed their mind",
    "refundable_amount": 50,
    "comment": "Partial refund for order #1001"
}
```

### POST /api/v3/refund/delete — Delete (cancel) refund request

Deletes a pending refund request. Approved refunds cannot be deleted.

Request example:

```json
{
    "refund_id": 42
}
```

## Payment operations

Capture or void card payments (auth-and-capture) via OAuth client credentials.

| Endpoint | Purpose |
|----------|--------|
| `POST /api/v3/payment/capture` | Capture (settle) an authorized hold — full or partial |
| `POST /api/v3/payment/void` | Void an authorized hold (not a captured payment) |

Capture identity: `type=transaction` uses `intent_key` from createTransaction / webhook / redirect; `type=invoice` uses `transaction_id` (invoice id).

Void identity: `type=transaction` uses `intent_key` from createTransaction / webhook / redirect; `type=invoice` uses `transaction_id` (invoice id).

Responses use `status`, `message`, and `data` (identity fields plus merchant `pay_load` from create).

Legacy: `/api/v2/bank/createCapture` and `/api/v2/bank/createVoid` remain for vendor-token clients and are unchanged.

Requires `Authorization: Bearer {access_token}` from `POST /oauth/token`.

### POST /api/v3/payment/capture — Capture authorized payment

Capture (settle) an authorized card hold.

Use after creating a transaction/invoice with auth-and-capture enabled. The payment must be in a waiting-capture (or partial-capture) state.

Identity:
- `type=transaction` — send `intent_key` from `createTransaction` / webhook / redirect (do not send `transaction_id`)
- `type=invoice` — send `transaction_id` (invoice id)

`amount` — optional; omit to capture the remaining authorized amount (partial capture supported when available).

Request example:

```json
{
    "type": "transaction",
    "intent_key": "550e8400-e29b-41d4-a716-446655440000",
    "amount": 150.5
}
```

### POST /api/v3/payment/void — Void authorized payment

Void an authorized (waiting-capture) hold.

Fully or partially captured payments cannot be voided — use the refund API instead.

Identity:
- `type=transaction` — send `intent_key` from `createTransaction` / webhook / redirect (do not send `transaction_id`)
- `type=invoice` — send `transaction_id` (invoice id)

Request example:

```json
{
    "type": "transaction",
    "intent_key": "550e8400-e29b-41d4-a716-446655440000"
}
```

## Test cards

Use these sandbox / test card numbers when testing Mastercard, Visa, and Meeza flows on staging or in test mode.

---

## Cards that always return a successful transaction

| Brand | Card number | Card holder name | Expiry date | CSV |
|-------|-------------|------------------|-------------|-----|
| Mastercard | `5123450000000008` | Fawaterak test | 12/26 | 100 |
| Visa | `4005 5500 0000 0001` | Fawaterak test | 12/26 | 100 |
| Meeza | `5078 0362 4660 0381` | Fawaterak test | 12/26 | 100 |

---

## Cards that always return a failed transaction

| Brand | Card number | Card holder name | Expiry date | CSV |
|-------|-------------|------------------|-------------|-----|
| Mastercard | `5543474002249996` | Fawaterak test | 05/26 | 123 |
| Visa | `4222 0000 0672 4235` | Fawaterak test | 12/26 | 123 |
| Meeza | `5078 0362 4278 3546` | Fawaterak test | 12/26 | 123 |

---

Note: Use your staging environment (`https://staging.fawaterk.com`) or test credentials when exercising these cards. Do not use test card numbers in production.
