---
title: Payments & gateways
description: Beginner-friendly setup guides for every Yatra payment gateway — PayPal, Pay Later, Stripe, Razorpay, Mollie, Paystack, Square, Authorize.Net, Bank Transfer. Every field, where to get the key from the gateway dashboard, screenshots, and a test workflow.
---
# Payments & gateways
Pro
Stripe and six other gateways are Yatra Pro. The free plugin ships with PayPal & Pay Later. Activate a license under Yatra → License to unlock the rest.
View pricing →
Yatra's free plugin includes **PayPal** and **Pay Later** as fully-working gateways. The other seven — Stripe, Razorpay, Mollie, Paystack, Square, Authorize.Net, Bank Transfer — are part of **Yatra Pro**.
::: tip New to payment gateways?
Each gateway below has a **Before you start → Get your keys → Paste in Yatra → Test it** flow. Follow the steps in order, paste the values into the matching field in Yatra → Settings → Payment, and you'll have a working checkout in under 10 minutes per gateway.
:::
## What's included
| Gateway | Free | Pro | Slug (in source) | Where it shines |
| --- | :-: | :-: | --- | --- |
| **PayPal** | ✅ | ✅ | `paypal` | Globally trusted; Simple (email + IPN) and Advanced (REST) modes. |
| **Pay Later** | ✅ | ✅ | `pay_later` | Pay-on-arrival / wire transfer / cash workflow. |
| **Stripe** | — | ✅ | `stripe` | Cards + Apple Pay / Google Pay, scheduled balance payments. |
| **Razorpay** | — | ✅ | `razorpay` | India: cards, UPI, netbanking, wallets. |
| **Mollie** | — | ✅ | `mollie` | Europe: iDEAL, Bancontact, SEPA, cards. |
| **Paystack** | — | ✅ | `paystack` | Africa-first; cards, transfers, mobile money. |
| **Square** | — | ✅ | `square` | NA / UK / AU / JP cards. |
| **Authorize.Net** | — | ✅ | `authorize_net` | US-centric merchant accounts. |
| **Bank Transfer** | — | ✅ | `bank_transfer` | Manual settlement; bank details on confirmation. |
## Where to configure
Open Yatra → Settings → Payment.

