# Reversal (CCREVERSE)

Reverse or void an authorization before it settles, with an option to auto-reroute to a credit if it already has.

Source: https://developer.inoviopay.com/api/reversal.html  
Markdown: https://developer.inoviopay.com/api/reversal.md

Merchants may request to reverse or void the original authorization before it is settled.

**POST** `https://api.inoviopay.com/payment/pmt_service.cfm`

### Request Parameters

| Parameter | Description |
|---|---|
| `REQUEST_ACTION` (required) | Must be set to `CCREVERSE`. |
| `REQUEST_REF_PO_ID` (required) | Reference Order ID (`PO_ID`) of the original transaction. |
| `CREDIT_ON_FAIL` (optional) | If set to `1`, the system will automatically attempt to credit the transaction if the reversal request fails (e.g., if it already settled). |

### Handling the Response

Monitor the response to verify the authorization was successfully voided before settlement.

| Field Name | Description |
|---|---|
| `TRANS_STATUS_NAME` | Check this to ensure the reversal was `APPROVED`. |
| `TRANS_VALUE` | The approved reversal amount. Similar to credits, this will return as a negative value (e.g., `-25.00`). |
| `TRANS_ID` | The unique Transaction ID assigned specifically to this reversal event. |
| `PO_ID` | The original Purchase Order ID linking this void back to the initial authorization. |

**cURL**

```bash
curl -X POST "https://api.inoviopay.com/payment/pmt_service.cfm" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "request_action=CCREVERSE&req_username=api_user&req_password=P%40ssw0rd%21&site_id=12345&request_api_version=4.14&request_response_format=JSON&request_ref_po_id=18103630&credit_on_fail=1"
```

**PHP**

```php
use Inovio\Gateway\{Credentials, InovioClient};
use Inovio\Gateway\Refs\Refs;

$client = new InovioClient(new Credentials('api_user', 'P@ssw0rd!', '12345'), 'SANDBOX');

// creditOnFail: true sets CREDIT_ON_FAIL=1 — if the order already settled,
// the gateway re-routes this call to CCCREDIT instead of declining.
$reversed = $client->reverse(Refs::order('18103630'), creditOnFail: true);

echo $reversed->status, "\n";
echo $reversed->amount?->toWire(), "\n";   // negative on the wire
```

**Node**

```ts
import { InovioClient, Refs } from '@inovio/gateway-sdk';

const client = new InovioClient(
  { reqUsername: 'api_user', reqPassword: 'P@ssw0rd!', siteId: '12345' },
  { environment: 'SANDBOX' }
);

// NOTE: CREDIT_ON_FAIL is not exposed on reverse() yet — call the API
// directly (request_action=CCREVERSE&credit_on_fail=1) for the auto-credit reroute.
const reversed = await client.reverse(Refs.order('18103630'));

console.log(reversed.status);
console.log(reversed.amount?.amount);   // negative on the wire
```

**Python**

```python
from inovio_gateway import Credentials, InovioClient, Refs

client = InovioClient(Credentials("api_user", "P@ssw0rd!", "12345"), environment="SANDBOX")

# NOTE: CREDIT_ON_FAIL is not exposed on reverse() yet — call the API
# directly (request_action=CCREVERSE&credit_on_fail=1) for the auto-credit reroute.
reversed_tx = client.reverse(Refs.order("18103630"))

print(reversed_tx.status.value)
print(reversed_tx.amount.to_wire() if reversed_tx.amount else "-")   # negative on the wire
```

**Java**

```java
import com.inoviopay.gateway.refs.Refs;

// NOTE: CREDIT_ON_FAIL is not exposed on reverse() yet — call the API
// directly (request_action=CCREVERSE&credit_on_fail=1) for the auto-credit reroute.
TransactionResult reversed = client.reverse(Refs.order("18103630"));

System.out.println(reversed.status());
System.out.println(reversed.amount() == null ? "-" : reversed.amount().toWire());   // negative on the wire
```

