Skip to content
Open
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
17 changes: 17 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,20 @@ Follows Gitflow:
**Before merging a new SDK version to `main`**, always run the version-tagging command above first.

CI/CD is defined in `.github/workflows/deploy.yml`. The `setenv.sh` script is run as part of the deployment to switch URLs and `includeCurrentVersion` flags between environments.

### Merge method (important)

`dev` and `main` are long-lived branches that must share history. Use the right merge method per target:

| PR | Merge method | Why |
|----|--------------|-----|
| feature → `dev` | **Squash and merge** | Keeps `dev` history clean; the squash is harmless here. |
| `dev` → `main` | **Create a merge commit** (never squash) | Squashing creates a new commit on `main` that does not share history with `dev`'s individual commits, so every later `dev` → `main` comparison reports false conflicts. A merge commit keeps the histories connected. |

GitHub cannot restrict the merge method per target branch (the setting is repo-wide), so this is a manual discipline: when merging `dev` → `main`, always pick **"Create a merge commit"** from the green button dropdown.

If a `dev` → `main` PR was accidentally squashed and the next one shows phantom conflicts, fix it by branching off `main`, merging `dev` into it (`git merge -X theirs --no-ff origin/dev`), verifying the resulting tree matches `dev` (`git diff origin/dev HEAD` is empty), and opening that branch as a merge-commit PR to `main`. This reconnects the histories.

### Avoiding broken builds