The screen has these sections:
1. **Global** — master *Test mode* switch and *Auto-confirm Pay Later bookings*.
2. **Partial / Deposit / Scheduled payments** — Pro-only flows (see [Settings → Payment](/settings#_5-payment) for every field).
3. **Gateways** — every gateway as a card with an **Enable** toggle and a **Settings** disclosure. Pro-only gateways display a **PRO** badge until you have an active license.
::: warning One Test Mode switch for all gateways
A single setting — `yatra_payment_test_mode` (default `true`) — drives test mode for **every** gateway. Each gateway stores both `live_*` and `test_*` key pairs and Yatra picks the active pair from this flag. There's no per-gateway test toggle in the current UI.
:::
## Currency
Configured under Settings → Currency — see [Settings → Currency](/settings#_9-currency). The currency code is global; multi-currency at checkout is a Pro module.
---
## PayPal (free)
PayPal is the most widely-recognised gateway and is the simplest to set up. Yatra offers two modes — start with **Simple** for testing, upgrade to **Advanced (REST)** when you go live.

### Before you start
- You'll need a **PayPal Business** account: .
- For test mode, also sign up for the free **PayPal Developer Sandbox**: .
### Mode A — Simple (email + IPN)
Easiest to set up. You only need your PayPal business email. Good for low-volume / trial use.
**Step 1: Note your PayPal email.** It's the email you used to sign up for your PayPal Business account.
**Step 2: Paste in Yatra.**
| Yatra field | Where it goes |
| --- | --- |
| **Mode** | Select **Simple (email + IPN)**. |
| **PayPal email** | Your PayPal Business email. |
**Step 3: Save**, then enable PayPal at the top of the panel and click **Save Settings**.
PayPal will POST IPN notifications to `https://yoursite.com/wp-json/yatra/v1/payment/webhook/paypal-ipn` after each transaction — no manual webhook setup needed in Simple mode.
### Mode B — Advanced (REST)
Full webhook support and the basis for scheduled / partial payments. Requires a REST app in your PayPal Developer dashboard.
**Step 1: Create a REST app.**
1. Sign in at .
2. Click **Apps & Credentials** → flip the **Sandbox / Live** toggle to **Live** when you're ready (start with Sandbox).
3. Click **Create App**, name it `Yatra YOUR-SITE`, pick your business account, save.
**Step 2: Copy the credentials.**
On the app page you'll see:
- **Client ID** — long alphanumeric string.
- **Secret** — click *Show* to reveal.
Keep the page open — you'll need both in a moment.
**Step 3: Paste in Yatra.**
| Yatra field | Where it goes |
| --- | --- |
| **Mode** | Select **Advanced (REST)**. |
| **Client ID** | The Client ID from the developer app page. |
| **Client Secret** | The Secret value (click *Show* in the PayPal dashboard to reveal). |
**Step 4: Save**, then enable PayPal, click **Save Settings**.
::: tip There's no "Webhook ID" field
Earlier doc revisions asked for a "Webhook ID" — that field does not exist in `PayPalGateway::getConfigFields()`. PayPal verification is handled internally based on Client ID / Secret.
:::
### Test it
- Confirm global Test mode is on under Settings → Payment → Global.
- If using Advanced REST, switch your PayPal app to Sandbox and use sandbox-account credentials.
- Book a trip on the front-end → choose PayPal at checkout.
- Pay with a sandbox personal account (PayPal creates one automatically; password is in your dev dashboard).
- Return to your site — booking should flip to Confirmed, payment to Completed.
### Useful links
- PayPal Developer Dashboard:
- Sandbox test accounts:
- PayPal pricing:
---
## Pay Later (free)
Not a real payment gateway — it lets customers reserve a booking now and pay later via cash, wire transfer, or cheque. Useful for travel agents with a deposit + balance workflow.

### How to configure
| Yatra field | Setting ID | Default | What to put |
| --- | --- | --- | --- |
| **Payment deadline (days)** | `payment_deadline_days` | `7` | Days after booking by which the customer must pay. Shown on the confirmation page and reminder email. |
| **Auto-cancel after (days)** | `auto_cancel_days` | `14` | Unpaid bookings older than this are auto-cancelled by the cron. Set `0` to disable auto-cancel. |
| **Require deposit at booking** | `require_deposit` | `false` | When on, the customer must pay a deposit through a real gateway before the Pay Later flow activates. |
| **Deposit amount** | `deposit_amount` | `0` | Currency amount required as deposit when *Require deposit* is on. |
| **Payment reminder (days before)** | `reminder_days` | `3` | How many days before the deadline to email the *Payment due* reminder. |
::: tip Auto-confirm
The *Settings → Payment → Auto-confirm Pay Later bookings* checkbox (under the Global section) skips the *Pending* state — useful when you're comfortable confirming on trust.
:::
When customers pick **Pay Later** at checkout, Yatra creates a **Pending** booking. Once you've received the money, mark the payment **Completed** in Yatra → Payments.
---
## Stripe PRO
PRO
Stripe — cards, wallets, scheduled balance payments
Yatra Pro includes Stripe with first-class checkout integration plus support for the Scheduled Payments module — auto-charge the balance on a future date.
Unlock Stripe →

### Before you start
- Sign up at — free, no credit card needed for test mode.
- To go live you'll need to verify your business (Stripe walks you through it after sign-up).
### Step 1 — Get your API keys
Stripe has separate **test** and **live** keys. Yatra stores **both pairs** and the global *Test mode* flag picks which is active. Generate both.
1. Open (test mode).
2. You'll see:
- **Publishable key** — starts with `pk_test_…`. Visible by default — copy it.
- **Secret key** — starts with `sk_test_…`. Click **Reveal** → copy it.
3. Now flip to live mode at the top-right and open .
4. Repeat: copy `pk_live_…` and `sk_live_…`.
::: tip Restricted keys
For tighter security in production you can use a **restricted key** (`rk_live_…`) instead of the secret key. It works as long as you grant it Read+Write on Payment Intents, Charges, Refunds, Webhook Endpoints, and Customers.
:::
### Step 2 — Create a webhook
1. Open (or `/test/webhooks` for the test endpoint).
2. Click **+ Add endpoint**.
3. **Endpoint URL:** `https://yoursite.com/wp-json/yatra/v1/payment/stripe/webhook`
4. **Listen to events** — pick **Select events** and tick at minimum:
- `payment_intent.succeeded`
- `payment_intent.payment_failed`
- `charge.refunded`
5. Click **Add endpoint**.
6. On the endpoint detail page, find **Signing secret** → click **Reveal** → copy the `whsec_…` value.
7. Repeat for the live mode if you have a separate live endpoint.
### Step 3 — Enable payment methods (optional)
By default Stripe only enables card payments. To add Apple Pay / Google Pay / Klarna / etc.:
1. Open .
2. Toggle on the methods you want.
3. Most need domain verification (Stripe shows the steps inline).
### Step 4 — Paste in Yatra
| Yatra field | Setting ID | Where it comes from |
| --- | --- | --- |
| **Live publishable key** | `live_publishable_key` | `pk_live_…` from step 1 (live tab). |
| **Live secret key** | `live_secret_key` | `sk_live_…` from step 1 (live tab). |
| **Test publishable key** | `test_publishable_key` | `pk_test_…` from step 1 (test tab). |
| **Test secret key** | `test_secret_key` | `sk_test_…` from step 1 (test tab). |
| **Webhook signing secret** | `webhook_secret` | `whsec_…` from step 2 — required since Yatra Pro 3.0.4. |
| **Enabled payment methods** | `enabled_methods` | Multi-select. Tick the methods you enabled in step 3. |
### Step 5 — Test it
- Confirm global Test mode is on.
- Book a trip → pick Stripe at checkout.
- Use Stripe's test card:
4242 4242 4242 4242 · any future expiry · any 3-digit CVC.
- Verify the booking shows Confirmed, payment Completed, and the receipt email arrives.
- Refund from the Stripe dashboard to make sure the webhook flips the payment to Refunded in Yatra.
::: warning Webhook secret is required (3.0.4+)
The Stripe webhook handler **rejects** any event that lacks a valid `Stripe-Signature` header. Without the **Webhook signing secret**, webhook deliveries fail and the booking updates only via the synchronous return-to-site flow.
Signature verification is HMAC-SHA256 over `{timestamp}.{raw-body}` with a 5-minute replay window — the same scheme as Stripe's official PHP SDK.
:::
### Useful links
- Stripe Dashboard → API keys:
- Stripe Dashboard → Webhooks:
- Stripe test cards:
- Stripe pricing:
---
## Razorpay PRO
Popular in India — supports cards, UPI, netbanking, and wallets in INR.

### Before you start
- Sign up at — Indian business (Indian bank account + KYC required to receive INR payouts).
- Razorpay has a built-in test mode; no separate sandbox account needed.
### Step 1 — Get your API keys
1. Sign in at .
2. From the left sidebar pick **Account & Settings → API Keys** (or open ).
3. Click the test/live toggle at the top right.
4. Click **Generate Test Key** (or **Generate Live Key**). A modal shows:
- **Key ID** — starts with `rzp_test_…` or `rzp_live_…`. Visible.
- **Key Secret** — shown **once**. Copy and save it now; Razorpay will never show it again.
5. Repeat for the other mode if you want both.
### Step 2 — Configure the webhook (optional but recommended)
Async webhook is helpful because the redirect-back can fail (browser closed, mobile network drop, etc.). Razorpay still confirms via webhook.
1. Open **Account & Settings → Webhooks** ().
2. Click **+ Add New Webhook**.
3. **Webhook URL:** `https://yoursite.com/wp-json/yatra/v1/payment/webhook/razorpay`
4. **Active Events:** tick at least `payment.captured`, `payment.failed`, `refund.processed`.
5. **Secret:** leave blank for now (Yatra verifies via Key Secret in this version).
6. Save.
### Step 3 — Paste in Yatra
| Yatra field | Setting ID | Notes |
| --- | --- | --- |
| **Key ID** | `key_id` | `rzp_test_…` or `rzp_live_…` from step 1. |
| **Key Secret** | `key_secret` | Paired secret from step 1. |
### Test it
Razorpay's test mode accepts the test card `4111 1111 1111 1111`, any future expiry, any CVC.
### Useful links
- Razorpay Dashboard:
- API Keys page:
- Webhooks page:
- Test cards & UPI IDs:
---
## Mollie PRO
Strong in Europe (Netherlands, Belgium, Germany, France) — iDEAL, Bancontact, SEPA, cards.

### Before you start
- Sign up at — European business with a European bank account.
- Mollie's test mode is built into your live account (toggle in the dashboard header).
### Step 1 — Get your API key
1. Sign in at .
2. In the dashboard header switch to **Test mode** (left) or **Live mode** (right) — Mollie shows separate keys for each.
3. From the left sidebar pick **Developers → API keys** (or open ).
4. Copy the appropriate key:
- **Test API key** — starts with `test_…`.
- **Live API key** — starts with `live_…`. Required for production.
::: tip Mollie auto-detects the mode
Unlike Stripe, Mollie has **one key per mode**, and Mollie itself reads the `test_` / `live_` prefix to decide what mode to run in. You only paste ONE key into Yatra — and you swap it manually when you go live.
:::
### Step 2 — Activate payment methods
1. Open .
2. For each profile, click **Payment methods** and tick the ones you want (iDEAL, Bancontact, SEPA, credit card, etc.).
3. Some methods need extra verification (e.g. Apple Pay needs domain verification).
### Step 3 — Paste in Yatra
| Yatra field | Setting ID | Notes |
| --- | --- | --- |
| **API key** | `api_key` | The `test_…` or `live_…` key from step 1. Mollie auto-detects the mode from the prefix. |
| **Webhook URL** | `webhook_url` | Auto-populated to `https://yoursite.com/wp-json/yatra/v1/payment/mollie/webhook`. Only change this if your site sits behind a proxy / reverse-host. |
| **Payment methods** | `payment_methods` | Multi-select. Leave empty to offer everything you've enabled in step 2. |
::: warning Mollie needs a publicly-reachable URL
Mollie only delivers webhooks to internet-accessible URLs. On a local-dev site (`yatra.local`, `localhost`) the gateway skips sending the `webhookUrl` parameter; confirmation happens via the return-to-site flow only. Use an ngrok tunnel for full local testing.
:::
### Useful links
- Mollie Dashboard:
- API keys page:
- Profiles & payment methods:
- Test payment methods reference:
---
## Paystack PRO
Africa-first — cards, bank transfer, USSD, mobile money. Primary in Nigeria, Ghana, Kenya, South Africa.

### Before you start
- Sign up at .
- Paystack has a built-in test mode toggle on the dashboard — no separate sandbox sign-up needed.
### Step 1 — Get your API keys
1. Sign in at .
2. From the sidebar pick **Settings → API Keys & Webhooks** (or open ).
3. You'll see two pairs:
- **Test Public Key** (`pk_test_…`) and **Test Secret Key** (`sk_test_…`).
- **Live Public Key** (`pk_live_…`) and **Live Secret Key** (`sk_live_…`) — visible only after Paystack approves your account.
4. Click **Show** beside each secret key, copy both pairs.
### Step 2 — Configure the webhook URL
Paystack lets you set one webhook URL per environment.
1. On the same **Settings → API Keys & Webhooks** page, scroll to **Webhook URL**.
2. Paste `https://yoursite.com/wp-json/yatra/v1/payment/paystack/webhook` for live.
3. Add the test webhook URL after toggling to test mode (or use the same — Paystack signs every event with the secret key).
### Step 3 — Paste in Yatra
| Yatra field | Setting ID | Notes |
| --- | --- | --- |
| **Public key** | `public_key` | `pk_live_…` or `pk_test_…`. Toggle the right pair based on the global *Test mode*. |
| **Secret key** | `secret_key` | `sk_live_…` or `sk_test_…`. Used for HMAC signature verification on webhooks. |
| **Webhook URL** | `webhook_url` | Auto-populated. Only change if proxied. |
| **Payment channels** | `payment_channels` | Multi-select (cards, bank transfer, USSD, mobile money, QR, EFT). Empty = all enabled on your Paystack account. |
### Useful links
- Paystack Dashboard:
- API Keys & Webhooks:
- Test cards:
- Paystack supported countries:
---
## Square PRO
US, UK, Canada, Australia, Japan. Useful when you also take in-person payments via Square's POS hardware.

### Before you start
- Sign up at .
- For development, sign in to the Square Developer Dashboard with the same Square account: .
### Step 1 — Create a developer application
1. Open .
2. Click **+ Create your first application** (or **+** at the top right). Name it `Yatra YOUR-SITE`.
3. On the application page you'll see two tabs: **Sandbox** and **Production**. Both have their own credentials.
### Step 2 — Copy credentials
On the **Production** tab (and again on **Sandbox** for testing), grab:
- **Application ID** — starts with `sq0idp-…` for production, `sandbox-sq0idb-…` for sandbox.
- **Access token** — under **Credentials**. Click **Reveal token** to see it. Starts with `EAAA…`.
You'll also need a **Location ID** — Square requires charges to be tied to a physical location.
### Step 3 — Find your Location ID
1. Open **Locations** in the developer dashboard sidebar, or in your Square dashboard go to **Account & Settings → Business → Locations**: .
2. Each location has an ID like `LXXX1234567890`. Copy the one matching the country/region you want to charge in.
### Step 4 — Paste in Yatra
| Yatra field | Setting ID | Where it comes from |
| --- | --- | --- |
| **Application ID** | `application_id` | The `sq0idp-…` / `sandbox-sq0idb-…` from the Developer app page. |
| **Access token** | `access_token` | The `EAAA…` token revealed on the Developer app page. |
| **Location ID** | `location_id` | The `LXXX…` ID from the Locations screen. |
Sandbox uses its own credentials. The global *Test mode* flag picks which set Yatra uses.
### Useful links
- Square Developer Dashboard:
- Locations:
- Square pricing:
- Sandbox test cards:
---
## Authorize.Net PRO
US-centric — popular with established merchants who already have an Authorize.Net merchant account through their acquirer.

### Before you start
- You need an active Authorize.Net merchant account. Sign up at .
- For development, register a free sandbox account at .
### Step 1 — Get API Login ID and Transaction Key
1. Sign in to **Merchant Interface**: (live) or (sandbox).
2. In the left menu pick **Account → Settings → Security Settings → General Security Settings → API Credentials & Keys**.
3. The **API Login ID** is shown plainly. Copy it.
4. To generate a new **Transaction Key**:
- Select *New Transaction Key*.
- Click **Submit** — Authorize.Net emails you a verification PIN.
- Enter the PIN. The new key is shown **once**. Copy it immediately.
### Step 2 — Get the Public Client Key
Still on **API Credentials & Keys**:
1. Scroll to **Public Client Key**.
2. Click **Submit** to generate one if it's empty.
3. Copy the key. This is what Yatra uses for Accept.js to tokenize card data in the browser.
### Step 3 — Paste in Yatra
| Yatra field | Setting ID | Notes |
| --- | --- | --- |
| **API Login ID** | `api_login_id` | From step 1. |
| **Transaction Key** | `transaction_key` | From step 1. |
| **Public Client Key** | `public_client_key` | From step 2 — required for Accept.js card tokenisation. |
Sandbox URL: `https://sandbox.authorize.net`. The global *Test mode* flag flips between live and sandbox endpoints.
### Useful links
- Live Merchant Interface:
- Sandbox Merchant Interface:
- Sandbox sign-up:
- Test credit cards:
---
## Bank Transfer PRO
No external account, no credentials — you just publish your bank details on the booking confirmation page. The booking is **Pending** until you mark it paid in Yatra → Payments.

| Yatra field | Setting ID | Notes |
| --- | --- | --- |
| **Bank name** | `bank_name` | Displayed on the booking confirmation page. |
| **Account holder name** | `account_name` | Displayed on the booking confirmation page. |
| **Account number** | `account_number` | Displayed on the booking confirmation page. |
| **Routing / SWIFT code** | `routing_code` | IBAN, SWIFT, ABA — whichever your bank requires. Free-text. |
| **Customer instructions** | `instructions` | Free-text shown to the customer beneath the bank details. |
PRO
Seven premium gateways — one license
Stripe, Razorpay, Mollie, Paystack, Square, Authorize.Net, and Bank Transfer all unlock with a single Yatra Pro license.
Compare Yatra Pro plans →
---
## Deposits, partial & scheduled payments PRO
These three flows live above the gateway list on **Settings → Payment** — they apply universally regardless of which gateway the customer picks. Full schema reference: [Settings → Payment](/settings#_5-payment).
| Flow | Key fields |
| --- | --- |
| **Partial payment** | `partial_payment` (toggle), `partial_payment_percentage` — customer pays a percentage at booking, the rest later. |
| **Deposit** | `deposit_required` (toggle), `deposit_percentage` — a percentage charged upfront before the booking is held. |
| **Scheduled balance** | `enable_scheduled_payments`, `scheduled_payment_type` (`single` / `installments`), `scheduled_payment_days`, `scheduled_payment_installments`, `scheduled_payment_interval`, `scheduled_payment_reminder_days`. |
Per-trip overrides live in the **Advanced** section of the Trip Builder (see [Create a trip → 4.1 Advanced Settings](/trip-creation#_4-1-advanced-settings)).
---
## The Payments admin

Open Yatra → Payments. You'll see every payment record across all bookings.
- **Search** by payment number, customer, or transaction ID.
- **Status filter** — All / Completed / Pending / Partial / Failed / Refunded / Cancelled.
- **Method filter** — filter by gateway.
- **Sort** — by Payment Date or Payment Number (asc / desc).
- **Default columns** — Payment, Customer, Booking, Amount, Method, Status, Date.
### Bulk actions
Tick rows and pick:
- Mark as Completed
- Mark as Failed
- Mark as Refunded
- Mark as Cancelled
- Delete permanently
### Add a payment manually

Click **+ Add New Payment** to record an offline payment (cash, wire, cheque):
| Field | Notes |
| --- | --- |
| **Booking** | Searchable dropdown (search by booking code, customer name, or email). |
| **Amount** | Number with the currency's decimal places. |
| **Payment Method** | Select — Credit Card / Debit Card / PayPal / Bank Transfer / Cash / Check / Other. |
| **Payment Date** | Date picker — cannot be in the future. Default = today. |
| **Transaction ID** | Optional reference (`TXN-12345`, internal ledger ID, etc.). |
| **Notes** | Internal-only text. |
| **Payment Status** | Sidebar select — Pending / Completed / Partial / Failed / Refunded / Cancelled. Default = `pending`. |
Click **Save Payment**. The booking's **Due Now** updates instantly.
---
## Refunds
| Gateway | Recommended refund flow |
| --- | --- |
| **PayPal / Stripe** | Refund in the gateway dashboard first, then mark refunded in Yatra. |
| **Razorpay / Mollie / Paystack / Square / Authorize.Net** | Same — gateway dashboard first, then mark refunded. |
| **Pay Later / Bank Transfer** | Refund manually via your bank, then mark refunded. |
To mark refunded:
- **Single payment** — open Payments, click the row → Edit → set **Status** to **Refunded**.
- **Bulk** — tick rows in the Payments list → bulk action **Mark as Refunded**.
When you mark refunded:
- The payment status changes to **Refunded**.
- The booking's payment status updates accordingly.
- An invoice download is still available (now marked refunded).
- The `yatra_payment_refunded` action fires for downstream automations.
## Test mode workflow
A safe way to test any gateway:
- Confirm the global Test mode is on under Settings → Payment → Global.
- Paste sandbox / test keys into the gateway's settings card.
- Set up the gateway webhook in sandbox mode pointing to your staging URL.
- Book a trip as a fresh test customer with the gateway's test card or sandbox account.
- Verify: booking shows Confirmed, payment shows Completed, and the receipt email arrives.
- Switch the global Test mode off, paste live keys, switch the webhook to live mode, and run one small live transaction with a real card. Refund it via the gateway dashboard.
## Payment-flow security model (3.0.4+)
Yatra's payment endpoints enforce three guarantees out of the box. You don't need to configure anything — these run on every checkout — but it's useful to know how they affect testing.
**1. Server-authoritative amounts.** When the React checkout calls `POST /yatra/v1/payment/create-intent` with a `booking_id`, Yatra ignores any `amount` / `currency` in the request body and recomputes them from the stored booking row (`amount_due`, `currency`). A tampered front-end cannot pay $1 for a $1000 trip. If the amounts disagree, Yatra forces the server value and fires the `yatra_payment_amount_mismatch` action so you can wire it to a fraud-monitoring tool.
**2. Booking ownership.** `POST /yatra/v1/payment/confirm` and `GET /yatra/v1/payment/status/{id}` require either:
- the requester is the registered user who owns the booking, **or**
- the requester is an administrator (`manage_options`), **or**
- the booking is a guest booking AND the request includes a matching `booking_token` (the short-lived transient set during checkout).
Anonymous reads of arbitrary booking IDs return `401`.
**3. Idempotent payment recording.** Each `(booking_id, transaction_id)` pair can only ever produce one row in the booking-payments table. A duplicate Stripe webhook, a re-clicked confirm button, or a parallel return-to-site + webhook race all collapse to a single payment record and a single confirmation email. Partial / deposit payments correctly accumulate `amount_paid` instead of being force-marked fully paid.
If you write a custom gateway, follow the same pattern by either calling `\Yatra\Repositories\PaymentRepository::findByTransactionId()` before inserting, or by extending `AbstractPaymentGateway::completePayment()`-style helpers that already include the guard.
## Webhook URLs (cheat sheet)
The free PayPal gateway uses a unified webhook controller (`/payment/webhook/{slug}`). Mollie, Paystack, and Stripe expose their own gateway-specific routes. The remaining gateways either don't surface a webhook field in this build, or fall through to the unified route.
```
# Free
https://yoursite.com/wp-json/yatra/v1/payment/webhook/paypal
https://yoursite.com/wp-json/yatra/v1/payment/webhook/paypal-ipn
# Pro — gateway-specific routes
https://yoursite.com/wp-json/yatra/v1/payment/stripe/webhook
https://yoursite.com/wp-json/yatra/v1/payment/mollie/webhook
https://yoursite.com/wp-json/yatra/v1/payment/paystack/webhook
# Pro — unified route (fallback)
https://yoursite.com/wp-json/yatra/v1/payment/webhook/razorpay
https://yoursite.com/wp-json/yatra/v1/payment/webhook/square
https://yoursite.com/wp-json/yatra/v1/payment/webhook/authorize_net
```
::: tip Where the routes are registered
The unified pattern is in `app/Controllers/PaymentGatewayController.php` (line 89): `register_rest_route( …, '/payment/webhook/(?P[a-z_]+)', … )`. Gateway-specific routes (Mollie, Paystack, Stripe) are registered in their own classes — search the Pro plugin for `register_rest_route` to confirm.
:::
## What's next
- [Email & notifications](/email-settings) — what fires after confirmation.
- [Settings → Payment](/settings#_5-payment) — the deposit / partial / scheduled-payment field reference.
- [Pro modules](/third-party-integrations) — every Pro feature, including Dynamic Pricing and Flexible Payments.
- [Troubleshooting](/troubleshooting).