# Get started

Authenticate and send your first request to the cloud device API over the Unity Gateway.

## Step 1: Get your credentials

Before performing a transaction, obtain the following credentials:

- **HMAC key:** Used for authentication and to create the HMAC signature for each API request.
- **Merchant credentials:** Your merchant ID, site ID, and point-of-sale ID, as assigned by PXP.
- **API base URL:** The Unity Gateway base URL for your environment (sandbox or production).


### HMAC key

To find your HMAC key:

1. In the Unity Portal, go to **Merchant setup > Sites**.
2. Select a site.
3. In the **Services** tab, find the *Pos service* row.
4. Click **Edit**.
5. The HMAC key is displayed in the top left. Click the copy icon () to copy it to your clipboard.



### Merchant credentials

#### Merchant ID

To find your merchant ID:

1. In the Unity Portal, go to **Merchant setup > Merchants**.
2. Select a merchant.
3. In the *General information* tab, look for **Merchant ID**.


#### Site ID

To find your site ID:

1. In the Unity Portal, go to **Merchant setup > Sites**.
2. Select a site.
3. In the *General information* tab, look for **Site ID**.


#### Point-of-sale ID

Use the POS ID as the `merchantPointOfSaleId` path parameter and as `pointOfInteraction.pointOfSaleId` in the request body.

1. In the Unity Portal, go to **Merchant setup > Sites**.
2. Select a site.
3. In the **Services** tab, find the *Pos service* row.
4. Click **Edit**.
5. Select a device.
6. Click **General settings**.
7. In the *POS settings* section, look for **POS ID**.


### API base URL

Call the cloud device API on the Unity Gateway. Choose the URL for your environment:

| Environment | Base URL |
|  --- | --- |
| Sandbox | `https://api-services.test.pxp.io/api/v1` |
| Production | `https://api-services.pxp.io/api/v1` |


To initiate a transaction, append `/cloud-device/{merchantPointOfSaleId}/transactions`:

```
https://api-services.pxp.io/api/v1/cloud-device/{merchantPointOfSaleId}/transactions
```

For example:

```
https://api-services.pxp.io/api/v1/cloud-device/POS-001/transactions
```

To modify an existing transaction, use:

```
https://api-services.pxp.io/api/v1/cloud-device/{merchantPointOfSaleId}/transactions/{systemTransactionId}/modifications
```

Unlike the local POS+ API, you don't call the device IP address or port 8181. The gateway routes the request to the device identified by `merchantPointOfSaleId`.

## Step 2: Prepare your API request

With your credentials ready, prepare your API request payload. The following example shows an in-store purchase transaction:

```json
{
  "merchant": "{merchantId}",
  "site": "{siteId}",
  "pointOfInteraction": {
    "pointOfSaleId": "{posId}",
    "language": "EN",
    "storeAndForwardType": "None"
  },
  "merchantTransactionId": "{merchantTransactionId}",
  "merchantTransactionDate": "2025-11-04T12:00:00.000Z",
  "amounts": {
    "transaction": 100.00,
    "currencyCode": "USD"
  },
  "transactionMethod": {
    "entryType": "Instore",
    "fundingType": "Card",
    "intent": "Purchase"
  },
  "statusCallbackUrl": "https://example.com/statuspacket"
}
```

For full request and response examples by intent, see [Initiate POS transactions](/guides/point-of-sale/pos-plus/cloud/api/initiate-transactions).

## Step 3: Generate an HMAC signature

The cloud device API uses the same PXP-POS HMAC-SHA256 authentication as the local POS+ API.

For each API request, you need to:

1. Create a unique request ID (UUID or GUID).
2. Generate a timestamp (Unix timestamp in seconds).
3. Combine the timestamp, request ID, request path, and request body.
4. Use your HMAC key to create an HMAC-SHA256 signature.


### HMAC signature format

The signature is calculated using the following data:

```
{timestamp}{requestId}{requestPath}{requestBody}
```

Where:

* `{timestamp}` is the current Unix timestamp in seconds.
* `{requestId}` is a unique UUID for the request.
* `{requestPath}` is the API path without a leading slash (for example, `api/v1/cloud-device/POS-001/transactions`).
* `{requestBody}` is the JSON request body as a string.


### Implementation examples

```csharp C#
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;

namespace Pxp.Pos.Sdk.Utils
{
  public static class HttpRequestMessageExtensions
  {
    public static HttpRequestMessage BuildHMACAuthentication(
      this HttpRequestMessage request,
      string requestBody,
      string apiKey,
      string endpoint)
    {
      var uri = new Uri(endpoint);
      var requestPath = uri.AbsolutePath.Trim('/');
      var requestId = Guid.NewGuid().ToString();
      var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
      var hmacRequestData = $"{timestamp}{requestId}{requestPath}{requestBody}";
      var hmacResult = ComputeHmacSha256(hmacRequestData, apiKey);
      var authHeader = $"PXP-POS {timestamp}:{hmacResult}";

      request.Headers.Add("Authorization", authHeader);
      request.Headers.Add("X-Request-Id", requestId);

      return request;
    }

    private static string ComputeHmacSha256(string data, string key)
    {
      using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
      {
        var hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
        return BitConverter.ToString(hashBytes).Replace("-", "").ToUpper();
      }
    }
  }
}
```

```python Python
import hmac
import hashlib
import uuid
from datetime import datetime
from urllib.parse import urlparse

def build_hmac_authentication(request_body: str, api_key: str, endpoint: str) -> dict:
  """
  Builds HMAC authentication headers for the HTTP request.

  Args:
    request_body: The request body as JSON string
    api_key: The API key for HMAC signature
    endpoint: The full endpoint URL

  Returns:
    dict: Dictionary containing Authorization and X-Request-Id headers
  """
  # Extract the path from the endpoint URL
  request_path = urlparse(endpoint).path.strip('/')

  # Generate request ID using UUID
  request_id = str(uuid.uuid4())

  # Get current timestamp in seconds since epoch
  timestamp = str(int(datetime.utcnow().timestamp()))

  # Combine data for HMAC calculation
  hmac_request_data = f"{timestamp}{request_id}{request_path}{request_body}"

  # Create HMAC-SHA256 signature
  hmac_secret = api_key.encode('utf-8')
  mac = hmac.new(hmac_secret, hmac_request_data.encode('utf-8'), hashlib.sha256)
  hmac_result = mac.digest().hex().upper()

  # Create authorisation header
  auth_header = f"PXP-POS {timestamp}:{hmac_result}"

  # Return headers
  return {
    'Authorization': auth_header,
    'X-Request-Id': request_id
  }
```

```javascript JavaScript
const crypto = require('crypto');
const { URL } = require('url');

/**
 * Builds HMAC authentication headers and adds them to the request
 * @param {string} requestBody - The request body as JSON string
 * @param {string} apiKey - The API key for HMAC signature
 * @param {string} endpoint - The full endpoint URL
 * @returns {Object} Object containing Authorization and X-Request-Id headers
 */
function buildHMACAuthentication(requestBody, apiKey, endpoint) {
  // Extract the path from the endpoint URL
  const requestPath = new URL(endpoint).pathname.replace(/^\/+|\/+$/g, '');

  // Generate request ID using UUID
  const requestId = crypto.randomUUID();

  // Get current timestamp in seconds since epoch
  const timestamp = Math.floor(Date.now() / 1000).toString();

  // Combine data for HMAC calculation
  const hmacRequestData = `${timestamp}${requestId}${requestPath}${requestBody}`;

  // Create HMAC-SHA256 signature
  const hmacSecret = crypto.createHmac('sha256', apiKey);
  hmacSecret.update(hmacRequestData, 'utf8');

  const hmacResult = hmacSecret.digest('hex').toUpperCase();

  // Create authorisation header
  const authHeader = `PXP-POS ${timestamp}:${hmacResult}`;

  // Add headers to the request
  return {
    'Authorization': authHeader,
    'X-Request-Id': requestId
  };
}

module.exports = { buildHMACAuthentication };
```