The build runs with `onBrokenMarkdownLinks: 'throw'`, so a single unresolvable Markdown link fails the entire production deploy. Within an SDK docs plugin, **links must be relative to that plugin** — e.g. from `restapi/restendpoints.md` link to `restobjects.md#anchor`, not `restapi/restobjects.md#anchor` (the plugin prefix points outside the plugin and won't resolve). Run `yarn build` locally before opening a `dev` → `main` PR to catch these.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ npm run docusaurus docs:version:android "Android SDK 7.1013.0"
Automatically, it will create the new folder for this version (version-Android SDK 7.1011.0) in `android_versioned_docs`.

```console
npm run docusaurus docs:version:restapi "REST API 2.29.0"
npm run docusaurus docs:version:restapi "REST API 2.30.0"
```

**To see it published you will have to restart docusaurus.**
Expand Down
2 changes: 1 addition & 1 deletion android/androidtransactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1355,7 +1355,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ The **`tokenizedOperation`** method allows integrators to provide a specific ope

---

## Cloud Tokenized Payments Operations
## Cloud Tokenized Payments Operations{#cloudTokenizedPaymentsOperations}

`cloudTokenizedPaymentsOperations`

Expand Down
95 changes: 71 additions & 24 deletions restapi/restendpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ POST endpoint used to send a financial operation to the payment terminal. The tr
| **BadRequest DeviceIsBusy Error** | The response code 400 with error 1001 is received from the API if the payment terminal is already processing a transaction. |
| **BadRequest DeviceNotResponding Error** | The response code 400 with error 1002 is received from the API if the payment terminal is offline. |
| **BadRequest CancelOperationNotAllowed Error** | The response code 400 with error 1003 is received from the API if the stopCurrentTransaction operation cannot be executed. A transaction can only be cancelled at specific steps of the transaction, while waiting for the card to be inserted or on PIN screen. |
| **BadRequest NoTransactionToCancel Error** | The response code 400 with error 1005 is received from the API if the stopCurrentTransaction operation is attempted but there is no transaction currently in progress to cancel. |

**Code Example**

Expand Down Expand Up @@ -1384,13 +1385,16 @@ This endpoint allows to Cancel/Void/Reverse a previous transaction without a rea
| `Body: amount` <span class="badge badge--secondary">Optional</span> <br />*String* | Decimal amount in String, ISO 4217; Required for partial-reversals. *Only if your acquirer supports partial-reversals*. |
| `Body: currency` <span class="badge badge--secondary">Optional</span> <br />*String* | Required for partial-reversals *Only if your acquirer supports partial-reversals*. |
| `Body: messageReasonCode` <span class="badge badge--secondary">Optional</span> <br />*String* | default: CUSTOMER_CANCELLATION. See [allowed values](restobjects.md#messageReasonCode)|
| `Body: 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. |

**Returns**

| Response | Response Code |
| ----------- | ----------- |
| [DeferredTokenizationResponse](restobjects.md#deferredTokenizationResponse) | Response code 200. |
| **BadRequest** | Response code 400. Returned when the transaction type is not eligible for deferred tokenization. |
| Result | Notes |
| ------ | ----- |
| `200` | Reversal accepted and processed. Response body is a [ReversalResponse](restobjects.md#reversalResponse) object. |
| `400` | Business rule error from the gateway (for example, the transaction was already reversed, or a partial-reversal `amount` exceeds the original amount). Returned as `BadRequestError` with `error.code` and `error.details`. |
| `403` | Forbidden — the API key does not belong to a merchant. Partner keys are not accepted by this endpoint. |
| `422` | Payload validation error (`VALIDATION_FAILED`) — missing `originalGuid`, invalid `messageReasonCode` enum value, or invalid `currency` length. |

**Code Example**

Expand Down Expand Up @@ -1447,37 +1451,80 @@ curl --location --request POST 'https://cloud.handpoint.io/reversal' \

```json
{
"httpStatus": 200,
"acquirerTid": "ACQUIRER_TID",
"agreementNumber": "123456789010102",
"cardToken": "665630867",
"cardTokenizationGuid": "7df78050-21dc-11f1-991b-6f80eaf25911",
"expiryDateMMYY": "0927",
"httpStatus": "200",
"maskedCardNumber": "************3555",
"serverDateTime": "20260317083711509",
"transactionReference": "75413c40-21db-11f1-991b-6f80eaf25911"
"amount": "0.04",
"approvalCode": "123456",
"batchNumber": "123",
"cardTypeName": "Visa",
"currency": "USD",
"customFields": {
"entry": [
{
"key": "messageReasonCode",
"value": "4000"
},
{
"key": "tenderType",
"value": "Credit"
},
{
"key": "issuerResponseCode",
"value": "00"
}
]
},
"expiryDateMMYY": "1027",
"f25": "4000",
"issuerResponseCode": "00",
"issuerResponseText": "Successful",
"maskedCardNumber": "************0936",
"serverDateTime": "20260709074155101",
"terminalDateTime": "20260709074155083",
"transactionReference": "ee47c0b5-ff0b-4847-977c-cb8b6c4a848c",
"authorizationGuid": "9db20c30-7b69-11f1-9754-81955277651b",
"originalGuid": "9db20c30-7b69-11f1-9754-81955277651b",
"reversalGuid": "a8534cd0-7b69-11f1-a47e-6df6451d705a"
}
```

</TabItem>
<TabItem value="400" label="400">
<TabItem value="Already Reversed" label="Already Reversed">

```json
{
"error": {
"statusCode": 400,
"name": "BadRequestError",
"message": "Already reversed",
"code": "3051",
"details": {
"body": {
"error": {
"errorCode": "3112",
"errorGuid": "624d05e0-21dd-11f1-991b-6f80eaf25911",
"httpStatus": "403",
"reason": "Transaction type is not eligible for deferred tokenization"
}
},
"status": 403
},
"message": "Viscus operation failed",
"errorCode": "3051",
"errorGuid": "c267a170-7b69-11f1-9754-81955277651b",
"httpStatus": 409,
"reason": "Already reversed"
}
}
}
```

</TabItem>
<TabItem value="Exceeds original amount" label="Exceeds original amount">

```json
{
"error": {
"statusCode": 400,
"name": "BadRequestError",
"statusCode": 400
"message": "Partial reversal amount exceeds original amount",
"code": "4066",
"details": {
"errorCode": "4066",
"errorGuid": "e5197770-7b69-11f1-9754-81955277651b",
"httpStatus": 400,
"reason": "Partial reversal amount exceeds original amount"
}
}
}
```
Expand Down
81 changes: 78 additions & 3 deletions restapi/restobjects.md
Original file line number Diff line number Diff line change
Expand Up @@ -1052,11 +1052,11 @@ The exact shape is very similar across these operations; some fields (such as `o

## Reversal {#reversal}

### ViscusReversalRequest {#viscusReversalRequest}
### ReversalRequest {#reversalRequest}

`ViscusReversalRequest` <span class="badge badge--info">Object</span>
`ReversalRequest` <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.
Object used by the [`POST /v1/reversal`](restendpoints#reversal) endpoint to reverse any reversible transaction. Only `originalGuid` is required; all other fields are optional and default to sensible values when not provided.

**Properties**

Expand Down Expand Up @@ -1150,6 +1150,81 @@ curl --location --request POST 'https://cloud.handpoint.io/reversal' \

---

### ReversalResponse {#reversalResponse}

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

Object returned by [`POST /v1/reversal`](restendpoints#reversal) when the reversal is accepted and processed by the gateway.

**Properties**

| Property | Description |
| -------- | ----------- |
| `httpStatus` <br />*String* | HTTP status code as returned by the gateway (for example, `"200"`). |
| `acquirerTid` <br />*String* | Acquirer terminal identifier used to process the reversal. |
| `agreementNumber` <br />*String* | Merchant agreement number used for the reversal. |
| `amount` <br />*String* | Amount that was reversed, in major units. Matches the original transaction amount for a full reversal, or the requested `amount` for a partial reversal. |
| `approvalCode` <br />*String* | Approval code returned by the issuer for the reversal. |
| `batchNumber` <br />*String* | Batch number the reversal was recorded against, provided the acquirer returns it. |
| `cardTypeName` <br />*String* | Card brand of the reversed transaction (for example, `"Visa"`). |
| `currency` <br />*String* | ISO 4217 3-character currency code of the reversed amount. |
| `customFields` <br />*Object* | Additional gateway metadata for the reversal, returned as an `entry` array of `{key, value}` pairs (for example, the applied `messageReasonCode` and `tenderType`). |
| `expiryDateMMYY` <br />*String* | Card expiry date in `MMYY` format. |
| `f25` <br />*String* | ISO 8583 field 25 (POS condition code) returned by the acquirer. |
| `issuerResponseCode` <br />*String* | Issuer response code for the reversal (for example, `"00"` for approved). |
| `issuerResponseText` <br />*String* | Human-readable description of the issuer response (for example, `"Successful"`). |
| `maskedCardNumber` <br />*String* | Masked PAN of the reversed transaction. |
| `serverDateTime` <br />*String* | Gateway server timestamp (`YYYYMMDDHHmmssSSS`) when the reversal was processed. |
| `terminalDateTime` <br />*String* | Terminal timestamp (`YYYYMMDDHHmmssSSS`), echoed back from the request or generated by the gateway when not provided. |
| `transactionReference` <br />*String* | `transactionReference` of the original transaction, echoed back for reconciliation. |
| `authorizationGuid` <br />*String* | GUID of the original authorization/sale being reversed. |
| `originalGuid` <br />*String* | GUID of the transaction that was reversed. Mirrors the `originalGuid` from the request. |
| `reversalGuid` <br />*String* | Unique identifier generated by the gateway for this reversal operation. |

**Code example**

```json
{
"httpStatus": 200,
"acquirerTid": "ACQUIRER_TID",
"agreementNumber": "123456789010102",
"amount": "0.04",
"approvalCode": "123456",
"batchNumber": "123",
"cardTypeName": "Visa",
"currency": "USD",
"customFields": {
"entry": [
{
"key": "messageReasonCode",
"value": "4000"
},
{
"key": "tenderType",
"value": "Credit"
},
{
"key": "issuerResponseCode",
"value": "00"
}
]
},
"expiryDateMMYY": "1027",
"f25": "4000",
"issuerResponseCode": "00",
"issuerResponseText": "Successful",
"maskedCardNumber": "************0936",
"serverDateTime": "20260709074155101",
"terminalDateTime": "20260709074155083",
"transactionReference": "ee47c0b5-ff0b-4847-977c-cb8b6c4a848c",
"authorizationGuid": "9db20c30-7b69-11f1-9754-81955277651b",
"originalGuid": "9db20c30-7b69-11f1-9754-81955277651b",
"reversalGuid": "a8534cd0-7b69-11f1-a47e-6df6451d705a"
}
```

---

## Batch {#batch}

### BatchCloseRequest {#batchCloseRequest}
Expand Down
5 changes: 5 additions & 0 deletions restapi/restreleasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ id: restreleasenotes
Don’t miss any updates on our latest releases. Contact your Handpoint relationship manager to subscribe to the Handpoint Newsletter!
:::

## 2.29.0
**Features:**

New `NoTransactionToCancel` error (error code `1005`) is now returned from [`POST /transactions`](restendpoints.md#operation-requests) when a `stopCurrentTransaction` operation is attempted but there is no transaction currently in progress to cancel. Previously this case was reported as the generic `CancelOperationNotAllowed` error (`1003`).

## 2.27.0
**Features:**

Expand Down
Loading
Loading