Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions restapi/restendpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -1188,6 +1188,126 @@ curl -X POST \
"https://cloud.handpoint.io/moto/reversal"
```

## Reversal Operations <span class="badge badge--warning">Beta</span>

The Reversal endpoint allows you to **reverse any reversible transaction** (authorization, payment or refund) using only its identifier. The reversal is processed against the Handpoint gateway via Cloud API without requiring a physical payment terminal.

Cloud API currently supports:

- `POST /v1/reversal` — reverses a transaction identified by `originalGuid`.

All request and response payloads are defined in [Reversal objects](restobjects#reversal).

---

### /v1/reversal

`Reversal`

`POST /v1/reversal` is used to **reverse (void)** a previously completed transaction. The operation is linked to the original transaction via `originalGuid`. No card data is sent; the gateway resolves the original transaction internally.

Reversals are typically used to cancel an authorization or payment shortly after it was processed, subject to acquirer rules. For partial reversals, provide `amount` and `currency` to release only part of the held funds.

#### Parameters

| Parameter | Notes |
| --------- | ----- |
| `Header: ApiKeyCloud` <span class="badge badge--primary">Required</span> | Cloud API key used to authenticate the merchant. |
| `Request Body: ViscusReversalRequest` <span class="badge badge--primary">Required</span> | [ViscusReversalRequest](restobjects#viscusReversalRequest) object identifying the transaction to reverse. |

Typical fields (see [ViscusReversalRequest](restobjects#viscusReversalRequest) for full details):

* `originalGuid` <span class="badge badge--primary">Required</span> – GUID of the transaction to reverse.
* `messageReasonCode` <span class="badge badge--secondary">Optional</span> – ISO 8583 reason code. Defaults to `CUSTOMER_CANCELLATION` when not provided.
* `timestamp` <span class="badge badge--secondary">Optional</span> – Terminal timestamp in `YYYYMMDDHHmmssSSS` format. Defaults to the current server time when not provided.
* `amount` <span class="badge badge--secondary">Optional</span> – Amount to reverse, for partial reversals only (e.g. `"15.00"`).
* `currency` <span class="badge badge--secondary">Optional</span> – ISO 4217 3-character code, for partial reversals only (e.g. `"EUR"`).

#### Returns

| Result | Notes |
| ------ | ----- |
| `200` | Reversal accepted and processed. Response body is a parsed gateway object. |
| `400` | Business rule error from the gateway (for example, unknown `originalGuid` or reversal not allowed). Returned as `BadRequestError` with `error.code` and `error.details`. |
| `403` | Forbidden — the API key does not belong to a merchant, or the merchant is not configured. |
| `422` | Payload validation error (`VALIDATION_FAILED`) — `originalGuid` is missing, `messageReasonCode` is not one of the allowed values, or `currency` is not exactly 3 characters. |

#### Behaviour examples

* **Happy path – full reversal**

```shell
curl -X POST \
-H "Content-Type: application/json" \
-H "ApiKeyCloud: XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX" \
-d '{
"originalGuid": "0c9d9df0-48ec-11eb-81a1-470a19c80d3a"
}' \
"https://cloud.handpoint.io/v1/reversal"
```

* **Partial reversal**

```shell
curl -X POST \
-H "Content-Type: application/json" \
-H "ApiKeyCloud: XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX" \
-d '{
"originalGuid": "0c9d9df0-48ec-11eb-81a1-470a19c80d3a",
"amount": "15.00",
"currency": "EUR"
}' \
"https://cloud.handpoint.io/v1/reversal"
```

* **With explicit reason code**

```shell
curl -X POST \
-H "Content-Type: application/json" \
-H "ApiKeyCloud: XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX" \
-d '{
"originalGuid": "0c9d9df0-48ec-11eb-81a1-470a19c80d3a",
"messageReasonCode": "TIMEOUT_WAITING_FOR_RESPONSE"
}' \
"https://cloud.handpoint.io/v1/reversal"
```

* **Validation error – missing `originalGuid`**

```json
{
"error": {
"statusCode": 422,
"name": "UnprocessableEntityError",
"message": "The request body is invalid.",
"code": "VALIDATION_FAILED",
"details": [
{
"path": "",
"code": "required",
"message": "must have required property 'originalGuid'",
"info": { "missingProperty": "originalGuid" }
}
]
}
}
```

#### Code example – full reversal

```shell
curl -X POST \
-H "Content-Type: application/json" \
-H "ApiKeyCloud: XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX" \
-d '{
"originalGuid": "0c9d9df0-48ec-11eb-81a1-470a19c80d3a"
}' \
"https://cloud.handpoint.io/v1/reversal"
```

---

## Batch Operations <span class="badge badge--warning">Beta</span>

:::info
Expand Down
80 changes: 80 additions & 0 deletions restapi/restobjects.md
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,86 @@ The exact shape is very similar across these operations; some fields (such as `o
}
```

## Reversal {#reversal}

### ViscusReversalRequest {#viscusReversalRequest}

`ViscusReversalRequest` <span class="badge badge--info">Object</span>

Object used by the [`POST /v1/reversal`](restendpoints#reversal-operations) endpoint to reverse any reversible transaction. Only `originalGuid` is required; all other fields are optional and default to sensible values when not provided.

**Properties**

| Property | Description |
| -------- | ----------- |
| `originalGuid` <span class="badge badge--primary">Required</span> <br />*String* | GUID of the transaction to reverse (maximum 64 characters). |
| `messageReasonCode` <span class="badge badge--secondary">Optional</span> <br />*String* | ISO 8583 reason code for the reversal. Defaults to `CUSTOMER_CANCELLATION` when not provided. See [allowed values](#messageReasonCode) below. |
| `timestamp` <span class="badge badge--secondary">Optional</span> <br />*String* | Timestamp in `YYYYMMDDHHmmssSSS` format (17 characters). Defaults to the current server time when not provided. |
| `amount` <span class="badge badge--secondary">Optional</span> <br />*String* | Amount to reverse for partial reversals (e.g. `"15.00"`). When provided together with `currency`, only the specified amount is released from the hold. The most recent reversal received supersedes any earlier partial reversal. |
| `currency` <span class="badge badge--secondary">Optional</span> <br />[*Currency*](#currency) | ISO 4217 3-character currency code for partial reversals (e.g. `"EUR"`). Must be exactly 3 characters. |

#### Allowed values for `messageReasonCode` {#messageReasonCode}

| Value | Description |
| ----- | ----------- |
| `CUSTOMER_CANCELLATION` | Transaction cancelled by the customer. **Default when not provided.** |
| `UNSPECIFIED_NO_ACTION_TAKEN` | No action taken; reason unspecified. |
| `SUSPECTED_MALFUNCTION` | Terminal malfunction suspected. |
| `FORMAT_ERROR_NO_ACTION_TAKEN` | Format error with no action taken. |
| `COMPLETED_PARTIALLY` | Transaction completed only partially. |
| `ORIGINAL_AMOUNT_INCORRECT` | The original transaction amount was incorrect. |
| `RESPONSE_RECEIVED_TOO_LATE` | Response from the acquirer arrived after the timeout. |
| `CARD_ACCEPTOR_DEVICE_UNABLE_TO_COMPLETE_TRANSACTION` | The terminal was unable to complete the transaction. |
| `DEPOSIT_OUT_OF_BALANCE` | Deposit amount does not balance. |
| `NO_CHECK_IN_ENVELOPE` | No check found in the deposit envelope. |
| `PAYMENT_OUT_OF_BALANCE` | Payment amount does not balance. |
| `DEPOSIT_OUT_OF_BALANCE_APPLIED_CONTENTS` | Deposit out of balance after applying contents. |
| `PAYMENT_OUT_OF_BALANCE_APPLIED_CONTENTS` | Payment out of balance after applying contents. |
| `UNABLE_TO_DELIVER_MESSAGE_TO_POINT_OF_SERVICE` | Message could not be delivered to the point of service. |
| `SUSPECTED_MALFUNCTION_CARD_RETAINED` | Malfunction suspected; card was retained. |
| `SUSPECTED_MALFUNCTION_CARD_RETURNED` | Malfunction suspected; card was returned. |
| `SUSPECTED_MALFUNCTION_TRACK_3_NOT_UPDATED` | Malfunction suspected; track 3 was not updated. |
| `SUSPECTED_MALFUNCTION_NO_CASH_DISPENSED` | Malfunction suspected; no cash was dispensed. |
| `TIMED_OUT_AT_TAKING_MONEY_NO_CASH_DISPENSED` | Timed out while taking money; no cash dispensed. |
| `TIMED_OUT_AT_TAKING_CARD_CARD_RETAINED_AND_NO_CASH_DISPENSED` | Timed out taking card; card retained and no cash dispensed. |
| `INVALID_RESPONSE_NO_ACTION_TAKEN` | Invalid response received; no action taken. |
| `TIMEOUT_WAITING_FOR_RESPONSE` | Timed out waiting for a response from the acquirer. |
| `PREMATURE_CHIP_CARD_REMOVAL` | Chip card was removed before the transaction completed. |
| `CHIP_CARD_DECLINES_TRANSACTION` | Chip card declined the transaction. |
| `SIGNATURE_TIMEOUT` | Signature capture timed out. |
| `MERCHANT_REVERSAL_SIGNATURE_DECLINED` | Merchant-initiated reversal; signature was declined. |
| `NO_REVERSAL_REASON_CODE` | No specific reason code applies. |

**Code example – full reversal (defaults)**

```json
{
"originalGuid": "0c9d9df0-48ec-11eb-81a1-470a19c80d3a"
}
```

**Code example – partial reversal**

```json
{
"originalGuid": "0c9d9df0-48ec-11eb-81a1-470a19c80d3a",
"amount": "15.00",
"currency": "EUR"
}
```

**Code example – with explicit reason code and timestamp**

```json
{
"originalGuid": "0c9d9df0-48ec-11eb-81a1-470a19c80d3a",
"messageReasonCode": "TIMEOUT_WAITING_FOR_RESPONSE",
"timestamp": "20240101120000000"
}
```

---

## Batch {#batch}

### BatchCloseRequest {#batchCloseRequest}
Expand Down
Loading