**Response**

```json
{
  "REQUEST_ACTION": "CCREVERSE",
  "REQ_ID": "93827164",
  "TRANS_STATUS_NAME": "APPROVED",
  "TRANS_VALUE": -25.00,
  "CURR_CODE_ALPHA": "USD",
  "TRANS_VALUE_SETTLED": -25.00,
  "CURR_CODE_ALPHA_SETTLED": "USD",
  "TRANS_EXCH_RATE": "",
  "TRANS_ID": 3948572111,
  "CUST_ID": 7382910,
  "XTL_CUST_ID": "xT883mP",
  "PO_ID": 18103630,
  "XTL_ORDER_ID": "",
  "BATCH_ID": 883922,
  "PROC_NAME": "Inovio Primary",
  "MERCH_ACCT_ID": 110203,
  "CARD_BRAND_NAME": "Visa",
  "CARD_TYPE": "VISA CLASSIC",
  "CARD_CLASS": "Consumer Debit",
  "CARD_PREPAID": 1,
  "CARD_BANK": "BOFI FEDERAL BANK",
  "CARD_COUNTRY": "USA",
  "CARD_DETAIL": "Debit",
  "CARD_BALANCE": "",
  "PMT_L4": "2921",
  "PMT_ID": 4895565,
  "PMT_ID_XTL": "",
  "PMT_AAU_UPDATE_DT": "",
  "PMT_AAU_UPDATE_DESC": "",
  "PROC_UDF01": "",
  "ANI_RESP_DECISION": "",
  "PROC_UDF02": "",
  "PROC_AUTH_RESPONSE": "VOID813",
  "PROC_RETRIEVAL_NUM": "B2C3D4E5-F6A7-8B9C-0D1E-2F3A4B5C6D7E",
  "PROC_REFERENCE_NUM": "REF187604789",
  "PROC_REDIRECT_URL": "",
  "AVS_RESPONSE": "M",
  "CVV_RESPONSE": "M",
  "CARD_BRAND_TRANSID": "",
  "REQUEST_API_VERSION": "4.14",
  "P3DS_VENDOR": "",
  "P3DS_RESPONSE": "",
  "PO_LI_ID_1": "9928175",
  "PO_LI_COUNT_1": 1,
  "PO_LI_AMOUNT_1": -25.00,
  "PO_LI_PROD_ID_1": "111205",
  "MBSHP_ID_1": "",
  "TRANS_NTOKEN_USED": 0
}
```

## Reverse or credit in one call: CREDIT_ON_FAIL

`CCREVERSE` reverses the original authorization; `CCREVERSECAP` reverses a successful `CCCAPTURE` transaction instead. Both actions accept `CREDIT_ON_FAIL`.

Setting `CREDIT_ON_FAIL=1` on `CCREVERSE` (or `CCREVERSECAP`) tells the gateway that if the order is already settled, and therefore cannot be reversed, the gateway itself re-routes the request to `CCCREDIT` instead of just failing. You send one request and the gateway decides whether a reversal or a credit is the correct operation for the order's current state.

> **Verified against the gateway**
> This re-route behavior was verified against the gateway directly, not just claimed in the spec. The response for a re-routed request comes back with `REQUEST_ACTION` equal to `CCCREDIT`, not `CCREVERSE`. Check `REQUEST_ACTION` in the response, not just `TRANS_STATUS_NAME`, if you need to know server-side whether the re-route happened.
>
> Without `CREDIT_ON_FAIL`, attempting to reverse an already-settled order returns gateway service code 515 (a decline) instead of succeeding.

Because the re-route is transparent, do not write your own settlement pre-check before deciding whether to call `CCREVERSE` or `CCCREDIT`. Send `CCREVERSE` with `CREDIT_ON_FAIL=1` and read `REQUEST_ACTION` off the response to see which operation the gateway actually performed.