## Step 4: Add HTTP headers

Include the HMAC signature and request ID in your HTTP headers:

| Header  | Description | Format  |
|  --- | --- | --- |
| `Authorization` | The HMAC signature, consisting of the authentication scheme (`PXP-POS`), timestamp, and HMAC value. | `PXP-POS {timestamp}:{hmac}` |
| `X-Request-Id` | The unique request ID (UUID) that you generated. | `{requestId}` |
| `Content-Type` | The media type of the request body. | `application/json` |


For example:

```
Authorization: PXP-POS 1699876543:A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6
X-Request-Id: 123e4567-e89b-12d3-a456-426614174000
Content-Type: application/json
```

## Step 5: Send the request and process the response

Send your API request to the cloud device URL with the prepared payload and headers.

On successful authorisation, you'll receive a `200` response similar to the following:

```json
{
  "state": "Authorised",
  "stateData": {
    "code": "CRD000",
    "message": "Approved"
  },
  "approvalCode": "A123456",
  "merchantTransactionId": "TXN-001",
  "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b",
  "merchantTransactionDate": "2025-01-27T08:51:02.826445+00:00",
  "providerTransactionId": "PROV-98765",
  "fundingData": {
    "maskedPrimaryAccountNumber": "************1234",
    "cardScheme": "Visa",
    "expiryMonth": "12",
    "expiryYear": "2025",
    "gatewayTokenId": "1ed768bb-e88a-4636-91ae-67927ccbb03a",
    "pointOfInteraction": {
      "entryType": "Instore"
    },
    "providerResponse": {
      "provider": "PXPFinancial",
      "code": "00",
      "message": "Approved",
      "merchantId": "77772182",
      "terminalId": "75836665",
      "paymentAccountReference": "V001ABCDEFGHIJKLMNOPQRSTUVWXY",
      "schemeTransactionId": "SCHEME-TXN-001",
      "issuerResponseCode": "00",
      "schemeTransactionLinkId": "LINK-001"
    }
  },
  "amounts": {
    "transaction": 30.32,
    "currencyCode": "EUR"
  }
}
```

### Response properties

| Property | Description |
|  --- | --- |
| `state`string (enum) | The current state of the transaction.Possible values:`Authorised``Captured``Cancelled``Error``Refused` |
| `stateData`object | Key value pair for various state data. |
| `stateData.code`string | The state details code. |
| `stateData.message`string | The state details message. |
| `approvalCode`string | A unique identifier code provided by the authorising entity, indicating approval or reference for the transaction. |
| `merchantTransactionDate`string (date-time) | The date and time when you initiated the transaction, in ISO 8601 format. |
| `merchantTransactionId`string | A unique transaction reference assigned by you. |
| `systemTransactionId`string | A unique identifier generated by PXP for each transaction. Use this value for captures, refunds, incremental authorisations, voids, and other modifications. |
| `providerTransactionId`string | A unique identifier assigned by the financial service provider for the transaction. |
| `fundingData`object | Card and provider details for the transaction, including the masked PAN, card scheme, `gatewayTokenId`, EMV data (when present), and `providerResponse`. |
| `amounts`object | Details about the transaction amounts, including optional gratuity or service charge. |
| `dccData`object | Details about Dynamic Currency Conversion (DCC) for the transaction. Only present when DCC is offered and processed. |


Store the `systemTransactionId` for future reference, reconciliation, and any follow-up operations such as capture, refund, or void. See [Initiate POS transactions](/guides/point-of-sale/pos-plus/cloud/api/initiate-transactions) for full response field details and webhook outcomes.