APIGiftCardController
Technical reference for the Scanfie Gift Card REST API
Overview
The APIGiftCardController exposes a JSON REST API that allows external systems to query, redeem
and roll back gift cards. It is intended for integrations such as a POS system or an external payment
terminal that needs to process Scanfie gift cards.
All three endpoints follow the same flow:
- Authenticate the caller using an API key and secret
- Validate the request body (required fields, amounts, CVC)
- Execute the mutation on the gift card wallet
- Return a JSON response (always HTTP 200 — errors are returned inside the body)
Authentication
Every request must include two HTTP headers:
| Header | Description |
|---|---|
X-API-key | The API key identifier |
X-API-secret | The corresponding secret |
The AbstractAPIController.authenticateRequest() method validates the key pair via
APIKey.calculateAuthenticatedKey(key, secret). If the key is valid, the associated
Company is set as the contextual company for the remainder of the request.
If the key is invalid, an error is returned immediately without further processing.
Response Envelope
All responses are wrapped in an APICallResponseWrapper.
The HTTP status code is always 200 OK — the caller must inspect the
errors list to determine whether the call succeeded.
// Success example
{
"valid": true,
"response": {
"errors": [],
// ...fields specific to each endpoint...
}
}
// Failure example
{
"valid": false,
"response": {
"errors": [
{ "field": "json", "message": "Giftcard not found" }
]
}
}
Endpoints
Retrieves the balance and validity of a gift card based on its external ID and CVC code.
This endpoint does not mutate anything — it is purely informational.
Use the returned internalId in subsequent /redeem calls.
Request body
{
"giftCardId": "SCAN-12345",
"giftCardCVC": "A1B2"
}
| Field | Type | Required | Description |
|---|---|---|---|
giftCardId | String |
Required | The external ID of the gift card (CompanyGiftCard.externalId) |
giftCardCVC | String |
Required | The CVC security code of the card |
Validation steps (in order)
giftCardIdmust not be empty- An active company context must exist
- The gift card must exist (
CompanyGiftCard.getByExternalId) giftCardCVCmust not be empty- CVC must match
giftCard.calculateCVCCode() - The gift card must not be expired (
giftCard.isExpired())
Response fields
{
"internalId": "550e8400-e29b-41d4-a716-446655440000",
"balance": 25.00,
"redeemable": true,
"errors": []
}
| Field | Type | Description |
|---|---|---|
internalId | String | Internal UUID of the gift card — pass this to /redeem |
balance | Double | Currently available balance in euros |
redeemable | Boolean | false if there are errors or no wallet is linked |
DirectPayment record is created and the wallet
balance is reduced. Store the returned associatedTransactionId — it is required
to perform a rollback.
Deducts an amount from the gift card wallet via Wallet.reductionViaPayment().
Request body
{
"giftCardInternalId": "550e8400-e29b-41d4-a716-446655440000",
"giftCardCVC": "A1B2",
"amountToRedeem": 15.00
}
| Field | Type | Required | Description |
|---|---|---|---|
giftCardInternalId | String |
Required | Internal UUID of the gift card (obtained via /query) |
giftCardCVC | String |
Required | CVC security code of the card |
amountToRedeem | Double |
Required | Amount to deduct in euros — must be > 0 |
Validation steps (in order)
giftCardInternalIdmust not be emptyamountToRedeemmust not benullor ≤ 0- An active company context must exist
- The gift card must exist (
CompanyGiftCard.getByInternalId) giftCardInternalIdmust match the ID of the found card- CVC must match
giftCard.calculateCVCCode() - The gift card must not be expired
- Sufficient balance must be available (
Wallet.canDeductAmount) - A
WalletPaymentMethodof typeGIFTCARDmust exist for the company
Processing
A new DirectPayment object is created and persisted with the following values:
| Field | Value |
|---|---|
status | SUCCESSFUL |
referenceId | giftCard.id |
amount | amountToRedeem |
selectedPaymentMethod | walletPaymentMethod (type GIFTCARD) |
dtPaid | now() |
giftCard | the resolved CompanyGiftCard |
turnoverRegistrationGroup | default gift card reservation group |
The wallet is then reduced via Wallet.reductionViaPayment(payment).
Response fields
{
"associatedTransactionId": "7f3e9a12-0c1d-4e2b-b8f0-123456789abc",
"redeemedAmount": 15.00,
"balanceAfterRedeem": 10.00,
"errors": []
}
| Field | Type | Description |
|---|---|---|
associatedTransactionId | String | UUID of the created DirectPayment — store this for rollback |
redeemedAmount | Double | Amount actually redeemed |
balanceAfterRedeem | Double | Balance after redemption |
SUCCESSFUL and
has not already been rolled back or cancelled.
Reverses a previously executed redemption. The DirectPayment is set to
REFUNDED and the balance is restored via Wallet.rollbackViaPayment().
Request body
{
"transactionId": "7f3e9a12-0c1d-4e2b-b8f0-123456789abc",
"giftCardInternalId": "550e8400-e29b-41d4-a716-446655440000"
}
| Field | Type | Required | Description |
|---|---|---|---|
transactionId | String |
Required | The associatedTransactionId from the /redeem response |
giftCardInternalId | String |
Required | Internal UUID of the gift card |
Validation steps (in order)
transactionIdmust not be emptygiftCardInternalIdmust not be empty- An active company context must exist
- The
DirectPaymentmust exist (BaseDao.getById) - The gift card must exist (
CompanyGiftCard.getByInternalId) DirectPayment.giftCardmust match the provided gift card- The transaction must not already be
REFUNDED - The transaction must not already be
CANCELLED - The transaction must have status
PAID(=SUCCESSFUL)
Processing
The DirectPayment is updated with the following values:
| Field | Value |
|---|---|
status | REFUNDED |
dtRefunded | now() |
dtCancelled | null |
The wallet balance is then restored via Wallet.rollbackViaPayment(payment).
Response fields
{
"associatedTransactionId": "7f3e9a12-0c1d-4e2b-b8f0-123456789abc",
"rollbackAmount": 15.00,
"balanceAfterRollback": 25.00,
"errors": []
}
| Field | Type | Description |
|---|---|---|
associatedTransactionId | String | UUID of the rolled-back DirectPayment |
rollbackAmount | Double | Amount reversed (= payment.amount) |
balanceAfterRollback | Double | Balance after rollback |
Recommended Integration Flow
Error Codes
All errors are returned as an array in response.errors, each with a field
and a message. The HTTP status is always 200.
| Error message | Endpoint | Cause |
|---|---|---|
Giftcard id is required | query | giftCardId is empty |
Invalid CVC code | query, redeem | CVC is missing or does not match |
Giftcard is expired | query, redeem | giftCard.isExpired() == true |
Giftcard not found | query, redeem, rollback | No card found with the provided ID |
No active company | all | No active company context (authentication failure) |
Invalid amount to redeem | redeem | amountToRedeem is null or ≤ 0 |
Insufficient funds | redeem | Balance < requested amount |
No wallet payment method found for account | redeem | No WalletPaymentMethod of type GIFTCARD configured |
Transaction not found | rollback | DirectPayment not found |
Transaction does not match giftcard | rollback | payment.giftCard ≠ provided gift card |
Transaction already rolled back | rollback | Status is already REFUNDED |
Transaction already cancelled | rollback | Status is already CANCELLED |
Transaction is not successful | rollback | Status is not PAID |
Request could not be authenticated | all | Invalid or missing API key / secret |
Invalid request: <message> | all | Malformed JSON or IO error reading the request body |
Requirements
Scanfie configuration
| Requirement | Description |
|---|---|
APIKey record | An active API key linked to the company |
CompanyGiftCard record | Gift card with an externalId and a linked wallet |
Wallet of type GIFTCARD | Must be linked to the CompanyGiftCard |
WalletPaymentMethod type GIFTCARD | A wallet/gift card payment method must be configured for the company |
TurnoverRegistrationGroup | The default gift card reservation payment registration group must exist |
Technical dependencies
| Class | Role |
|---|---|
CompanyGiftCard | Look up and validate the card; CVC calculation via calculateCVCCode() |
Wallet | Balance mutations via reductionViaPayment() and rollbackViaPayment() |
DirectPayment | Transaction record for audit trail and rollback capability |
WalletPaymentMethod | Determines which payment method the redemption is booked under |
TurnoverRegistrationGroup | Revenue accounting for gift card redemptions |
BaseDao | Retrieve DirectPayment by UUID during rollback |