Flexepin Merchant API
Everything you need to accept Flexepin vouchers: validate a PIN, redeem it, and handle the responses correctly.
1. What Flexepin Is
The Flexepin voucher is essentially a 16-digit code (the "PIN") that a customer enters at the merchant's checkout to deposit funds, or pay for a product or service. Each PIN is unique, single-use, and has its own fixed monetary value. Once a voucher is redeemed, the transaction is final and cannot be reversed.
A voucher's PIN can reach you one of two ways:
- Manual entry: the customer manually enters their pre-purchased 16-digit PIN at your checkout — this is the flow this document covers.
- Automatic delivery via Flexpay: the PIN is delivered directly to you via the Flexpay add-on, instead of the customer typing it in — see the Flexpay documentation for that flow.
2. General Info
Environments
| Environment | Base URL |
|---|---|
| Test | https://testrest.flexepin.com |
| Production | https://rest.flexepin.com |
Credentials
The API key & secret, and Back Office (Merchant Portal) credentials, are provided by the Flexepin support team.
Use your API Key as your Terminal ID as well. They are the same value — there is no separate, distinct Terminal ID to obtain.
The production credentials will be shared after the integration has been completed and a commercial agreement has been put in place.
Support
If you need your credentials reset or for any other help, contact support@flexepin.com.
3. Integration at a Glance
4. Try It Live
Before writing any code, you can generate real test vouchers and submit them for validation and redemption through the interactive demo site — it shows you the actual request and response for every API call.
https://demo.staging.flexepin.com/
Prefer to test in Postman?
Download the collection below and import it — it includes Validate, Redeem, and the transaction lookup requests, all with the HMAC signature computed for you automatically before each send. Just set your API Key, Merchant Secret, and a test PIN in the collection's Variables tab.
⬇ flexepin_merchant_api.postman_collection.json
5. Validate & Redeem APIs, Side by Side
| Validate | Redeem | |
|---|---|---|
| Method | GET | PUT |
| Changes anything? | No | Yes — marks the voucher as Used, transaction is final |
| Request body | Never — GET has no body | Optional — customer_id / customer_ip / customer_ip_data |
| Mandatory step? | No — explicitly optional | Yes — this is what completes the payment |
| Safe to retry? | Yes | No — can only succeed once |
Confirmed: reusing the same current_transaction_id on repeated Validate calls does not cause any issue and does not affect redemption.
Validate — response example
See Section 7 for a complete, runnable Validate request.
{
"result": "0",
"result_description": "Success",
"serial": "54040500000303719",
"currency": "EUR",
"description": "Flexepin EUR 100",
"value": 100
}
Redeem — response example
See Section 7 for a complete, runnable Redeem request.
{
"result": "0",
"result_description": "Success",
"transaction_id": "..."
}
6. Authentication (HMAC)
Every request must prove it genuinely came from you, but without ever sending your secret key over the network. Instead, each request carries a one-time "signature" — built from the request itself plus your secret key — that Flexepin recalculates on their end to confirm it matches. This applies to both the Validate and Redeem calls you just saw above.
The header
AUTHENTICATION: HMAC [api_key]:[signature]:[nonce]
Building the signature
Concatenate these four items with a newline (\n) between each, then compute a SHA-256 HMAC of the result, keyed with your Merchant Secret:
Request Method
URI Endpoint
nonce
Request body
If there's no body, leave it empty — but the newline before it must still be there.
The nonce (in the auth header) and the current_transaction_id (in the URL) are two separate values that both need to be unique per request — but they do different jobs. The nonce only affects the signature. Generate a unique one every time.
Worked example
This is a signed Redeem request, using the URL shape from Section 5:
| Method | PUT |
| URI | /voucher/redeem/1938475602918475/MERCHANTTESTKEY/58291 |
| Nonce | 1735689421983 |
| Body | { "customer_ip": "203.0.113.42", "customer_ip_data": {...} } |
| Merchant Secret | Tr7!qXpL9$mWzKv2 (placeholder test value — not a real credential) |
🔑 Try it yourself — live signature calculator
Pre-filled with the worked example above — click Compute and confirm it produces the same signature. Then try your own Method / URI / Nonce / Body. The Merchant Secret field is fixed to a test-only value and can't be edited — this tool is for checking your code's logic, not for use with your real secret.
7. Starter Code
Complete, working functions for Validate and Redeem — not a template with a gap where the signature should go. Swap in your real PIN, API Key, and Merchant Secret before using it.
8. Flexepin Voucher Currencies & Types
The various Flexepin currencies fall into two types.
| Voucher Type | Currency |
|---|---|
| Closed Loop | EUR, GBP, PLN, CHF |
| Open Loop | CAD, USD, NZD, ZAR |
Note: If you are not sure which currencies you should implement — confirm this with your team. Implementing EUR and CAD covers all scenarios from a technical point of view.
- The end user sees no difference in the validation/redemption between the 2 types.
- The Validation/Redemption API requests are the same between the 2 types.
- Only a small difference exists in the API responses between the 2 types.
Voucher handling as per Voucher type
Closed Loop:
When EUR, GBP, PLN & CHF vouchers are submitted to the Validate API they come back as having the 'Quarantine' status — this is expected, not an error, proceed to redemption.
When a closed loop voucher is submitted to the Redeem API, it is automatically swapped in the background (by the Flexepin system) for an equivalent Active status voucher, and that one is redeemed toward the merchant instead. The redeemed voucher takes on the status of 'Used'.
Your original transaction ID is preserved, but the Serial number, Description, and EAN fields will reflect the new, swapped-to voucher. No action is required on your end — this happens automatically on Flexepin's side.
Open Loop:
When CAD, USD, NZD, ZAR vouchers are submitted to the Validate API they come back as having the 'Active' status — proceed to redemption.
When an open loop voucher is submitted to the Redeem API, the same voucher is redeemed towards the merchant and takes on the status of 'Used'.
9. Result Codes
Success / still valid
| HTTP | Code | Meaning |
|---|---|---|
| 200 | 0 | Success — voucher is Active, or transaction succeeded |
| 200 | 10251 | Quarantine — valid and fully redeemable, not an error. Applies to EUR, GBP, PLN and CHF (Closed Loop) Flexepin vouchers. |
Errors
| HTTP | Code | Meaning | Commonly caused by |
|---|---|---|---|
| 200 | 32 | No voucher stock | There is no stock available for a voucher product allocated to the merchant profile. This error is very rare. If it occurs, it is most likely when the merchant profile is first set up and its products are created. This is on the Flexepin side — please contact Flexepin support. |
| 200 | 503 | Maintenance mode | Scheduled downtime — retry later |
| 200 | 4019 | Voucher type/value not accepted | The merchant has not been configured for this currency or denomination. Nothing has gone wrong on either side: the end user tried to redeem a voucher that isn't compatible with the merchant's account, for example a CAD voucher at a merchant that only accepts EUR. |
| 200 | 4071 | Voucher is locked | Flexpay only: the merchant has not yet responded to the webhook that delivered the voucher details with a success result (resultCode: 0). |
| 200 | 4072 | Voucher already used | Voucher has already been used. |
| 200 | 4073 | Voucher not active | The merchant profile has not been set up to accept the specific voucher product that the end user tried to redeem. This error is rare and indicates a misconfiguration in the Flexepin system. |
| 200 | 4074 | Voucher expired | The voucher is older than 12 months. |
| 200 | 4075 | Invalid voucher PIN | Invalid voucher PIN supplied. |
| 200 | 4080 | Voucher value insufficient | — |
| 403 | 403 | Not authorised to access this resource | Invalid credentials or HMAC authentication. Use the HMAC signature calculator in Section 6 to check your signature logic. |
| 401 | 401 | Invalid Terminal ID | The merchant's API key was not used in the Terminal ID field. The Terminal ID is the same value as the API key. |
10. Flexepin Terms & Conditions Acceptance by the User
Required on any screen where a customer enters or submits a Flexepin PIN:
- A Terms & Conditions checkbox, unchecked by default
- The user must manually check it before proceeding — if it is left unchecked, the customer must not be able to continue with the transaction
- The site may remember the user's selection for future transactions
- "Flexepin Terms & Conditions" as a hyperlink opening in a new tab
- On hover: "By checking, you acknowledge that you have read, understood, and agree to be bound by the Terms and Conditions associated with the use of a Flexepin voucher. Acceptance is necessary to access and utilise our offerings."
Live example
Reference implementation
<div class="flexepin-tc">
<input type="checkbox" id="tcdemo">
<label for="tcdemo">
I agree to the <a href="https://www.flexepin.com/flexepin-terms-and-conditions-eea/" target="_blank">Flexepin Terms & Conditions</a>
</label>
</div>
11. Reference Appendix
All endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /status | Check API is online |
| GET | /voucher/validate/{pin}/{terminal_id}/{current_transaction_id} | Check voucher status |
| PUT | /voucher/redeem/{pin}/{terminal_id}/{current_transaction_id} | Finalise redemption |
| GET | /trans/trans_no/{trans_no}/{terminal_id}/{current_transaction_id} | Look up a transaction by Flexepin trans_no |
| GET | /trans/trans_id/{past_transaction_id}/{terminal_id}/{current_transaction_id} | Look up a transaction by your own merchant transaction ID |
| GET | /trans/between/{from_date}/{to_date}/{terminal_id}/{current_transaction_id} | Look up transactions in a date range (yyyy-mm-dd) |
Common parameters
| Parameter | Type | Notes |
|---|---|---|
pin | string | The Flexepin 16-digit PIN |
terminal_id | string | Same as your API Key — see "General Info" |
current_transaction_id | string | Unique per request, max 32 characters — used for duplicate detection |