# Full API Integration

Full API Integration is designed for partners who want to embed the full card issuing flow directly into their own system.

In this model, the partner does not use Sparados hosted mobile or web applications. Instead, the partner manages the end-user experience on its own side and communicates with Sparados APIs directly.

Full API Integration allows partners to:

- create users via API
- create cards via API
- manage card lifecycle
- retrieve and display card data, including PAN / CVV
- handle OTP and 3DS flows
- receive Apple Pay / Google Pay OTP notifications
- retrieve transactions and receive transaction notifications

This integration model gives the partner full control over the user and card flow, but may require PCI DSS compliance if sensitive card data is received, processed, stored, or displayed.

Before using Full API Integration, the partner must complete onboarding with Sparados, sign the cooperation agreement, and configure Mutual TLS authentication for the selected environment.

**API Endpoints**

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-api-integration-beta" style="height: 141px; width: 106.190476%;" width="100%"><thead><tr style="height: 29px;"><th style="height: 29px; width: 25.029797%;">**API**

</th><th style="height: 29px; width: 13.230036%;">**Integration**

</th><th style="height: 29px; width: 31.8236%;">**BETA**

</th><th style="height: 29px; width: 30.035757%;">**PROD**

</th></tr></thead><tbody><tr style="height: 67px;"><td style="height: 67px; width: 25.029797%;">Card, User, Card Data, 3DS and X-Pay Notifications API [(swagger)](https://sp-api.verestro.dev/docs?urls.primaryName=External "Swagger")

</td><td style="height: 67px; width: 13.230036%;">Simple / Full

</td><td style="height: 67px; width: 31.8236%;">`https://sp-api.secure-verestro.dev`

</td><td style="height: 67px; width: 30.035757%;">`https://sp-api.secure-verestro.com`

</td></tr><tr style="height: 45px;"><td style="height: 45px; width: 25.029797%;">Transaction API [(swagger)](https://developer.verestro.com/books/transaction-history-api/page/technical-documentation-thc-external-api "Swagger THC")

</td><td style="height: 45px; width: 13.230036%;">Simple / Full

</td><td style="height: 45px; width: 31.8236%;">`https://services.upaidtest.pl/thc`

</td><td style="height: 45px; width: 30.035757%;">`https://services.upaid.pl/thc`

</td></tr></tbody></table>

##### **1. SERVER-TO-SERVER SECURITY**

Communication between the partner and Sparados is secured using TLS certificates. The authentication method depends on the communication direction.

**Partner → Sparados APIs**

All requests sent by the partner to Sparados APIs require Mutual TLS (mTLS). The partner must configure the client certificate provided during onboarding. The same client certificate can be used across all mTLS-protected APIs unless agreed otherwise.

Instructions for generating and configuring the client certificate are available in the [Connecting Server-to-Server](https://developer.sparados.com/books/sparados-api-documentation/page/connecting-to-server-to-server-apis) section.

**Sparados → Partner Webhooks**

Webhook notifications, including Transaction API, 3DS OTP and Wallet notifications, are delivered over HTTPS. During the TLS handshake, Sparados presents its TLS server certificate. The partner system should validate the certificate before accepting the connection.

**Certificates**:  
• BETA – [ca\_beta.crt](https://developer.sparados.com/attachments/2)  
• PROD – [ca\_prod.crt](https://developer.sparados.com/attachments/1)

Certificates are environment-specific and may be renewed periodically. Partners should replace the certificate when a new one is provided by Sparados.

##### **2. HOW FULL API INTEGRATION WORKS**

Full API documentation is available here:

[Swagger Full API Documentation](https://sp-api.verestro.dev/docs?urls.primaryName=External)

In the Full API model, the partner creates the end user and card directly through API.  
The process starts with creating a user using:

`POST /secure/users/`

The partner must provide the required user details, including email, phone number, first name, last name, date of birth, and nationality. After the user is created, Sparados returns `id`, which should be stored as `userId`.

The partner then creates a card for this user using:

`POST /secure/cards/`

The partner provides the returned `userId` in the card creation request body, together with the `balanceId` of the balance from which the card should be funded and basic card details such as description and visual identifier.

Once the card has been created successfully, Sparados returns `cardId`.

If additional limits need to be assigned to the card, they should be added only after the card has been created, using:

`POST /secure/cards/{cardId}/limits`

After the additional limits are created successfully, Sparados returns `201 Created` with the created limit details. Once the card has been created successfully, Sparados returns cardId.

[![User and card Creation.png](https://developer.sparados.com/uploads/images/gallery/2026-06/scaled-1680-/user-and-card-creation.png)](https://developer.sparados.com/uploads/images/gallery/2026-06/user-and-card-creation.png)

**<span style="color: #000000;">  
</span>**

##### **3. VALUES USED IN SPARADOS CARDS API**

**Detailed Swagger documentation is available at the end of this document.**

This section describes common value formats used across Sparados Cards API.  
These rules apply when creating cards, defining card limits, setting validity periods, and managing card-related operations.

<span style="font-size: 11pt; font-family: Arial, sans-serif; color: #000000; background-color: transparent; font-weight: bold; font-style: normal; font-variant: normal; white-space-collapse: preserve;">Date format</span>

Sparados APIs use the ISO 8601 date and time format.

The expected format is:

```
YYYY-MM-DDTHH:mm:ss.SSSZ
```

Where:

- `T` separates the date from the time
- `Z` represents Zulu time / UTC time

Example:

```
2023-05-22T10:00:01.953Z
```

<span style="color: rgb(0, 0, 0); font-family: Arial, sans-serif; font-size: 11pt; font-style: normal; font-variant-caps: normal; font-weight: bold; white-space-collapse: preserve;">Minor values</span>

All numeric amount values used in Sparados Cards API are provided in minor units.  
For example, to assign a card with a limit of `100.50 EUR`, send:

```
10050
```

This applies to values such as:

- card budget
- additional limits
- budget increases
- budget decreases

<span style="font-size: 11pt; font-family: Arial, sans-serif; color: #000000; background-color: transparent; font-weight: bold; font-style: normal; font-variant: normal; white-space-collapse: preserve;">Currency</span>

Cards are created in the currency of the linked balance. The currency does not need to be provided separately when creating a card, because it is inherited from the selected linked balance.  
Each balance can have only one currency. Transactions may still be performed in other currencies, depending on the card configuration and transaction rules.

##### <span class="s1">**4. USER MANAGEMENT**</span>

In Full API Integration, the partner manages end users directly through API.

The user must be created before a card can be assigned to that user.

**User API Methods**

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-method-endpoint-desc" width="100%"><thead><tr><th>**Method**

</th><th>**Endpoint**

</th><th>**Description**

</th></tr></thead><tbody><tr><td>`POST`

</td><td>`/secure/users/`

</td><td>Creates a new end user.

</td></tr><tr><td>`GET`

</td><td>`/secure/users/`

</td><td>Retrieves the list of users.

</td></tr><tr><td>`GET`

</td><td>`/secure/users/{userId}`

</td><td>Retrieves details of a specific user.

</td></tr><tr><td>`PATCH`

</td><td>`/secure/users/{userId}`

</td><td>Updates selected user details.

</td></tr><tr><td>`DELETE`

</td><td>`/secure/users/{userId}`

</td><td>Deletes or deactivates the user, depending on the agreed configuration.

</td></tr></tbody></table>

**GET USERS**

To retrieve the list of users created for the partner, use:

`GET /secure/users/`

This endpoint returns users available under the partner configuration. The returned user `id` should be stored as `userId` and used when creating or managing cards assigned to this user.

Example response:

```json
[
  {
    "id": 123456,
    "email": "john.smith@example.com",
    "phoneNumber": "48123456789",
    "firstName": "John",
    "lastName": "Smith",
    "dateOfBirth": "1990-01-01",
    "nationality": "PL"
  }
]
```

**CREATE USER**

`POST /secure/users/`

Required fields:

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-field-type-descripti" width="100%"><thead><tr><th>**Field**

</th><th>**Type**

</th><th>**Description**

</th></tr></thead><tbody><tr><td>`email`

</td><td>`string`

</td><td>End user’s email address.

</td></tr><tr><td>`phoneNumber`

</td><td>`string`

</td><td>End user’s phone number.

</td></tr><tr><td>`firstName`

</td><td>`string`

</td><td>End user’s first name.

</td></tr><tr><td>`lastName`

</td><td>`string`

</td><td>End user’s last name.

</td></tr><tr><td>`dateOfBirth`

</td><td>`string`

</td><td>End user’s date of birth. Recommended format: `YYYY-MM-DD`.

</td></tr><tr><td>`nationality`

</td><td>`string`

</td><td>End user’s nationality. Recommended ISO country code, for example `PL`.

</td></tr></tbody></table>

Example request:

```json
{
  "email": "john.smith@example.com",
  "phoneNumber": "48123456789",
  "firstName": "John",
  "lastName": "Smith",
  "dateOfBirth": "1990-01-01",
  "nationality": "PL"
}
```

Example response:

```json
{
  "id": 123456
}
```

The returned `id` should be stored by the partner as `userId` and used when creating a card through `POST /secure/cards/`.

##### **5. CREATE CARD**

To issue a new virtual card for an existing user, use:

`POST /secure/cards/`

This endpoint issues a new virtual card linked to the selected balance and assigns it to the specified user.

The user must be created first through:

`POST /secure/users/`

After the user is created, Sparados returns `id`, which should be used as `userId` in the card creation request body.

The card is created directly using the selected `balanceId` and the assigned `userId`.

The partner can obtain the available `balanceId` values by calling:

`GET /secure/balances/`

The currency of the card depends on the selected `balanceId`. For example, if the card is linked to a EUR balance, the card currency will be EUR. If the card is linked to a PLN balance, the card currency will be PLN.

The `budgetMinor` field is optional. If it is not provided, the user can spend up to the amount available on the linked balance. If `budgetMinor` is provided, it defines the spending limit assigned to the card. A transaction is approved only if both the linked balance and the card budget are sufficient.

The `visualId` is provided by Sparados when a new card visual is created for the client. If it is not provided, the default card visual is used. Providing the correct visualId ensures that the card is displayed correctly in Apple Wallet and Google Wallet.

The `description` field is optional. It is displayed in the Sparados webview when the partner uses it to present card details, but the partner may also use this field to store its own card description or reference.

The response from `POST /secure/cards/` may take approximately 1–2 seconds, because Sparados creates the card, assigns it to the user, and configures the card balance before returning the response.

Once the response is returned, the card is already created and ready to use. Sparados returns the created card data, including `cardId`. The partner should store this value, as it is required for later card management, card data retrieval, and adding additional limits to the card.

Request body example:

```json
{
  "balanceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "userId": 0,
  "budgetMinor": 0,
  "description": "string",
  "visualId": 0
}

```

Request body fields:

<table id="bkmrk-field-type-descripti-1" style="width: 100%;"><thead><tr><th style="width: 12.514331%;">Field</th><th style="width: 7.867075%;">Type</th><th style="width: 79.618594%;">Description</th></tr></thead><tbody><tr><td style="width: 12.514331%;">`balanceId*`</td><td style="width: 7.867075%;">string, uuid</td><td style="width: 79.618594%;">UUID of the balance the card will be funded from. The partner can obtain this value by calling `GET /secure/balances/`. The card currency depends on the selected balance.</td></tr><tr><td style="width: 12.514331%;">`userId*`</td><td style="width: 7.867075%;">integer</td><td style="width: 79.618594%;">ID of the user the card will be assigned to. This value is returned by `POST /secure/users/`.</td></tr><tr><td style="width: 12.514331%;">`budgetMinor`</td><td style="width: 7.867075%;">integer</td><td style="width: 79.618594%;">Optional spending limit assigned to the card, expressed in minor currency units, for example `10000` = `100.00 PLN`. If this field is not provided, the card may spend up to the amount available on the linked balance. If provided, both the linked balance and the card budget must be sufficient for the transaction to be approved.</td></tr><tr><td style="width: 12.514331%;">`description`</td><td style="width: 7.867075%;">string</td><td style="width: 79.618594%;">Optional card description. It is displayed in the Sparados webview and may also be used by the partner to store its own card description or reference.</td></tr><tr><td style="width: 12.514331%;">`visualId`</td><td style="width: 7.867075%;">integer</td><td style="width: 79.618594%;">Card visual identifier provided by Sparados when a new card visual is created for the client. If not provided, the default card visual will be used. This value is required for correct card display in Apple Wallet and Google Wallet.</td></tr></tbody></table>

Additional properties are not processed by the API.

Example response:

```json
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "balanceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "userId": 0,
  "budgetMinor": 0,
  "description": "string",
  "visualId": 0
}

```

##### **CARD BUDGET**

A card budget defines how much can be spent using a specific card. It is independent from the linked balance, which represents the actual funds available on the payment account.

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-field-meaning-budget" width="100%"><thead><tr><th style="width: 18.002299%;">Field</th><th style="width: 81.997701%;">Meaning</th></tr></thead><tbody><tr><td style="width: 18.002299%;">`budgetMinor`</td><td style="width: 81.997701%;">Spending limit assigned to the card. This value defines the maximum amount that can be spent using the card.</td></tr><tr><td style="width: 18.002299%;">`balanceMinor`</td><td style="width: 81.997701%;">Available amount remaining from the card budget. This value decreases after successful transactions.</td></tr></tbody></table>

Example:

```json
Initial budget:
budgetMinor  = 100000 (1,000.00 EUR)
balanceMinor = 100000 (1,000.00 EUR)

After spending 250.00 EUR:
budgetMinor  = 100000
balanceMinor = 75000
```

Card budget and additional card limits are independent mechanisms. The card budget defines how much can be spent by the card, while additional card limits define how, where, and how often the card may be used, for example ATM withdrawals, e-commerce transactions, MCC restrictions, merchant restrictions, or transaction count limits. Both validations are performed during transaction authorization.

##### **ADJUSTING CARD BUDGET**

To adjust the card budget, use:

`PATCH /secure/cards/{id}/budget`

This endpoint changes the card budget by the value provided in `adjustmentAmountMinor`. A positive value, or a value without the `+` sign, increases the card budget. A negative value decreases the card budget.

Request body fields:

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-field-type-descripti-2" width="100%"><thead><tr><th style="width: 33.373063%;">Field</th><th style="width: 8.70126%;">Type</th><th style="width: 57.925677%;">Description</th></tr></thead><tbody><tr><td style="width: 33.373063%;">`adjustmentAmountMinor*`</td><td style="width: 8.70126%;">integer</td><td style="width: 57.925677%;">Amount by which the card budget should be adjusted. The value is expressed in minor currency units. Positive values increase the card budget. Negative values decrease the card budget.</td></tr></tbody></table>

Examples:

```json
{
  "adjustmentAmountMinor": 10000
}
```

This increases the card budget by 100.00 EUR.

```json
{
  "adjustmentAmountMinor": -5000
}
```

This decreases the card budget by 50.00 EUR.

This endpoint does not add funds to the linked balance and does not change the payment account balance. The card must already have a budget configured. Otherwise, the API returns `HTTP 409 Conflict`.

##### **RESETTING CARD BUDGET**

To reset the card budget, use:

`POST /secure/cards/{id}/budget/reset`

This endpoint recreates the existing budget and resets the spent amount, making the full budget available again.

Request body fields:

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-field-type-descripti-3" width="100%"><thead><tr><th style="width: 22.288439%;">Field</th><th style="width: 13.232306%;">Type</th><th style="width: 64.479255%;">Description</th></tr></thead><tbody><tr><td style="width: 22.288439%;">`newBudgetMinor`</td><td style="width: 13.232306%;">integer</td><td style="width: 64.479255%;">Optional. If provided, the budget is recreated using the new value and the full amount becomes available again. If omitted, the existing budget value is reused and the available amount is reset to the current budget.</td></tr></tbody></table>

The card must already have a budget configured. Otherwise, the API returns `HTTP 409 Conflict`.

##### <span class="s1">**6. CHECKING ACCOUNT BALANCE**</span>

To check the balance of the payment account connected with issued cards, use:

`GET /secure/balances/{balanceId}`

This method returns the current balance of the payment account linked to issued cards. This is the actual account balance, not the card budget.

The `balanceId` required for this method is provided by Sparados after the payment account is created for the partner.

##### **7. ADDITIONAL CARD SPENDING LIMITS**

After the card has been created, additional card limits can be assigned using:

`POST /secure/cards/{id}/limits`

This endpoint adds one limit to an existing card. Additional limits should be added only after the card has been successfully created and is ready to use. Each `POST /secure/cards/{id}/limits` request adds a single additional limit. Editing and deleting limits are also performed one by one. Only the `GET` method returns a list of limits assigned to the card.

All `amountMinor` values are provided in minor currency units, for example `10000` = `100.00 PLN`. Amount-based limits are cumulative, not per-transaction limits. Each successful transaction reduces the remaining amount available until the applicable limit period resets or the limit is removed.

##### **REQUEST BODY FIELDS**

<table id="bkmrk-field-type-descripti-5" style="width: 100%; height: 267px;"><thead><tr style="height: 29px;"><th style="width: 15.016034%; height: 29px;">Field</th><th style="width: 10.96728%; height: 29px;">Type</th><th style="width: 74.016687%; height: 29px;">Description</th></tr></thead><tbody><tr style="height: 29px;"><td style="width: 15.016034%; height: 29px;">`type`</td><td style="width: 10.96728%; height: 29px;">string</td><td style="width: 74.016687%; height: 29px;">Type of the card limit.</td></tr><tr style="height: 45px;"><td style="width: 15.016034%; height: 45px;">`amountMinor`</td><td style="width: 10.96728%; height: 45px;">integer</td><td style="width: 74.016687%; height: 45px;">Amount limit in minor currency units, for example `10000` = `100.00 PLN`. Used for amount-based limits.</td></tr><tr style="height: 45px;"><td style="width: 15.016034%; height: 45px;">`maxAttempts`</td><td style="width: 10.96728%; height: 45px;">integer</td><td style="width: 74.016687%; height: 45px;">Maximum number of transactions allowed within the selected period. Used for quantity-based limits.</td></tr><tr style="height: 29px;"><td style="width: 15.016034%; height: 29px;">`period`</td><td style="width: 10.96728%; height: 29px;">string</td><td style="width: 74.016687%; height: 29px;">Limit period. Available values: `DAILY`, `WEEKLY`, `MONTHLY`.</td></tr><tr style="height: 45px;"><td style="width: 15.016034%; height: 45px;">`mccList`</td><td style="width: 10.96728%; height: 45px;">array of strings</td><td style="width: 74.016687%; height: 45px;">List of merchant category codes used for MCC whitelist or blacklist limits.</td></tr><tr style="height: 45px;"><td style="width: 15.016034%; height: 45px;">`merchantIdList`</td><td style="width: 10.96728%; height: 45px;">array of strings</td><td style="width: 74.016687%; height: 45px;">List of merchant IDs used for merchant whitelist or blacklist limits.</td></tr></tbody></table>

##### **SUPPORTED LIMIT TYPES**

`TRX_ALL` — cap on all transactions combined.

```json
{
  "type": "TRX_ALL",
  "amountMinor": 50000,
  "maxAttempts": 10,
  "period": "MONTHLY"
}

```

`TRX_E_COM` — cap on e-commerce transactions only.

```json
{
  "type": "TRX_E_COM",
  "amountMinor": 10000,
  "maxAttempts": 5,
  "period": "DAILY"
}

```

`TRX_ATM` — cap on ATM withdrawals.

```json
{
  "type": "TRX_ATM",
  "amountMinor": 30000,
  "maxAttempts": 2,
  "period": "WEEKLY"
}

```

`FOREIGN_AMOUNT` — cap on the total amount spent in a foreign currency.

```json
{
  "type": "FOREIGN_AMOUNT",
  "amountMinor": 20000,
  "period": "MONTHLY"
}

```

`FOREIGN_QUANTITY` — cap on the number of foreign-currency transactions.

```json
{
  "type": "FOREIGN_QUANTITY",
  "maxAttempts": 3,
  "period": "DAILY"
}

```

`QUANTITY` — cap on total transaction count regardless of transaction type.

```json
{
  "type": "QUANTITY",
  "maxAttempts": 100,
  "period": "DAILY"
}

```

`AMOUNT_PLN` — cap on PLN-denominated spend.

```json
{
  "type": "AMOUNT_PLN",
  "amountMinor": 50000,
  "period": "WEEKLY"
}

```

`AMOUNT_EUR` — cap on EUR-denominated spend.

```json
{
  "type": "AMOUNT_EUR",
  "amountMinor": 20000,
  "period": "MONTHLY"
}

```

`MCC_BLACKLIST` — blocks transactions at terminals with the given merchant category codes.

```json
{
  "type": "MCC_BLACKLIST",
  "mccList": ["5812", "5813"]
}

```

`MCC_WHITELIST` — allows transactions only at terminals with the given merchant category codes.

```json
{
  "type": "MCC_WHITELIST",
  "mccList": ["5812"]
}

```

`MERCHANT_ID_BLACKLIST` — blocks transactions at specific merchants.

```json
{
  "type": "MERCHANT_ID_BLACKLIST",
  "merchantIdList": ["9AF3C2B1D4E5"]
}

```

`MERCHANT_ID_WHITELIST` — allows transactions only at specific merchants.

```json
{
  "type": "MERCHANT_ID_WHITELIST",
  "merchantIdList": ["9AF3C2B1D4E5"]
}

```

##### **RESPONSE**

After the limit has been created successfully, the API returns `201 Created` with the created limit details.

Example response:

```json
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "type": "TRX_ALL",
  "amountMinor": 0,
  "maxAttempts": 0,
  "period": "DAILY",
  "mccList": [
    "string"
  ],
  "merchantIdList": [
    "string"
  ]
}

```

The returned `id` is the limit ID. The partner should store this value if the limit may need to be edited or removed later. The same limit ID can also be retrieved using the `GET` method that returns the list of limits assigned to the card.

##### **MULTIPLE AND OVERLAPPING LIMITS**

The API allows multiple limits of the same type, including limits with the same period. All applicable limits are checked for each transaction, so the most restrictive limit is effectively enforced. For example, if a card has two weekly `TRX_ATM` limits of `100 EUR` and `50 EUR`, the effective weekly ATM limit is `50 EUR`.

The API validates conflicts between whitelists and blacklists because these rules are mutually exclusive. `MCC_WHITELIST` and `MCC_BLACKLIST` cannot be active at the same time, and the same rule applies to `MERCHANT_ID_WHITELIST` and `MERCHANT_ID_BLACKLIST`.

##### **GETTING, EDITING AND DELETING CARD LIMITS**

If the partner wants to edit an existing limit, the partner must use the limit ID in the `PATCH` method. This limit ID is returned when the limit is created using `POST /secure/cards/{id}/limits`. It can also be retrieved by calling the `GET` method that returns the list of limits assigned to the card. To change an existing limit, the partner should either edit the existing limit using its limit ID or remove the existing limit first and then add a new one.

The difference is how accumulated usage counters are handled. If the existing limit is edited, the current usage counter is preserved. If the limit is removed and a new limit is created, the accumulated usage counter associated with the removed limit is not carried over to the new limit

For example, if the card has a `TRX_ATM` limit of `100 EUR` and the user has already spent `20 EUR`, then increasing the existing limit to `200 EUR` means the user will still have `180 EUR` available under this limit. However, if the partner removes the existing `TRX_ATM` limit and then adds a new `TRX_ATM` limit of `200 EUR`, the accumulated usage counter is reset and the user will have the full `200 EUR` available under the new limit.

Recommended approach:

If the partner wants to change the limit value while preserving accumulated usage, the existing limit should be edited using its limit ID. If the partner wants to reset accumulated usage, the existing limit should be removed and a new limit should be created.  
Although the API allows multiple limits of the same type, removing or editing the existing limit before adding its replacement is recommended to avoid overlapping limits and unclear card configuration.

##### <span class="s1">**8. CARD DATA RETRIEVAL**</span>

To retrieve encrypted card details, use:

`GET /secure/cards/{id}/sensitive`

This endpoint returns sensitive card data, including PAN and CVV, in encrypted form.

The `{id}` parameter is the `cardId` returned by `POST /secure/cards/`

**Encryption**

Card details are always returned as a JWE token.

To decrypt the response, the partner must provide an RSA public key with each request.

The card data is encrypted using the provided public key. Only the holder of the matching private key can decrypt the response.

**Requirements**

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-requirement-descript" width="100%"><thead><tr><th>**Requirement**

</th><th>**Description**

</th></tr></thead><tbody><tr><td>RSA key pair

</td><td>Minimum key size: `2048-bit`<span class="s1">.</span>

</td></tr><tr><td>Public key format

</td><td>Base64-encoded SPKI PEM.

</td></tr><tr><td>Request header

</td><td>Public key must be sent in the `Public-Key` header.

</td></tr><tr><td>Response format

</td><td>API returns encrypted payload as a JWE compact token.

</td></tr><tr><td>Encryption algorithm

</td><td>`RSA-OAEP-256 + A256GCM`<span class="s2">.</span>

</td></tr></tbody></table>

**Request Header**

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-header-value-public-" width="100%"><thead><tr><th>**Header**

</th><th>**Value**

</th></tr></thead><tbody><tr><td>`Public-Key`

</td><td>Base64-encoded RSA public key in SPKI PEM format.

</td></tr></tbody></table>

**Response Format**

```json
{
  "payload": "<JWE compact token>"
}
```

**Decrypted Payload Example**

After decrypting the JWE token, the payload contains card details:

```json
{
  "id": 123,
  "type": "VIRTUAL",
  "cardNo": "5414599451242598",
  "cvv": "111",
  "exp": "2031-05-31",
  "issuerCardId": "1111111111111111",
  "dcCorporationId": "7f846a2f-92b4-4094-a776-35cf3753ef51",
  "balanceId": "67716ba1-081b-4919-8aae-9fdbee10be23"
}
```

**Recommended Security Flow**

If card data should be visible only to the end user, the key pair should be generated on the frontend side.

Recommended flow:

1. The frontend generates a temporary RSA key pair.
2. The frontend keeps the private key locally, for example in the user session.
3. The frontend sends only the public key to the partner backend.
4. The partner backend forwards the public key to Sparados API in the `Public-Key` header.
5. Sparados returns encrypted card data as a JWE token.
6. The encrypted payload is forwarded back to the frontend.
7. The frontend decrypts the payload using the private key.
8. PAN and CVV are displayed only to the end user.

**Security Note**

Never send the private key to Sparados API or to the partner backend if the decrypted card data should be accessible only to the end user. Only the public key should be sent in the request header.

Accessing, processing, storing, or displaying PAN / CVV may require PCI DSS compliance.

##### <span class="s1">**9. SPARADOS TRANSACTION API**</span>

Sparados Transaction History API allows partners to retrieve transaction history and receive transaction notifications.

The API consists of two parts:

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-type-description-inb" width="100%"><thead><tr><th>**Type**

</th><th>**Description**

</th></tr></thead><tbody><tr><td>Inbound API

</td><td>API methods called by the partner to retrieve transaction data from Sparados.

</td></tr><tr><td>Outbound API

</td><td>Webhook notifications sent by Sparados to the partner system when transaction events occur.

</td></tr></tbody></table>

Transaction API documentation is available here:

[`https://developer.verestro.com/books/transaction-history-api/page/technical-documentation-thc-external-api`](https://developer.verestro.com/books/transaction-history-api/page/technical-documentation-thc-external-api)

**Authentication**

Authentication and certificate requirements are described in the **Server-to-Server Security section**. Inbound API requests require Mutual TLS (mTLS). Outbound webhook notifications are delivered over HTTPS using the Sparados TLS server certificate.

**Backward Compatibility**

Future API changes will be backward compatible. The following changes may be introduced without breaking compatibility:

1. adding a new endpoint
2. adding a new optional request parameter
3. adding a new optional response field
4. adding a new enum value
5. relaxing validation rules for an existing parameter, for example making it optional
6. The partner system should ignore unknown fields and unknown enum values received in API responses.

**Outbound Retry Strategy**

If an outbound webhook call fails because of a timeout, connection issue, or HTTP `5xx` response, Sparados will retry the call automatically.

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-retry-stage-descript" width="100%"><thead><tr><th>**Retry stage**

</th><th>**Description**

</th></tr></thead><tbody><tr><td>Initial retries

</td><td>3 retries with up to 5 seconds between each attempt.

</td></tr><tr><td>Extended retries

</td><td>If the call still fails, Sparados performs 3 additional retries after 15 minutes, 30 minutes, and 2 hours.

</td></tr><tr><td>Final result

</td><td>If all retries fail, the webhook call is dismissed.

</td></tr></tbody></table>

The partner endpoint should return a successful HTTP `2xx` response after receiving and processing the notification. Webhook delivery should be treated as at-least-once, so the partner should process webhook notifications idempotently.

##### <span class="s1">**10. OTP AND WALLET NOTIFICATION WEBHOOKS**</span>

In Full API Integration, Sparados can send OTP and wallet-related notifications to endpoints provided by the partner.

The partner must provide Sparados with the full webhook URLs that should be used for notification delivery.

Webhook notifications are delivered over HTTPS using the Sparados TLS server certificate. Authentication and certificate requirements are described in the **Server-to-Server Security section**.

The partner endpoint should return:

`204 No Content`

to confirm that the notification was received successfully.

**3DS OTP Notification**

This webhook is triggered when a 3DS OTP is generated for a card in your corporation.

**Endpoint**

`POST {3ds_otp_notification_url}`

The full endpoint URL is provided by the partner during integration setup.

**Request Body**

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-field-type-descripti-6" width="100%"><thead><tr><th>**Field**

</th><th>**Type**

</th><th>**Description**

</th></tr></thead><tbody><tr><td>`balanceId`

</td><td>`string`

</td><td>Balance ID related to the card.

</td></tr><tr><td>`currency`

</td><td>`string`

</td><td>Transaction currency.

</td></tr><tr><td>`merchantName`

</td><td>`string`

</td><td>Merchant name for the transaction.

</td></tr><tr><td>`otp`

</td><td>`string`

</td><td>3DS one-time password generated for the transaction.

</td></tr><tr><td>`cardId`

</td><td>`integer`

</td><td>Card ID.

</td></tr><tr><td>`userId`

</td><td>`integer`

</td><td>User ID assigned to the card.

</td></tr><tr><td>`amountMinor`

</td><td>`integer`

</td><td>Transaction amount in minor units.

</td></tr><tr><td>`cardLast4Digits`

</td><td>`string`

</td><td>Last 4 digits of the card number.

</td></tr></tbody></table>

**Example Request Body**

```json
{
  "balanceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "currency": "EUR",
  "merchantName": "Example Merchant",
  "otp": "123456",
  "cardId": 123,
  "userId": 456,
  "amountMinor": 1000,
  "cardLast4Digits": "2598"
}
```

**Expected Response**

`204 No Content`

**Wallet Notifications**

This webhook is triggered when a wallet notification event occurs for a card in your corporation.

It is used for Apple Pay / Google Pay related events, including activation code delivery and token status updates.

**Endpoint**

`POST {wallet_notifications_url}`

The full endpoint URL is provided by the partner during integration setup.

**Message Types**

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-messagetype-descript" width="100%"><thead><tr><th>`messageType`

</th><th>**Description**

</th></tr></thead><tbody><tr><td>`ACTIVATION_CODE_DELIVERY`

</td><td>Wallet activation code should be delivered to the end user.

</td></tr><tr><td>`TOKEN_ACTIVATED`

</td><td>Wallet token has been activated.

</td></tr><tr><td>`CARD_REMOVED_BY_CUSTOMER`

</td><td>Card has been removed from the wallet by the customer.

</td></tr><tr><td>`CARD_REMOVED_BY_ISSUER`

</td><td>Card has been removed from the wallet by the issuer.

</td></tr></tbody></table>

**Request Body**

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-field-type-descripti-7" width="100%"><thead><tr><th>**Field**

</th><th>**Type**

</th><th>**Description**

</th></tr></thead><tbody><tr><td>`cardLast4Digits`

</td><td>`string`

</td><td>Last 4 digits of the card number.

</td></tr><tr><td>`tokenRequestorType`

</td><td>`string`

</td><td>Wallet provider / token requestor type.

</td></tr><tr><td>`messageType`

</td><td>`string`

</td><td>Wallet notification type.

</td></tr><tr><td>`activationMethodType`

</td><td>`string`

</td><td>Activation method type. Present only for `ACTIVATION_CODE_DELIVERY`.

</td></tr><tr><td>`activationMethodValue`

</td><td>`string`

</td><td>Activation method value. Present only for `ACTIVATION_CODE_DELIVERY`.

</td></tr><tr><td>`activationCode`

</td><td>`string`

</td><td>Wallet activation code. Present only for `ACTIVATION_CODE_DELIVERY`.

</td></tr><tr><td>`formFactor`

</td><td>`string`

</td><td>Device or wallet form factor.

</td></tr><tr><td>`cardId`

</td><td>`integer`

</td><td>Card ID.

</td></tr></tbody></table>

**Example Request Body**

```json
{
  "cardLast4Digits": "2598",
  "tokenRequestorType": "APPLE_PAY",
  "messageType": "ACTIVATION_CODE_DELIVERY",
  "activationMethodType": "SMS",
  "activationMethodValue": "48123456789",
  "activationCode": "123456",
  "formFactor": "PHONE",
  "cardId": 123
}
```

**Expected Response**

`204 No Content`

**Important**

The fields `activationCode`<span class="s2">, </span>`activationMethodType`<span class="s2">, and </span>`activationMethodValue`<span class="s2"> are present only when </span>`messageType`<span class="s2"> is:</span>

`ACTIVATION_CODE_DELIVERY`

##### <span class="s1">**11. API SWAGGER DOCUMENTATION**</span>

Detailed API documentation is available here:

<table border="1" cellpadding="8" cellspacing="0" id="bkmrk-api-documentation-li" style="height: 164px;" width="100%"><thead><tr style="height: 29px;"><th style="height: 29px;">**API**

</th><th style="height: 29px;">**Documentation link**

</th></tr></thead><tbody><tr style="height: 45px;"><td style="height: 45px;">Full API Swagger

</td><td style="height: 45px;">`https://sp-api.verestro.dev/docs?urls.primaryName=External`

</td></tr><tr style="height: 29px;"><td style="height: 29px;">Cards API Swagger

</td><td style="height: 29px;">`https://sparados-bc-api.upaidtest.pl/api-secure.yaml`

</td></tr><tr style="height: 61px;"><td style="height: 61px;">Transaction API Documentation

</td><td style="height: 61px;">`https://developer.verestro.com/books/transaction-history-api/page/technical-documentation-thc-external-api`

</td></tr></tbody></table>

Use the Swagger documentation as the source of detailed endpoint schemas, request parameters, response formats, and available enum values.