Download OpenAPI specification:Download
This document contains a technical description for adding cards and deleting cards to and from Storebox PCI DSS Certified environment.
This only includes card operations that are out of PCI-scope. For operations like programatically adding cardholder data use the Vault API.
The intended audience for this documentation is technicians developing system integration to Storebox.
The API is organized around REST. The API is designed to have predictable, resource-oriented URLs and to use HTTP response codes to indicate API errors. We use built-in HTTP features, like HTTP authentication and HTTP verbs. JSON is the data interchange format and will be returned in responses from the API, including errors.
When users have registered their card number, Storebox will collect and maintian token values from multiple sources in order to identify users realtime based on their paymentcard. This usually requires collaboration with the terminal which provides the token sent to Storebox.
Note that Storebox stores cards in a PCI-DSS compliant environment and never exposes a users raw card number. All endpoints containing card information returns only a masked version of the card number.
Concepts:
Truncated/Masked card number | A masked card number consists of the first 6 and last 4 digits of the card number. The middle digits have been replaced by a character, we use X, for example: 4571000000000000 -> 457100XXXXXX0000 |
Card types | When cards are entered in Storebox, we try to identify the type of the card based on the IIN. The identified type resolves to a cardTypeId: 1 - Dankort/VISA Dankort 2 - eDankort 3 - VISA/VISA Electron 4 - Mastercard 5 - Reserved 6 - JCB 7 - Maestro 8 - Diners Club 9 - American Express 10 - Reserved 11 - Forbrugsforeningen 16 - BankAxept |
Card frame |
To support users in registering their payment card information, Storebox delivers a PCI-DSS certified webpage. The page can be embedded in an iframe or webview on any page and is highly customizable. |
When submitting a card to Storebox PCI compliant environment, Storebox will make as many validation checks as possible before accepting the request.
Checks include:
It is important to note that requests will also return http code 200 on validation errors.
For cardframe submits the cardframe will handle card validation responses from the backend and only send the enduser to the accepturl if a valid card has been entered.
When the backend accepts a submit request, the processing of the card will continue asynchronously. When processing has completed and only then, the PCI environment will send a notification to the provided callbackurl.
The accept URL is the URL where the enduser is redirected after they click the add payment card button. The URL is mainly an indicator to the caller that the operation is done, and the input window can be closed. The following is an example of completion detection in the iframe integration.
<iframe src="..." onload="done()"></iframe>
<script>
function done() {
// ... remove iframe etc
}
</script>
The callback URL is where the registered data is sent. This will usually be the server that hosts the integrating website/API.
To have Strong Customer Authentication (SCA) like 3D Secure activated contact Storebox.
If SCA is enabled, a declineurl must also be provided, when loading the cardframe. The SCA flow will start automatically after the card submit and will redirect the user through the relevant verification flow.
Only if the SCA flow is successful will the card be added to Storebox and the user will be redirected to the accept URL. If the flow for some reason is unsuccessfull the user will be redirected to the decline URL.
Server-side you generate the cardframe URL with all parameters (salt must never fall in the hands of client) and provide it to the client.
A quick demo can be had via https://developer.storebox.com/frame/index.html
Example data:
Hash generation:
UTF8 hmac-sha256 with salt as key of the string "userid + provider + accepturl + declineurl + callbackurl + cssurl + languageurl".
hmac-sha256({salt}, userId + provider + accepturl + declineurl + callbackurl + cssurl + languageurl)
String being HMAC'd: yourcustomeridyourprovideridhttps://developer.storebox.com/frame/accepted.htmlhttps://developer.storebox.com/frame/declined.htmlhttps://storebox.comhttps://developer.storebox.com/frame/assets/card.css?v=5https://developer.storebox.com/frame/assets/lang.json?v=6
Final URL with proper URL encoded parameters, provider and hash that is provided to client: [https://cardapi.test.storebox.com/api/v1/cards/cardframe?provider=yourproviderid&userId=yourcustomerid&accepturl=https%3A%2F%2Fdeveloper.storebox.com%2Fframe%2Faccepted.html&declineurl=https%3A%2F%2Fdeveloper.storebox.com%2Fframe%2Fdeclined.html&callbackurl=https%3A%2F%2Fstorebox.com&cssurl=https%3A%2F%2Fdeveloper.storebox.com%2Fframe%2Fassets%2Fcard.css%3Fv%3D5&languageurl=https%3A%2F%2Fdeveloper.storebox.com%2Fframe%2Fassets%2Flang.json%3Fv%3D6&hash=57f3a998962a7fc188edfa84f58bab67ba141de2416a55b92895f538467c18f5&type=card"]
Result in browser
The card frame is styled via the CSS specified in the cssurl
parameter in the initial call.
The stylesheet is cached and is only downloaded if the URL changes. For this reason a version parameter can be used in the cssurl
, for example https://.../style.css?v=1
. Please refrain from using a constantly changing parameter, like a timestamp.
This is the Card Frame HTML structure that can be styled:
<form action="" method="post">
<div class="field field-input">
<div class="field-label">Kortnummer</div>
<input id="CardNumber" name="CardNumber">
</div>
<div class="field field-input">
<div class="field-label">Udløbsmåned</div>
<input id="ExpMonth" name="ExpMonth">
</div>
<div class="field field-input">
<div class="field-label">Udløbsår</div>
<input id="ExpYear"name="ExpYear">
</div>
<div class="field field-btn">
<input type="submit" class="button" value="Gem nyt kort ">
</div>
</form>
<div class="generalError">
</div>
<div class="maxCards">
</div>
A JSON file specified by languageurl
configures the text displayed in the card input. The file contains of translation label and value like in the following example. The file must be provided in UTF-8.
{
"expMonth": {
"errorInvalid":"Skal være mellem 1 og 12",
"label":"Udløbsmåned",
"placeholder": "Indtast udløbsmåned"
},
"expYear": {
"label":"Udløbsår",
"placeholder":"Indtast udløbsår",
"errorExpired":"Kortet er udløbet"
},
"error": {
"generalError":"Der skete en fejl. Prøv venligst igen",
"maxCards":"Du kan ikke tilføje flere kort"
},
"btn": {
"save":"Gem kort"
},
"accountno": {
"errorInvalid":"Ugyldigt kontonummer",
"errorMinLength":"Skal minimum være 11 tegn",
"label":"Kontonummer",
"placeholder":"Indtast kontonummer",
"duplicate":"Kontonumret er allerede registreret"
},
"card": {
"errorInvalid":"Ugyldigt kortnummer",
"unsupportedType":"Denne korttype kan ikke bruges",
"unsupportedBinRange":"Dette kortnummer kan ikke bruges",
"label":"Kortnummer",
"placeholder":"Indtast kortnummer",
"duplicate":"Kortet er allerede registreret"
}
}
The text values are cached and are only downloaded if the URL changes. For this reason a version parameter
should be used in the languageurl
, for example http://.../en.json?v=1
. Please refrain from using a constantly
changing parameter, like a timestamp.
When a card has been fully processed a callback (GET) will happen if the callbackUrl parameter was defined on initial cardframe request. This includes important parameters such as externalCardId. Documentation is found under 'Callbacks' below.
At the time of writing, the callback is the only way to obtain those values. If the values are lost or ignored,
they cannot be re-sent by Storebox. Especially externalCardId
should be stored as this makes it possible to remove the card
from the PCI environment at a later point.
Under some circumstances a notification may be sent more than once.
The callback does not act upon the responses sent from the callbackurl endpoint. I.e. a redirect will not be followed.
When handling cards that support payment via account number, it is necessary to register both account number as well as the card number. Just like how all the card numbers must be registered for any combined card that contains multiple payment methods, e.g. MasterCard with both debit and credit.
Alternatively you may consider letting the user choose what they will be adding: a card number or an account number.
userId required | string External id of the user who owns the card |
provider required | string The identity of the caller. This is issued by Storebox |
accepturl required | string The URL where the page is redirected after successful card submit. This happens in the frontend so app handlers can be used. |
declineurl | string Required if Strong Customer Authentication (like 3DS) is enabled. The URL where the page is redirected after unsuccessful Strong Customer Authentication. This happens in the frontend so app handlers can be used. |
cssurl | string Absolute URL for the CSS file for input styling |
languageurl | string Public URL for the translation JSON file |
callbackurl | string The URL to callback when the card has finished processing. |
type | string Enum: "card" "accountno" What type of frame should be displayed. Default is the card frame Possible values
|
hash required | string HMAC-SHA256 hash of the parameters. hmac-sha256({salt}, userId + provider + accepturl + declineurl + callbackurl + cssurl + languageurl). The salt is provided by Storebox along with the provider value |
NOTE It is only allowed to add non-EMV cards, for example BankAxept or customer card using this interface. For EMV card, please contact Storebox support.
The API accepts an encrypted package containing the full cardnumber and expiry month/year.
The encrypted payload is a JSON string in the form:
{
"expiry": {
"year": 20,
"month": 1
},
"cardNumber": "...",
"par": "..."
}
cardNumber or par may be omitted. If PAR is omitted, Storebox will try to look it up. If cardNumber is omitted, the receipts will only work with PAR-based payment methods.
The string is encrypted and Base64 encoded. The supported encryption algorithm is RSA with OAEP padding.
Test example of generating the card payload from the command line.
cat <carddata.txt> | openssl pkeyutl -encrypt -pubin -inkey <transport.pem> -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 | base64
The resulting card payload should be added in the encryptedCard
request property.
If BankAxept cards are added, they have to be in their card number for i.e. 957852<account-number><luhn-digit>
.
provider required | string The provider name |
userId required | string The user id |
encryptionProvider required | string The encryption provider |
encryptedCard required | string The card encrypted with the RSA transport key using OAEP padding |
callbackUrl | string The URL to receive the callback when the card is created |
{- "provider": "storebox",
- "userId": "1234",
- "encryptionProvider": "storebox",
- "encryptedCard": "string",
- "callbackUrl": "string"
}
Return all cards registered to the caller. The result is pageable and sortable.
page | integer <int32> Pagenumber to return. The page index is zero-based. Defaults to 0 (zero) |
size | integer <int32> Elements returned per page. Defaults to 100. |
sort | string^(cardNumber|cardTypeId|userId|created),(asc|... Sort of the returned content. Defaults to 'sort=created,desc'. Sort can have any of the values: cardNumber, cardTypeId, userId or created. In addition to defining the field to sort in, the sort direction is also defined in this field by either asc or desc Example: '...&sort=cardNumber,asc&...' |
{- "content": [
- {
- "externalCardId": "e75ca15c8ae1401c943ff15df437f1d8",
- "provider": "storebox",
- "cardNumber": "445412XXXXXX9016",
- "expMonth": 12,
- "expYear": 21,
- "cardTypeId": 1,
- "userId": "nxb3wMhjIjeElyNMQGzW431RCqLVL2vt",
- "verified": true,
- "created": "2014-05-14T15:22:11Z"
}
], - "totalElements": 1000,
- "totalPages": 10,
- "first": true,
- "last": false,
- "numberOfElements": 100,
- "page": 0
}
Get all cards registered to a specific userId
userId required | string Example: e75ca15c8ae1401c943ff15df437f1d8 Member id that should be looked up |
[- {
- "externalCardId": "e75ca15c8ae1401c943ff15df437f1d8",
- "provider": "storebox",
- "cardNumber": "445412XXXXXX9016",
- "expMonth": 12,
- "expYear": 21,
- "cardTypeId": 1,
- "userId": "nxb3wMhjIjeElyNMQGzW431RCqLVL2vt",
- "verified": true,
- "created": "2014-05-14T15:22:11Z"
}
]
If existing cards are stored in Storebox, which have not yet been verified by 3DS, this endpoint can be used to start the 3DS flow.
The card owner must complete the authentication, so this endpoint will redirect and start the 3DS flow. The endpoint must therefore be used from a browser or webview like the card frame.
After a successful completion the card will be marked as verified.
provider required | string The identity of the caller. This is issued by Storebox. |
externalCardId required | string Id of the card to verify. The card id was delivered in the callback on card creation. |
accepturl required | string The URL where the page is redirected after successful card verification. This happens in the frontend so app handlers can be used. |
declineurl required | string The URL where the page is redirected if the verification was unsuccessful. This happens in the frontend so app handlers can be used. |
hash required | string HMAC-SHA256 hash of the parameters. hmac-sha256({salt}, provider + externalCardId + accepturl + declineurl). The salt is provided by Storebox along with the provider value |
Insert account number only. Note that even though this inserts an account number it is still conceptually a card, i.e. it is deleted as a card using the externalCardId. The callback is the same as the card frame.
userId required | string External id of the user who owns the card |
provider required | string The identity of the caller. This is issued by Storebox |
accepturl required | string The URL where the page is redirected after successful card submit. This happens in the frontend so app handlers can be used. |
cssurl | string Absolute URL for the CSS file for input styling |
languageurl | string Public URL for the translation JSON file |
callbackurl | string The URL to callback when the card has finished processing |
hash required | string HMAC-SHA256 hash of the parameters. hmac- sha256({salt}, userId + provider + accepturl + callbackurl + cssurl + languageurl). The salt is provided by Storebox along with the provider value |
Insert account number only by API. This endpoint verifies the format of the account defined by the accountNoType.
accountNo required | string The accountNo that should be added. |
accountNoType required | string The type of the submitted account no. This value is provided by Storebox. |
userId required | string An unique identifier of the owner of the account no. |
provider required | string The owner program of the account no. This value is provided by Storebox. |
callbackUrl | string Optional - Event url to call when the asynchronous add account no. operation has completed. |
{- "accountNo": "12345678901",
- "accountNoType": "bankaxept",
- "userId": "3sk2zjf65u97jrw4yl17",
- "provider": "storebox",
}
{- "status": 0,
- "externalCardId": "hdwu2gbqesc49admkxnv"
}