# Gateway Routing

Control which payment gateway (processor account) processes each transaction.

---

## Overview

A merchant can hold several gateways. For each card sale AuxCORE picks one, in this order — the first rule that names a usable gateway wins:

1. **Limit reroute** - a merchant limit rule or WatchDog volume rule that reroutes to another gateway ([Risk Management](../fraud/risk.md))
2. **Identity reroute** - a KYC / AssureLocate gate that names a gateway
3. **Caller hint** - `preferredGateway` or `gatewayHint` in the transaction request
4. **Hybrid payer route** - the gateway configured for the selected payer (`payer: merchant | cardholder`), when the merchant uses the hybrid fee model
5. **Priority** - the active, card-capable gateway with the lowest `priority` number

Every step is constrained by **payment purpose**: a gateway reserved for a purpose (e.g. `donation`) only takes payments that declare that purpose, and an ordinary payment never lands on it.

Card-capable means `paymentMode` is `Card` or `Both` and `acceptCard` is not `false`. There is no cross-rail fallback: a merchant with no card gateway gets an error rather than a card sent to an ACH or crypto gateway.

> **Note:** There is no `/merchants/:merchantId/gateway-routing` endpoint and no expression-based rule language. Routing is configured on the gateway records below.

All endpoints are admin API routes: `Authorization: Bearer <JWT>` (or an API key in `x-api-key`).

---

## List Gateways

```http
GET /api/v1/merchants/:merchantId/gateways
```

```bash
curl https://uat.auxcore.net/api/v1/merchants/3f2a9c1e-7b4d-4e8a-9f10-2c5d6e7f8a90/gateways \
  -H "Authorization: Bearer YOUR_TOKEN"
```

## Get the Primary Gateway

```http
GET /api/v1/merchants/:merchantId/gateways/primary
```

Returns the active gateway with the lowest `priority`. On a priority tie this endpoint returns the **oldest** gateway, while routing picks the newest, so keep priorities distinct.

## Gateway Stats

```http
GET /api/v1/merchants/:merchantId/gateways/stats
```

---

## Set Gateway Priority

Lower number = tried first. Give each gateway a distinct priority; on a tie the most recently created gateway wins.

```http
PATCH /api/v1/merchants/:merchantId/gateways/:id/priority
```

```bash
curl -X PATCH https://uat.auxcore.net/api/v1/merchants/3f2a9c1e-7b4d-4e8a-9f10-2c5d6e7f8a90/gateways/9b2c4d6e-1a3f-4b5c-8d7e-0f1a2b3c4d5e/priority \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "priority": 1 }'
```

**Response:** `{ "success": true, "message": "Gateway priority updated successfully", "data": { … } }`. Unknown gateway → `404` with `{ "success": false, "message": "Gateway not found" }`.

---

## Enable / Disable a Gateway

Only `ACTIVE` gateways are routed to.

```http
PATCH /api/v1/merchants/:merchantId/gateways/:id/status
```

```json
{ "status": "INACTIVE" }
```

`status` is one of `ACTIVE`, `INACTIVE`, `SUSPENDED`, `TESTING`; anything else returns `400` `Invalid status value`.

---

## Routing Rules on a Gateway

Each gateway can carry `routingRules`, set with the gateway update:

```http
PUT /api/v1/merchants/:merchantId/gateways/:id
```

```json
{
  "routingRules": {
    "paymentPurpose": "donation"
  },
  "loadBalanceWeight": 50,
  "perTransactionLimit": 5000
}
```

| Field | Description |
|-------|-------------|
| `routingRules.paymentPurpose` | Reserves the gateway for one purpose. Slug `[a-z0-9_-]{1,30}`; invalid values are rejected. A merchant must keep at least one active general (unreserved) card gateway. |
| `loadBalanceWeight` | Percentage weight for weighted load balancing (default `50`) |
| `perTransactionLimit` | Sales above this amount are refused on this gateway |
| `visaEnabled` / `mastercardEnabled` / `amexEnabled` / `discoverEnabled` | Card brands accepted |

`GET /api/v1/public/payment-purposes` (API key) lists the purposes configured for the merchant.

---

## Rotation and Load Balancing

Merchant-level rotation is configured with the gateway switch.

### Initialize the Gateway Switch

```http
POST /api/v1/merchants/:merchantId/gateway-switch/initialize
```

```json
{
  "baseGateway": { "name": "NMI" },
  "secondaryGateway": { "name": "TsysSierra" },
  "rotationEnabled": true,
  "rotationStrategy": "failover",
  "transactionCountLimit": 50
}
```

- `rotationStrategy: "weighted"` (or `"load_based"`) - picks among gateways at random in proportion to `loadBalanceWeight`.
- `rotationEnabled: true` with another strategy - alternates primary and secondary every `transactionCountLimit` transactions.
- Otherwise the primary gateway is used.
- With no stored rotation config at all, a merchant with more than one gateway whose `loadBalanceWeight` is above `0` is load balanced by weight automatically.

Initializing the switch resets the transaction counter and always sets `failoverEnabled` to `true`.

### Get Gateway Switch Status

```http
GET /api/v1/merchants/:merchantId/gateway-switch-status
```

**Response:** `data` = `{ rotationEnabled, failoverEnabled, primaryGateway, secondaryGateway, rotationStrategy, currentTransactionCount, transactionCountLimit, rotationGatewayIds }`.

---

## Failover

If the chosen gateway returns a gateway error, a processing error or a timeout, AuxCORE retries the sale on the next available gateway, once per configured gateway. A normal decline from the issuer is **not** failed over.

---

## Choosing a Gateway per Request

Public API transactions may pass a hint:

```http
POST /api/v1/public/transaction
```

```json
{
  "Amount": 100.00,
  "SuggestedMode": "Card",
  "pciToken": "pci_tok_8f2c1a9b7e4d",
  "gatewayHint": "TsysSierra"
}
```

`preferredGateway` / `gatewayHint` accept a gateway type, display name or gateway id. A hint that names a gateway reserved for a different payment purpose is ignored.

---

**Need help?** Contact support@auxcore.net
