> For the complete documentation index, see [llms.txt](https://docs.jgopay.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.jgopay.com/english/create-payment.md).

# Create Payment

## Endpoint

```http
POST /payment/request
Authorization: Bearer <access_token>
Content-Type: application/json
```

## Request Body

| Field            | Type   | Required | Description                                                                                                                                                                                                                                             |
| ---------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `amount`         | number | Yes      | Payment amount (see [Amount Rules](#amount-rules))                                                                                                                                                                                                      |
| `currency`       | string | No       | ISO 4217 currency code (`MYR`). Defaults to your configured currency                                                                                                                                                                                    |
| `reference_id`   | string | Yes      | Your unique order/invoice ID (max 100 chars, **alphanumeric only**)                                                                                                                                                                                     |
| `customer_name`  | string | Yes      | Customer's name                                                                                                                                                                                                                                         |
| `customer_phone` | string | Yes      | Customer's phone number (include country code, no `+`)                                                                                                                                                                                                  |
| `callback_url`   | string | No       | Callback URL for payment notifications. Falls back to merchant default                                                                                                                                                                                  |
| `redirect_url`   | string | No       | URL to redirect customer after payment                                                                                                                                                                                                                  |
| `payment_method` | string | Yes      | Payment method code (`QR_PAYMENT`, `BANK_TRANSFER`, `MOBILE_WALLET`)                                                                                                                                                                                    |
| `metadata`       | object | No       | Custom key-value data stored with the transaction. **Not** returned in callbacks — use `reference_id` to correlate. **Required for `BANK_TRANSFER`:** include `provider_channel_id` (see [Payment Methods](/english/payment-methods.md#fpx-bank-codes)) |

> **Security:** `callback_url` and `redirect_url` must use HTTPS (`https://`) in production. HTTP URLs are rejected with HTTP 422. This prevents interception of callback payloads containing payment status and signatures.

> **Warning:** `redirect_url` is not validated against a pre-registered domain. If your API key is compromised, an attacker could create payments that redirect your customers to phishing sites after payment. To mitigate this:
>
> * Restrict API key access to backend servers only — never expose in client-side code
> * Monitor payment creation logs for unexpected `redirect_url` values
> * Rotate your API key immediately if compromise is suspected (see [Authentication](/english/authentication.md#emergency-revocation))

## Field Validation

| Field            | Rule                                  | Notes                                                                                |
| ---------------- | ------------------------------------- | ------------------------------------------------------------------------------------ |
| `reference_id`   | **Alphanumeric only** (a-z, A-Z, 0-9) | No spaces, hyphens, or special characters. Will return `VALIDATION_ERROR` if invalid |
| `customer_phone` | String, 1-50 characters               | Include country code without `+` (e.g., `60123456789`)                               |
| `amount`         | Positive number                       | Up to 2 decimal places                                                               |

> **`BANK_TRANSFER` (FPX):** When using `payment_method: "BANK_TRANSFER"`, you must include `metadata.provider_channel_id` with the customer's bank code. See [Payment Methods](/english/payment-methods.md#fpx-bank-codes) for the full list.

## Amount Rules

| Currency | Format           | Min Amount | Max Amount |
| -------- | ---------------- | ---------- | ---------- |
| **MYR**  | Up to 2 decimals | 5 MYR      | 50,000 MYR |

## Response

You receive gateway-specific data:

```json
{
  "status": "success",
  "data": {
    "payment_id": "PAY_MYR12346",
    "payment_url": "https://payment.yourbrand.com/p/MYR12346",
    "status": "PROCESSING",
    "amount": 100.00,
    "currency": "MYR",
    "reference_id": "ORDER20260325002",
    "expires_in": 1800,
    "expires_at": "2026-03-25T12:30:00Z",
    "gateway": {
      "behavior": "REDIRECT_EXTERNAL",
      "redirect_url": "https://gateway.example.com/pay/xyz789",
      "qr_data_string": null
    }
  }
}
```

### Response Fields

| Field                  | Type   | Description                                                                   |
| ---------------------- | ------ | ----------------------------------------------------------------------------- |
| `payment_id`           | string | Unique payment identifier                                                     |
| `payment_url`          | string | Payment page URL — send the customer here for `QR_PAYMENT`                    |
| `status`               | string | Initial status (`PROCESSING`)                                                 |
| `amount`               | number | Confirmed payment amount                                                      |
| `currency`             | string | Currency code                                                                 |
| `reference_id`         | string | Your reference ID                                                             |
| `expires_in`           | number | Seconds until expiry                                                          |
| `expires_at`           | string | Expiry timestamp (ISO 8601)                                                   |
| `gateway.behavior`     | string | How to handle the response                                                    |
| `gateway.redirect_url` | string | Redirect URL — send the customer here for `BANK_TRANSFER` and `MOBILE_WALLET` |

### Which URL to Send the Customer To

| `payment_method` | Send the customer to                                     |
| ---------------- | -------------------------------------------------------- |
| `QR_PAYMENT`     | `payment_url` — the payment page displays the DuitNow QR |
| `BANK_TRANSFER`  | `gateway.redirect_url` — the bank authorization page     |
| `MOBILE_WALLET`  | `gateway.redirect_url` — the TNG authorization page      |

## Check Payment Status

Query the current status of a payment.

```http
GET /payment/status/:identifier
Authorization: Bearer <access_token>
```

`:identifier` accepts either the JGoPay `payment_id` (`PAY_xxx`) or your own `reference_id` — so you can check status without storing our ID. Reference IDs are alphanumeric, so no URL encoding is needed. If a `payment_id` match is found it wins; otherwise the value is looked up as a `reference_id` within your account.

### Response

```json
{
  "status": "success",
  "data": {
    "payment_id": "PAY_MYR12345",
    "reference_id": "ORDER20260325001",
    "amount": 100.00,
    "currency": "MYR",
    "status": "SUCCESS",
    "gateway_reference": "TXN_20260325_ABC123",
    "created_at": "2026-03-25T12:00:00Z",
    "completed_at": "2026-03-25T12:15:30Z",
    "expires_at": "2026-03-25T12:30:00Z"
  }
}
```

| Field               | Type   | Description                                                                                       |
| ------------------- | ------ | ------------------------------------------------------------------------------------------------- |
| `payment_id`        | string | JGoPay payment identifier                                                                         |
| `reference_id`      | string | Your original reference ID                                                                        |
| `amount`            | number | Payment amount                                                                                    |
| `currency`          | string | Currency code                                                                                     |
| `status`            | string | Current status (`PENDING`, `PROCESSING`, `SUCCESS`, `FAILED`, `EXPIRED`, `CANCELLED`, `REFUNDED`) |
| `gateway_reference` | string | Gateway's transaction reference (`null` until processed)                                          |
| `created_at`        | string | Creation timestamp (ISO 8601)                                                                     |
| `completed_at`      | string | Completion timestamp (`null` if not completed)                                                    |
| `expires_at`        | string | Expiry timestamp (`null` if not set)                                                              |

> Use this endpoint as a fallback to verify payment status if you don't receive a callback. Do not use it as the primary status mechanism — rely on [callbacks](/english/webhooks.md) instead.

## Gateway Behaviors

| Behavior            | Action                   | Methods              |
| ------------------- | ------------------------ | -------------------- |
| `REDIRECT_EXTERNAL` | Redirect to gateway page | DuitNow QR, FPX, TNG |

All MYR payment methods use the redirect flow — see [Payment Methods](/english/payment-methods.md) for details on each.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.jgopay.com/english/create-payment.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
