# General The API is based on common HTTP API implementations. ### HTTP methods Only `GET` & `POST` apply. ### Secure connections Non-secure connections are not allowed. Using `http://` instead of `https://` results in a redirect: #### Redirect Response * Status Code: `302` * Content Type: `text/html; charset=iso-8859-1` * Location: The secure version for the requested URL ### Headers * User-Agent: Each request must define the header `User-Agent`. If not provided, the request will be blocked and result in a non-API HTTP error. * Content-Length/Transfer-Encoding: A request must also contain the header `Content-Length`, which is usually present implicitly ( using cURL or [Postman](https://www.getpostman.com/) ). Transfer-Encoding is also supported and should be used instead of Content-Length with value '[chunked](https://en.wikipedia.org/wiki/Chunked_transfer_encoding)'. If neither is used, the request will be blocked and result in a non-API HTTP error. Missing headers result in: #### Forbidden Response * Status Code: `403` * Content Type: `text/html; charset=iso-8859-1` # Authentication As a merchant you'll access the VPOS as a remote service without interaction of the customer. The access is restricted and requires you to authenticate. **Note:** In the curl examples, there is an `apikey` user that you must replace with your own API key. ## API Keys We provide you with a set of API keys. See [Operating Mode](#operating-mode) for a detail description of this property. See [Entry Mode](#entry-mode) for a detail description of this property. Authentication is performed using Basic Authentication which requires you to send an `Authorization` header for each request. The format of the value of the header is defined as `username:password`. The `username` is the value of the API key and the password remains empty. An example of a TEST API key: `t_e40a9b36f4c1fa31f512c623bb5a315696e98cea:` **Note**: * This API key is not valid and cannot be used to perform tests with; you must use the keys we will provide. * The header string must be Base64 encoded. ## Entry Mode There are 2 entry modes: **ECOM** & **INSTORE**. The entry mode specifies the environment used to initiate payment. Online or e-commerce transactions ( **ECOM** ) take place in a web, online or mobile environment. The software runs on a device owned by the customer; his or her smartphone, laptop, computer, etc.... In-store ( **INSTORE** ) transactions take place in a store/merchant environment. The software runs on a merchant owned device; a kiosk, vending machine, register ... An entry mode is not required when creating keys, as it will default to **ECOM** when not specified. ## Operating Mode When a key is generated, you can choose the operating mode of the key. The mode defines what will happen with the payment when it is processed by the system. There are 2 operating modes: **LIVE** & **TEST**. To identify the operating mode of a key, use the prefix: `l_` for **LIVE** and `t_` for **TEST**. Dependent on the operating mode of the used key, the payment methods will be processed differently. When using a **TEST** key: 1. A card payment will not be processed by the acquirer and always succeed 2. An iDEAL payment will be handled by a simulated acquirer 3. A PayPal payment will be handled by the PayPal sandbox servers 4. A token will be a simulated token that is _NOT_ PCI compliant # Error Handling In case of an error we respond with a corresponding HTTP status code. The body of the response will be an error in JSON. ## Response * Status Code: Dependent on the type of error: see [HTTP Status](#http-status) for possible values * Content Type: `application/json;charset=UTF-8` * Content: [Error](#error) ## HTTP Status | Code | Message | Description | |------|---------|-------------| | 400 | Bad Request | Invalid input in the request | | 401 | Unauthorized | None or invalid API key (typo, expired) | | 404 | Not Found | Invalid URL | | 415 | Unsupported Media Type | Not using `application/json` as the content type | | 500 | Internal Server Error | Unexpected error | | 504 | Gateway Timeout | Processing the request took too long. Default time out is 60000 ms | ## Error All resources will return a JSON object in case of an error. *Definition* | Name | Description | |------|-------------| | type | Possible values: `input_error`, `process_error`, `unexpected_error`| | message | A generic message. Contains helpful information regarding the cause of the error. Should not be parsed | | field | In case of type `input_error` the field that caused the error. Else not present | | reference | A reference that you can provide to the helpdesk for investigation of the failing request | | failureCode | An optional field that explains more about the cause of the failure. Possible values: [Failure Codes](#failure-codes) | | transactionReference | In case of a time out, an optional transaction reference to query the status of the transaction. | *Example of an Input error due to an invalid amount* ```json { "type" : "input_error", "message" : "An input parameter is incorrect", "reference" : "718ee617", "field" : "amount" } ``` ## Failure Codes All error responses with failure codes are HTTP Status Code 400: Bad Request. | Name | Description | |------|-------------| | expired | The transaction is expired which can happen if remote services such as iDEAL or PayPal expire the transaction on their side| | processing_error | A general error if the transaction can't be processed correctly| | invalid_config | The configuration of the merchant or method is not correct| | cancelled | The transaction is cancelled by either the customer or the merchant. The field `cancelledBy` indicates the initiator of the cancel| | unsufficient_balance | In case of refunds, the transaction can be denied if the balance of the merchant is insufficient| | fraud_detected | The transaction is denied due to fraud prevention| | rejected | The transaction is manually confirmed and rejected | | unknown_reference | The reference used is not known. | | refund_limit | The refund limit for this transaction has been reached, not further refunds are allowed for this transaction. | | unsupported_currency | The [currency](#currencies) in your request is not supported | | qr_failed | There was a problem with the `required` QR-Code | | card_refused | The transaction is declined because the card host refused/declined the transaction | | insufficient_funds | The transaction is declined because the customer has insufficient funds available | | vault_token_expired | Either the vault access token or the card data attached to the vault access token is expired | | amount_limit_exceeded | The transaction amount exceeds the configured limit | | bad_credentials | The provided authentication credentials in your request are incorrect | *Example of a Process error due to invalid method configuration with failure code* ```json { "type" : "process_error", "message" : "The request could not be processed", "reference" : "dfa865b6", "failureCode" : "invalid_config" } ``` # Resources * The API is based on REST principles although it isn't a pure REST interface * Each response body is encoded with UTF-8 * Each datetime value is in the so-called epoch timestamp; number of **milliseconds** since January 1st, 1970, UTC * Each [ISO 8601 Duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) is interpreted relative to the epoch time; number of **milliseconds** since January 1st, 1970, UTC ## Payment The payment resource is responsible for initiating new payments and refunds. #### Flow The general flow will be: 1. You [create a new payment](#create-a-new-payment) 2. Redirect the customer to us 3. Dependent on the selected payment method, we guide the customer throughout the payment process 4. When the payment is done, we redirect the customer back to your shop 5. You [read the payment](#read-a-transaction) to verify the status 6. Occasionally, you [manually approve the transaction](#manually-approve-or-reject-a-transaction) in case of suspicious activity #### Status Verification We do not expose the status of the payment or any of its details to the customer. It is up to you to verify the status of the payment and act accordingly. [Webhooks](#webhooks) are provided to give you feedback, but this principle remains. #### Collecting payments The VPOS will collect the money of your customers on your behalf when your payment is processed by: * method `ideal`, or * method `sofort`, or * method `banktransfer`, or * method `card` using acquirer `paybox`, `bancontact` or `payvision`. On regular intervals, you will be paid out. #### Deferred sales A deferred sale is a payment that is suitable for businesses that need to authorise an amount from the card holder before the services or goods are delivered. Once the card holder has received his services or goods, the merchant can than complete the transaction with an amount less than or equal to the reserved amount. Deferred sales are supported for card brand Bancontact (`bcmc`) with several limitations set by Bancontact: 1. Only merchants in category **Automated Fuel Dispensers** (MCC 5542) are allowed to use this service 2. The maximum amount of an authorisation is set to 125 EUR To use deferred sales with our API, you need to implement the following functionality: 1. [Authorise](#create-a-new-payment) the amount with a payment of type `authorise` 2. Complete the transaction with a [capture](#capture-an-existing-authorisation) of the final amount In case the money should be released back to the card holder, a [reversal](#reverse-an-existing-authorisation) can used. #### Payment ##### Definition | Name | Description | |------|-------------| |type|Fixed value: `sale`, `credit` or `authorise`| |amount|The amount of the transaction | |currency|An ISO 4217 three-letter code. Possible values: [Currencies](#currencies)| |token|If a token was requested and if the payment concerns cards, a max 18 long string will be returned. Else null| |tokenMaskedInput|If a token was created, the input (PAN or IBAN) will be returned, [masked](#masking).| |status|Possible values: [Transaction Status](#transaction-status)| |merchantOrderReference|A reference, maximum 255 characters, of the order associated with this payment| |description|A description to show the customer| |language|The language of the customer. Possible values: `eng`, `nld`, `deu` or `fra`| |method|The payment method that the customer chooses. Possible values: [Supported Methods](#supported-methods)| |brand|This is only filled in for card payments and is the brand of the used card. Possible values: [Supported Brands](#supported-brands)| |metadata|An arbitrary string, maximum 255 characters, that can be used to track payments| |payUrl|To complete the payment the customer should be redirected to this URL.| |returnUrl|After the payment is completed (successfully or otherwise) the customer is redirected to this URL| |cancelUrl|This url can be used to [cancel the payment](#cancel-a-payment). Only included when applicable| |reference|A unique reference for the payment transaction| |methodTransactionId|A third party transaction ID which identifies the payment transaction in external systems. If empty no such id was available or no third party was employed| |created|The local server datetime the payment was created, epoch timestamp| |lastUpdate|The local server datetime the payment was updated, epoch timestamp| |entryMode|The entryMode for the payment resulting from the [Api Key](#api-keys) used. Possible values: `ecom` or `instore`| |failureCode|An error code indication what caused the failure. Possible values: [Failure Codes](#failure-codes)| |cancelledBy|Indicates who initiated the cancel. Possible values: `customer` and `merchant`| |billingAddress|The billing street address| |billingCity|The billing city of the customer| |billingState|The billing region/state of the customer| |billingPostalCode|The billing postal (zip) code of the customer| |billingCountry|The billing country , an ISO 3166 alpha-2 code| |billingEmail|The billing email of the customer| |billingPhoneNumber|The billing phone number of the customer| |billingFirstName|The billing first name of the customer| |billingLastName|The billing last name of the customer| |billingHouseNumber|The billing house number of the customer| |billingHouseExtension|The billing house extension of the customer| |shippingAddress|The shipping street address| |shippingCity|The shipping address city| |shippingState|The shipping address region/state| |shippingPostalCode|The shipping address postal (zip) code| |shippingCountry|The shipping address country, an ISO 3166 alpha-2 code| |shippingEmail|The shipping email of the customer| |shippingPhoneNumber|The shipping phone number of the customer| |shippingFirstName|The shipping first name of the customer| |shippingLastName|The shipping last name of the customer| |shippingHouseNumber|The shipping house number of the customer| |shippingHouseExtension|The shipping house extension of the customer| |childReferenceId|Contains the referenceId of the resulting child transaction. Applies to [landing page](#landing-page) and [vault](#vault) payments| |manualApprovalRequired|A boolean value that indicates whether this transaction is awaiting [manual approval](#manually-approve-or-reject-a-transaction) | |note|A text message attached to this transaction| |signoff|The person who performed the manual approval or rejection| |paidout|A boolean value that indicates if this transaction has been paid out. Possible values: `yes` or `no`. Only available for [Collecting Payments](#collecting-payments)| |paidoutDate|The date on which the payment to the merchant was done. Only available for [Collecting Payments](#collecting-payments)| |unstructuredReference|The unstructured reference used when performing the payout to the merchant or to the customer in case of refunds. Only available for [Collecting Payments](#collecting-payments)| |paidoutReference|The reference used when performing the payout to the merchant. This can be used to look up a transaction related to that payout. Only available for [Collecting Payments](#collecting-payments)| |details|An optional object listing method specific payment details. Possible types: [Payment Details](#payment-details) | |userAuthenticationMethods|Optional list of authentication methods performed by the cardholder in case Vault Access Token is used: Possible values: [User Authentication Method](#user-authentication-method)| |sequenceType|Optional field indicating the sequence type of the transaction in case Vault Access Token is used: Possible values: [Sequence Type](#sequence-type)| ##### Transaction Status | Name | Description | Webhook called? | |------|-------------|------------------| | pending | The transaction is created but not completed yet | No | | failed | Transaction processing failed | Yes | | manualintervention | The transaction is in a state of which we can't recover automatically. Contact the helpdesk for further investigation| Yes | | success | The transaction is processed successfully | Yes | ##### User Authentication Method | Name | Description | |------|-------------| | username_password | The cardholder used username and password to authenticate successfully| | pin | The cardholder used PIN to authenticate successfully| | hsm | Authentication was successfully performed through Secret/Private Key in Secure Hardware Solution| | ssm | Authentication was performed through Secret/Private Key in Secure Software Solution (mobile app)| | location_based | Location-based Authentication was successfully performed (GPS location or other location based analysis of customer device) | | environmental_based | Environmental Authentication in Secure Software Solution (mobile app) was successfully performed (WIFI SSID, MAC addresses of customer device)| | behaviour_analysis | Behavioral Analysis was successfully performed (methods allowing the actual user from robots like measuring consumer movements for example)| | biometrics | Biometrics Authentication was successfully performed (for example fingerprint validation on mobile phone)| | out_of_band | Out Of band Authentication was successfully performed (usage of a second communication channel like phone communication, one time password by SMS)| ##### Sequence Type | Name | Description | |------|-------------| | express_checkout | A non-recurring one-time transaction| | recurring | A periodic based recurring transaction| | installment | A recurring payment of which the number of payments is limited in frequency and/or time| *Example* ```json { "type" : "sale", "amount" : 316.35, "currency" : "eur", "status" : "success", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Payment description", "language" : "eng", "method" : "card", "metadata" : "my custom metadata", "reference" : "C1505181754007360.1", "methodTransactionId" : "2ddd58ef-ba83-41bd-b208-647bcd8256b2", "created" : 1431964440770, "lastUpdate" : 1431964458858, "payUrl" : "https://redirect.jforce.be/card/payment.html?reference=C1505181754007360.1", "returnUrl" : "http://shop/?order=8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "brand" : "visa", "token" : "2424242424242424", "tokenMaskedInput" : "4111XXXXXXXX1111" } ``` #### Payment Details * [LandingPage Payment Details](#landingpage-payment-details) * [BankTransfer Payment Details](#banktransfer-payment-details) * [Card Payment Details](#card-payment-details) * [Terminal Payment Details](#terminal-payment-details) * [iDEAL Payment Details](#ideal-payment-details) * [Giropay Payment Details](#giropay-payment-details) * [Payconiq Payment Details](#payconiq-payment-details) * [OK.APP Payment Details](#ok-app-payment-details) ##### LandingPage Payment Details | Name | Description | |------|-------------| |expirationDuration|The time until payment expiration in [ISO 8601 Duration](https://en.wikipedia.org/wiki/ISO_8601#Durations)| |mail|In case of `banktransfer`, A boolean value that indicates to mail the payment instructions. Defaults to `true`| *Example* ```json { "expirationDuration" : "P0Y2M1DT0H0M0.000S" } ``` ##### BankTransfer Payment Details | Name | Description | |------|-------------| |expirationDuration|The time until payment expiration in [ISO 8601 Duration](https://en.wikipedia.org/wiki/ISO_8601#Durations)| |iban|The IBAN account number the customer must wire the amount to| |bic|The BIC number of the bank the customer should wire the amount to| |banktransferReference|The reference the customer should use for the bank transfer| |mail|A boolean value that indicates to mail the payment instructions. Defaults to `true`| |mailReminderDuration|The time until to mail a payment reminder in [ISO 8601 Duration](https://en.wikipedia.org/wiki/ISO_8601#Durations)| *Example* ```json { "expirationDuration" : "P0Y0M12DT0H0M0.000S", "iban" : "NL91ABNA0417164300", "bic" : "INGBNL2A", "banktransferReference" : "0000341468425141", "mail" : true, "mailReminderDuration" : "P0Y0M7DT0H0M0.000S" } ``` ##### Card Payment Details | Name | Description | |------|-------------| |maskedPan|The [masked](#masking) primary account number| |cardholderFirstName|The first name of the cardholder| |cardholderLastName|The last name of the cardholder| |qrCode|Contains the content of the QR code that should be shown to the customer| |urlIntent|Contains the URL intent that can open a brand specific mobile app| |authorisedAmount|The authorised amount of the transaction. Only present for successful `authorise` transactions. This can be equal to or lower than the requested amount if supported by the acquirer| More information on the use of `qrCode` and `urlIntent` for Bancontact payments can be found [here](doc/bancontact). *Example* ```json { "maskedPan": "XXXXXXXXXXXXXX227", "cardholderFirstName": "testName", "cardholderLastName": "testLastName", "qrCode": "BEP://1BEP.JFORCE.BE:3417/TMI$2N145W4C2HSHJKGOZNVFOMQG", "urlIntent": "BEPGenApp://DoTx?TransId=1BEP.JFORCE.BE:3417/TMI$2N145W4C2HSHJKGOZNVFOMQG", "authorisedAmount": 45.33 } ``` #### Terminal Payment Details | Name | Description | |------|-------------| |terminalId| The terminal id as assigned by CCV | |managementSystemId | The management system id of this terminal as by assigned CCV | |accessProtocol| The communication protocol between the terminal and access server | |ip| The browser accessible IP of the terminal for initiating the wake up | |port| The browser accessible port of the terminal's socket handling HTTP calls | |operatingEnvironment| The environment in which the terminal is operating. Possible values: `ATTENDED` and `SEMI_UNATTENDED`. Defaults to `SEMI_UNATTENDED` when empty. | |merchantLanguage | The language of the merchant in which the intermediate page should be displayed | |merchantReceipt| The receipt for the merchant as an escaped JSON string. The content can be parsed to a JSON array | |customerReceipt| The receipt for the customer as an escaped JSON string. The content can be parsed to a JSON array | |journalReceipt| The journal for the merchant as an escaped JSON string. The content can be parsed to a JSON array| |eJournal| The E-Journal for the merchant as an escaped JSON string. The content can be parsed to a XML | |askMerchantSignature| If true, the receipt should be signed by the merchant | |askCustomerSignature| If true, the receipt should be signed by the customer | |askCustomerIdentification| If true, the customer should provide identification | |printCustomerReceipt| If true, the merchant print the customer receipt | *Example* ```json { "terminalId" : "1234536", "managementSystemId" : "000103030", "accessProtocol" : "OPI_NL", "ip" : "127.0.0.1", "port" : 6235, "operatingEnvironment" : "ATTENDED", "merchantLanguage" : "NLD", "merchantReceipt" : "[ \"Kopie Merchant\", \"\", ...]", "customerReceipt" : "[ \"Kopie Klant\", \"\", ...]", "journalReceipt" : "[ \"JOURNAAL\", \"\", ...]", "eJournal" : "<?xml version=\"1.0\"?>\n<E-Journal>\n...</E-Journal>", "askMerchantSignature" : false, "askCustomerSignature" : false, "askCustomerIdentification" : false, "printCustomerReceipt" : false } ``` ##### iDEAL Payment Details | Name | Description | |------|-------------| |consumerBic|The BIC of the cardholder| |consumerAccountNumber|The account number of the cardholder| *Example* ```json { "consumerBic": "INGBNL2A", "consumerAccountNumber": "NL53INGB0654422370" } ``` ##### Giropay Payment Details | Name | Description | |------|-------------| |consumerBic|The BIC of the cardholder| |consumerAccountNumber|The account number of the cardholder| *Example* ```json { "consumerBic": "INGBNL2A", "consumerAccountNumber": "NL53INGB0654422370" } ``` ##### Payconiq Payment Details | Name | Description | |------|-------------| |transactionId|The transaction ID known in the system of Payconiq. Only for informational purposes.| |qrCode|Contains the content of the QR code that should be shown to the customer.| *Example* ```json { "transactionId": "transaction_id_from_scheme", "qrCode": "https://pay-url.payconiq.com/api/transactions/115DS5D5F1QSDG5F1QDG531QGD531QD15GS3" } ``` ##### OK.APP Payment Details | Name | Description | |------|-------------| |transactionId|The transaction ID known in the system of OK.APP. Only for informational purposes.| |qrCode|Contains the content of the QR code that should be shown to the customer. | *Example* ```json { "transactionId": "transaction_id_from_scheme", "qrCode": "https://okit.io/q/#t05442jTA-4vW3chFlDEg" } ``` ##### Parsing the receipts The receipt string contains an escaped JSON array which can be parsed into a JSON node tree. Each item in the array is a line of the receipt. The line should be handled as-is including empty lines and content multiple spaces that handle text alignment. *Example (JavaScript)* ```javascript var receipt = "[ \"Kopie Merchant\", \"\", \"******* PAS OP: TEST SYSTEEM *******\", \"\", \"Terminal: 20000002\", \"Merchant: 123456789012345\", \"Periode: 3090 Transactie: 10274782\"]"; var lines = JSON.parse(receipt); lines.forEach(line => console.log(line)); ``` ``` Kopie Merchant ******* PAS OP: TEST SYSTEEM ******* Terminal: 20000002 Merchant: 123456789012345 Periode: 3090 Transactie: 10274782 ``` ##### Parsing the E-Journal The string containing the XML is well formed and can be parsed into a DOM tree. ### Create a new payment #### Request * Resource: `/api/v1/payment` * Method: `POST` * Content-Type: `application/json` * Authentication: **Required** * Supports [idempotency](#idempotency) * Parameters | Name | Required | Method | Description | Max Length| |------|----------|--------|-------------|-----------| |amount|Yes|All|The amount of the transaction with format as defined by the [currency](#currencies) used|19+2| |currency|Yes|All|An ISO 4217 three-letter code. Possible values: [Currencies](#currencies)|3| |returnUrl|Conditional|All|Not required when using the [Card Request Details](#card-request-details) or the [Vault Request Details](#vault-request-details). After the payment is completed (successfully or otherwise) the customer is redirected to this URL. If not left empty it must include a [scheme](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Examples) to be usable for browser redirection or Android/iOs app usage. We do not validate this url.|2000| |method|Yes|All|The payment method that the customer chooses. Possible values: [Supported Methods](#supported-methods)|n/a| |language|Yes|All|The language of the customer. Defines the language to be used in the payment screens the customer will see. Possible values: `eng`, `nld`, `deu` or `fra`|3| |metadata|No|All|An arbitrary string, maximum of 255 characters, that can be used to track payments|255| |merchantOrderReference|No|All|A reference, maximum of 255 characters, of the order associated with this payment|255| |description|No|All|A description to show the customer|255| |webhookUrl|No|All|The [webhook](#webhooks) URL invoked for transaction changes. This overrides the merchant webhook if one is present. We do not validate this url|2000| |issuer|No|`ideal`|The issuer chosen by the customer. If not entered, the customer will be presented with a payment page to choose the issuer. Possible values: see [List all methods](#list-all-methods) |255| |brand|No|`card`| The card brand chosen by the customer . Possible values: [Supported Brands](#supported-brands)|n/a| |tokenize|No|`card`|Return a token calculated from the PAN or IBAN, depending on the payment method. Possible values: `yes`, `no`. Default: `no`|3| |storeInVault|No|`card`|Stores the relevant data used in this transaction in the vault for later use. At this moment only supported for method `card`. Possible values: `yes`, `no`. Default: `no`|3| |billingAddress|No|All|The billing street address|255| |billingCity|No|All|The billing city of the customer|255| |billingState|No|All|The billing region/state of the customer|255| |billingPostalCode|No|All|The billing postal (zip) code of the customer|255| |billingCountry|No|All|The billing country of the customer, an ISO 3166 alpha-2 code. See for more info: [Country Codes - ISO 3166](http://www.iso.org/iso/home/standards/country_codes.htm). For value `BE` and method `banktransfer` customers will receive an appropriate bank account number and structured reference|2| |billingEmail|Conditional|`banktransfer`|The billing email of the customer. Required when method is `banktransfer` and then defines the email to send the payment instructions to|255| |billingPhoneNumber|No|All|The billing phone number of the customer|255| |billingFirstName|No|All|The billing first name of the customer|255| |billingLastName|No|All|The billing last name of the customer|255| |billingHouseNumber|No|All|The billing house number of the customer|255| |billingHouseExtension|No|All|The billing house extension of the customer|255| |shippingAddress|No|All|The shipping street address|255| |shippingCity|No|All|The shipping address city|255| |shippingState|No|All|The shipping address region/state|255| |shippingPostalCode|No|All|The shipping address postal (zip) code|255| |shippingCountry|No|All|The shipping address country, an ISO 3166 alpha-2 code|2| |shippingEmail|No|All|The shipping email of the customer|255| |shippingPhoneNumber|No|All|The shipping phone number of the customer|255| |shippingFirstName|No|All|The shipping first name of the customer|255| |shippingLastName|No|All|The shipping last name of the customer|255| |shippingHouseNumber|No|All|The shipping house number of the customer|255| |shippingHouseExtension|No|All|The shipping house extension of the customer|255| |transactionType|No|All|Indication of TransactionType. Possible values: `sale`, `credit`, `authorise`. Default `sale`. Note that `authorise` and `credit` only apply to `card` payments. `credit` is not supported for brand `bcmc`|n/a| |details|Conditional|All|A details object which includes method specific details. Possible values: [Method Request Details](#method-request-details)|n/a| |userAuthenticationMethods|No|`card`|Optional list of authentication methods performed by the cardholder in case Vault Access Token is used: Possible values: [User Authentication Method](#user-authentication-method)|n/a| |sequenceType|No|`card`|Optional field indicating the sequence type of the transaction in case Vault Access Token is used: Possible values: [Sequence Type](#sequence-type)|n/a| *Example* ```json { "amount" : 316.35, "currency" : "eur", "method" : "card", "returnUrl" : "http://shop/?order=8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "metadata" : "my custom metadata", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Payment description", "language" : "eng", "tokenize" : "yes" } ``` #### Method Request Details * [LandingPage Request Details](#landingpage-request-details) * [BankTransfer Request Details](#banktransfer-request-details) * [Card Request Details](#card-request-details) * [Giropay Request Details](#giropay-request-details) * [Terminal Request Details](#terminal-request-details) * [Vault Request Details](#vault-request-details) ##### LandingPage Request Details These details are possible for a payment using the method `landingpage`. | Name | Required | Description | Max Length | |------|----------|-------------|------------| |expirationDuration|No|The time until payment expiration in [ISO 8601 Duration](https://en.wikipedia.org/wiki/ISO_8601#Durations). Defaults to a maximum of `P2M1D`|20| |mail|No|A boolean value that indicates to mail the payment instructions for `banktransfer` payments. Defaults to `true`|5| *Example* ```json { "amount" : 0.1, "currency" : "EUR", "method" : "landingpage", "returnUrl" : "http://shop/?order=8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "metadata" : "my custom metadata", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Payment description", "language" : "eng", "details" : { "expirationDuration" : "P0Y2M1DT0H0M0.000S" } } ``` ##### BankTransfer Request Details These details are possible for a payment using the method `banktransfer`. | Name | Required | Description | Max Length | |------|----------|-------------|------------| |expirationDuration|No|The time until payment expiration in [ISO 8601 Duration](https://en.wikipedia.org/wiki/ISO_8601#Durations). Defaults to a maximum of `P12D`|20| |mail|No|A boolean value that indicates to mail the payment instructions. Defaults to `true`|5| |mailReminderDuration|No|The time until to mail a payment reminder in [ISO 8601 Duration](https://en.wikipedia.org/wiki/ISO_8601#Durations). Defaults to a maximum of `P7D` and should be lesser than `expirationDuration`|20| *Example* ```json { "amount" : 0.1, "currency" : "EUR", "method" : "banktransfer", "returnUrl" : "http://shop/?order=8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "metadata" : "my custom metadata", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Payment description", "language" : "eng", "billingEmail" : "youremail@email.com", "details" : { "expirationDuration" : "P0Y0M12DT0H0M0.000S", "mail" : true, "mailReminderDuration" : "P0Y0M7DT0H0M0.000S" } } ``` ##### Giropay Request Details These details are possible for a payment using the method `giropay`. | Name | Required | Description | Max Length | |------|----------|-------------|------------| |bic|Yes|The BIC number of the bank of the customer.|255| |iban|No|The IBAN number of the customer.|255| *Example* ```json { "amount" : 0.1, "currency" : "EUR", "method" : "giropay", "returnUrl" : "http://shop/?order=8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "metadata" : "my custom metadata", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Payment description", "language" : "eng", "billingEmail" : "youremail@email.com", "details" : { "iban" : "DE89370400440532013000", "bic" : "TESTDETT310" } } ``` ##### Card Request Details When sending card data directly, you need to ensure you are PCI compliant. If you don't want to handle card data on your own servers, this scenario is not suited for you. See the [examples](#examples) to learn more about what our API has to offer. | Name | Required | Description | Max Length| |------|----------|-------------|-----------| |pan|Yes|The primary account number. All spaces and dashes are removed|19| |expiryDate|Yes|The expiry date of the card. Format: `MMyy` or `MMyyyy`. Example: `0219` or `022019` are both February 2019|6| |cardholderFirstName|Yes|The first name of the cardholder|255| |cardholderLastName|Yes|The last name of the cardholder|255| |cvc|Conditional|The CVC/CVV2 security code of the card. Only required if `transactionType = sale` or `transactionType = credit` and brand is **not** `bcmc`. When a vaultAccessToken is used, the cvc code is optional and depending on configuration.|4| |vaultAccessToken|Conditional| The Vault Access Token that has valid data card stored in the vault. Only required if `transactionType = sale` |40| *Example* ```json { "amount" : 0.1, "currency" : "EUR", "method" : "card", "returnUrl" : "http://shop/?order=8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "metadata" : "my custom metadata", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Payment description", "language" : "eng", "details": { "pan": "67032222222222227", "expiryDate": "1220", "cardholderFirstName": "testName", "cardholderLastName": "testLastName" } } ``` ##### Terminal Request Details | Name | Required | Description | Max Length | |------|----------|-------------|------------| |terminalId| Yes | The terminal id as assigned by CCV |20| |managementSystemId | Yes | The management system id of this terminal as assigned by CCV |50| |accessProtocol | Yes | The communication protocol between the terminal and access server |20| |ip| Yes | The browser accessible IP of the terminal for initiating the wake up |50| |port| Yes | The browser accessible port of the terminal's socket handling HTTP calls |5| |operatingEnvironment| Yes | The environment in which the terminal is operating. Possible values: `ATTENDED` and `SEMI_UNATTENDED`. Defaults to `SEMI_UNATTENDED` when empty. |20| |merchantLanguage| Yes/No | The language of the merchant, used to change the language in which the intermediate page is displayed in `ATTENDED` operatingEnvironments. Required when operatingEnvironment is `ATTENDED`, Not required otherwise.|3| *Example* ```json { "amount" : 0.1, "currency" : "EUR", "method" : "TERMINAL", "returnUrl" : "http://shop/?order=3857c68a-f43d-473c-b2ac-2c826bba175a", "metadata" : "{'order': '3857c68a-f43d-473c-b2ac-2c826bba175a', 'datetime': 1491207703113}", "merchantOrderReference" : "3857c68a-f43d-473c-b2ac-2c826bba175a", "description" : "API Payment description for order 3857c68a-f43d-473c-b2ac-2c826bba175a", "language" : "NLD", "details" : { "port" : 6235, "managementSystemId" : "000103030", "ip" : "127.0.0.1", "terminalId" : "1234536", "accessProtocol" : "OPI_NL", "operatingEnvironment" : "ATTENDED", "merchantLanguage" : "NLD" } } ``` ##### Vault Request Details When a payment is initiated with a [Vault Access Token](#vault-access-token), the data stored in the vault with this Access Token must be usable for the method indicated. For example, when the method `card` is used, the Vault Access Token must have card data stored. | Name | Required | Description | Max Length | |------|----------|-------------|------------| |vaultAccessToken| Yes | The Vault Access Token that has valid data stored in the vault. |40| *Example* ```json { "amount" : 0.1, "currency" : "EUR", "method" : "card", "returnUrl" : "http://shop/?order=8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "metadata" : "my custom metadata", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Payment description", "language" : "eng", "details": { "vaultAccessToken" : "5C810B0AD0B1BC0926EBEA53" } } ``` #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: [Payment](#payment) ### Refund an existing payment Refunds are allowed for all existing payment methods, except `LandingPage`, `Terminal`, `Token` and `Vault`. * Full refunds and partial refunds are supported * For some payment methods, refunds above the original amount may be accepted * For some payment methods, we apply balance calculations per day. This allows you to refund as much as you earned that day. If your balance is insufficient, the transaction is denied with failure code `UNSUFFICIENT_BALANCE` #### Refund | Name | Description | |------|-------------| |type|Fixed value: `refund`| |amount|The refund amount| |currency|Echo from the [Payment](#payment)| |status|Possible values: [Transaction Status](#transaction-status)| |paidout|A boolean value that indicates if this transaction has been paid out. Only available for [collecting protocols](#collecting-payments). Possible values: `yes` or `no`| |paidoutDate|The date when the payment to the customer was done. Only valid for collecting protocols.| |merchantOrderReference|Echo from the [Payment](#payment)| |description|A description of the transaction| |language|Echo from the [Payment](#payment)| |method|Echo from the [Payment](#payment)| |brand|Echo from the [Payment](#payment)| |metadata|Echo from the [Payment](#payment)| |reference|A unique reference for the refund transaction| |unstructuredReference|The unstructured reference used when performing the payout to the merchant. Only valid for collecting protocols| |paidoutReference|The reference used when performing the payout to the customer. This can be used to look up transaction related to that payout. Only valid for collecting protocols| |created|The local server datetime the refund was created, epoch timestamp| |lastUpdate|The local server datetime the refund was updated, epoch timestamp| |failureCode|An error code indication what caused the failure. Possible values: [Failure Codes](#failure-codes)| #### Request * Resource: `/api/v1/refund` * Method: `POST` * Content-Type: `application/json` * Authentication: **Required** * Supports [idempotency](#idempotency) * Parameters |Name|Required|Description| Max Length| |----|--------|-----------|-----------| |reference|Yes|The unique reference of the payment to refund|255| |description|No|The description of the refund. If not provided we use the original payment description|255| |amount|No|The amount to refund. If not provided we use the original payment amount. The [currency](#currencies) used will be the currency of the original payment and the format must be the same|19+2| |webhookUrl|No|The [webhook](#webhooks) URL invoked for transaction changes. This overrides the merchant webhook if one is present. We do not validate this url|2000| *Example* ```json { "reference": "C1505181754007360.1", "description": "API Refund Description" } ``` #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: [Refund](#refund) *Example* ```json { "type" : "refund", "amount" : 316.35, "currency" : "eur", "status" : "PENDING", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Refund Description", "language" : "eng", "method" : "card", "metadata" : "my custom metadata", "reference" : "C1505181613078800.1", "brand" : "visa", "created" : 1431958387914, "lastUpdate" : 1431958387914 } ``` ### Capture an existing authorisation An existing authorise can be captured using this resource. #### Capture | Name | Description | |------|-------------| |type|Fixed value: `capture`| |amount|The capture amount| |currency|Echo from the [Payment](#payment)| |status|Possible values: [Transaction Status](#transaction-status)| |paidout|A boolean value that indicates if this transaction has been paid out. Only available for [collecting protocols](#collecting-payments). Possible values: `yes` or `no`| |paidoutDate|The date on which the payment to the merchant was done. Only available for [Collecting Payments](#collecting-payments)| |merchantOrderReference|Echo from the [Payment](#payment)| |description|The description of the transaction| |language|Echo from the [Payment](#payment)| |method|Echo from the [Payment](#payment)| |brand|Echo from the [Payment](#payment)| |metadata|Echo from the [Payment](#payment)| |reference|A unique reference for the capture transaction| |unstructuredReference|The unstructured reference used when performing the payout to the merchant. Only available for [Collecting Payments](#collecting-payments)| |paidoutReference|The reference used when performing the payout to the merchant. This can be used to look up a transaction related to that payout. Only available for [Collecting Payments](#collecting-payments) |created|The local server datetime the capture was created, epoch timestamp| |lastUpdate|The local server datetime the capture was updated, epoch timestamp| |failureCode|An error code indication what caused the failure. Possible values: [Failure Codes](#failure-codes)| #### Request * Resource: `/api/v1/capture` * Method: `POST` * Content-Type: `application/json` * Authentication: **Required** * Supports [idempotency](#idempotency) * Parameters |Name|Required|Description|Max Length| |----|--------|-----------|----------| |reference|Yes|The unique reference of the payment to capture|255| |description|No|The description of the capture. If not provided we use the original payment description|255| |amount|No|The amount to capture. If not provided we use the original payment amount. The [currency](#currencies) used will be the currency of the original payment and the format must be the same|19+2| |webhookUrl|No|The [webhook](#webhooks) URL invoked for transaction changes. This overrides the merchant webhook if one is present. We do not validate this url|2000| *Example* ```json { "reference": "C1505181754007360.1", "description": "API Capture Description" } ``` #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: [Capture](#capture) *Example* ```json { "type" : "capture", "amount" : 316.35, "currency" : "eur", "status" : "PENDING", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Capture Description", "language" : "eng", "method" : "card", "metadata" : "my custom metadata", "reference" : "C1505181613078800.1", "brand" : "visa", "created" : 1431958387914, "lastUpdate" : 1431958387914 } ``` ### Reverse an existing authorisation The funds reserved with an authorisation can be released with a reversal. Note: only transactions of type `authorise` and method `card` can be reversed. #### Reversal | Name | Description | |------|-------------| |type|Fixed value: `reversal`| |amount|Echo from the [Payment](#payment)| |currency|Echo from the [Payment](#payment)| |status|Possible values: [Transaction Status](#transaction-status)| |merchantOrderReference|Echo from the [Payment](#payment)| |description|The description of the transaction| |language|Echo from the [Payment](#payment)| |method|Echo from the [Payment](#payment)| |brand|Echo from the [Payment](#payment)| |metadata|Echo from the [Payment](#payment)| |reference|A unique reference for the reversal transaction| |methodTransactionId|A third party transaction ID which identifies the payment transaction in external systems. If empty no such id was available or no third party was employed| |created|The local server datetime the reversal was created, epoch timestamp| |lastUpdate|The local server datetime the reversal was updated, epoch timestamp| |failureCode|An error code indication what caused the failure. Possible values: [Failure Codes](#failure-codes)| #### Request * Resource: `/api/v1/reversal` * Method: `POST` * Content-Type: `application/json` * Authentication: **Required** * Supports [idempotency](#idempotency) * Parameters |Name|Required|Description|Max Length| |----|--------|-----------|----------| |reference|Yes|The unique reference of the payment to reverse|255| |description|No|The description of the reversal. If not provided we use the original payment description|255| |webhookUrl|No|The [webhook](#webhooks) URL invoked for transaction changes. This overrides the merchant webhook if one is present. We do not validate this url|2000| *Example* ```json { "reference": "C1505181754007360.1", "description": "API Reversal Description" } ``` #### Response * Status Code: `200` * Content: [Reversal](#reversal) *Example* ```json { "type" : "reversal", "amount" : 316.35, "currency" : "eur", "status" : "PENDING", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Reversal Description", "language" : "eng", "method" : "card", "metadata" : "my custom metadata", "reference" : "C1505181613078800.1", "brand" : "visa", "created" : 1431958387914, "lastUpdate" : 1431958387914 } ``` ### Cancel a payment When it is possible to cancel a payment, a `cancelUrl` will be included in the payment entity. #### Methods supporting cancel | Name | API name | |------|-----------| | Card | card | | Payconiq | payconiq | | OK.APP | okit | Note that a `cancelUrl` can only be used successfully up to a certain point, and a cancellation could fail because it's too late to cancel. This will result in a rejection of the cancellation, and no change in the payment process. #### Request * Resource: `cancelUrl` * Method: `POST` * Content-Type: `application/json` * Authentication: **Required** #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: If the cancel was allowed, the system will return a `200 - OK` status code. If the cancel was not allowed, the system will return a `400 - Bad Request` status code, and return an error as described in [Error Handling](#error-handling). ## Transaction ### Read a transaction #### Transaction A transaction can be a Payment (Sale, Credit, Authorise), Refund, Capture, Token or Vault transaction depending on the type. #### Request * Resource: `/api/v1/transaction?reference={reference}` * Method: `GET` * Authentication: **Required** * Parameters: `reference`: The unique reference of the transaction, max 255 #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: [Payment](#payment) or [Refund](#refund) or [Capture](#capture) or [Reversal](#reversal) or [Token](#token) or [Vault Access Token](#vault-access-token) ### Read a collection of transactions by query #### Request * Resource: `/api/v1/transaction` * Method: `GET` * Authentication: **Required** * Parameters |Name|Required|Description| |----|--------|-----------| |referenceBefore|No|Returns previous payments before this reference | |referenceAfter|No|Returns next payments after this reference| |references|No|Returns the payments that have a references in this list. Example value: reference1,reference2,..| |merchantOrderReference|No|Returns payments with the exact same merchant order reference| |createdBefore|No|Returns payments created before this timestamp, excluding payments with this create timestamp| |createdAfter|No|Returns payments created after this timestamp, excluding payments with this create timestamp| |amountMinimum|No|Returns payments with the same or a greater amount| |amountMaximum|No|Returns payments with the same or a smaller amount| |type|No|Returns payments with the same type. Possible values: `sale`, `refund`, `token`, `credit`, `authorise`, `capture` or `vault`| |method|No|Returns payments with the same method. Possible values: [Supported Methods](#supported-methods)| |status|No|Returns payments with the same status. Possible values: [Transaction Status](#transaction-status)| |paidout|No|Returns payments with the same paidout status. This can be `yes` for all payments, `no` for transactions that are not yet paid out, and `never` for transactions that are not collecting. Possible values: `yes`, `no`, or `never`| |unstructuredReference|No|Returns payments with the same collector payment reference. Only valid for collecting protocols| |paidoutReference|No|Returns the transactions related to that paidoutReference. Can be used to find the transactions that form the payment to the merchant. Only valid for collecting protocols| |orderBy|No|Returns payments ordered by a property. Possible values: `reference`, `created` or `amount`, default: `created`| |order|No|Returns payments ordered by the direction. Possible values: `asc` or `desc`, default: `desc`| |count|No|Limits the returned payments to the count. Default & maximum: 500| **Note**: We do not support paging using a _page_ parameter but provide parameters to implement a sliding window. If the response list has the same count as you requested, you may request the next page by using the referenceBefore or the referenceAfter with the data of the first or last item in the list respectively. #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: A JSON array of [Transactions](#transaction) *Example* ```bash # First 100 transactions created after 2015/01/01 01:01:01.000, sorted ascending curl https://redirect.jforce.be/api/v1/transaction?createdAfter=1420074061000&count=100&order=asc -u apikey: ``` ```json [ { "type" : "sale", "amount" : 316.35, "currency" : "eur", "status" : "success", "merchantOrderReference" : "CFED8B1C8B9F292500E2E837767900BF2448EE28", "description" : "A description for an order", "language" : "eng", "method" : "card", "brand" : "visa", "metadata" : "CFED8B1C8B9F292500E2E837767900BF2448EE28", "returnUrl" : "http://shop?order=CFED8B1C8B9F292500E2E837767900BF2448EE28", "entryMode" : "ecom", "reference" : "AC130090D6C19A09CD4B8B3EECCE199AD895B6E0", "created" : 1420106400000, "lastUpdate" : 1420106700000 }, { "type" : "sale", "amount" : 316.35, "currency" : "eur", "status" : "success", "paidout" : "yes", "merchantOrderReference" : "f1699892-25eb-4c1c-9cc3-3e345ccc1cec", "description" : "A description for an order", "language" : "nld", "method" : "ideal", "metadata" : "I1506151348179039.1", "reference" : "I1506151348179039.1", "created" : 1434368898588, "lastUpdate" : 1434368901391, "payUrl" : "https://idealtest.secure-ing.com/ideal/issuerSim.do?trxid=0050000101228409&ideal=prob", "returnUrl" : "http://shop?order=f1699892-25eb-4c1c-9cc3-3e345ccc1cec", "entryMode" : "ecom" } ] ``` *Second Example* ```bash # Payments with references: C1507300954022980.1,C1507300955272271.1,I1507301136243800.1,I1507301136354361.1 curl https://redirect.jforce.be/api/v1/transaction?references=C1507300954022980.1,C1507300955272271.1,I1507301136243800.1,I1507301136354361.1 -u apikey: ``` ```json [ { "type" : "sale", "amount" : 0.40, "currency" : "eur", "status" : "success", "merchantOrderReference" : "ca47e7aa-5d57-42e3-bb53-532006c93d9c", "description" : "API Payment description", "language" : "nld", "method" : "ideal", "metadata" : "ca47e7aa-5d57-42e3-bb53-532006c93d9c", "reference" : "I1507301136354361.1", "created" : 1438248996081, "lastUpdate" : 1438249968771, "payUrl" : "https://redirect.jforce.be", "returnUrl" : "http://shop?order=f1699892-25eb-4c1c-9cc3-3e345ccc1cec", "entryMode" : "ecom", "paidout" : "yes", "unstructuredReference" : "AFREK. CPSPi BCMC DAT. 20150730/5211 AANT. 2 MREF. Joury Gokel" }, { "type" : "sale", "amount" : 0.20, "currency" : "eur", "status" : "success", "merchantOrderReference" : "e3c56b80-c97c-48b7-91ec-67262e99c628", "description" : "API Payment description", "language" : "nld", "method" : "ideal", "metadata" : "e3c56b80-c97c-48b7-91ec-67262e99c628", "reference" : "I1507301136243800.1", "created" : 1438248985129, "lastUpdate" : 1438249968768, "payUrl" : "https://redirect.jforce.be", "returnUrl" : "http://shop?order=f1699892-25eb-4c1c-9cc3-3e345ccc1cec", "entryMode" : "ecom", "paidout" : "yes", "unstructuredReference" : "AFREK. CPSPi BCMC DAT. 20150730/5211 AANT. 2 MREF. Joury Gokel" }, { "type" : "sale", "amount" : 0.15, "currency" : "eur", "status" : "success", "merchantOrderReference" : "0c01096f-4122-4dd9-be49-5872a1fb91ad", "description" : "API Payment description", "language" : "nld", "method" : "card", "metadata" : "0c01096f-4122-4dd9-be49-5872a1fb91ad", "reference" : "C1507300955272271.1", "created" : 1438242927232, "lastUpdate" : 1438246838175, "payUrl" : "https://redirect.jforce.be", "returnUrl" : "http://shop?order=f1699892-25eb-4c1c-9cc3-3e345ccc1cec", "entryMode" : "ecom", "brand" : "bcmc", "token" : "93333333333333076", "tokenMaskedInput" : "4111XXXXXXXX1111", "paidout" : "yes", "unstructuredReference" : "AFREK. CPSPi BCMC DAT. 20150730/5211 AANT. 1 MREF. Joury Gokel" }, { "type" : "sale", "amount" : 316.35, "currency" : "eur", "status" : "pending", "merchantOrderReference" : "0c01096f-4122-4dd9-be49-5872a1fb91ad", "description" : "API Payment description", "language" : "nld", "method" : "card", "metadata" : "0c01096f-4122-4dd9-be49-5872a1fb91ad", "reference" : "C1507300954022980.1", "created" : 1438242842320, "lastUpdate" : 1438242842320, "payUrl" : "https://redirect.jforce.be", "returnUrl" : "http://shop?order=f1699892-25eb-4c1c-9cc3-3e345ccc1cec", "entryMode" : "ecom", "token" : "PENDING" } ] ``` ### Manually approve or reject a transaction Payments are scanned for fraudulent activity and if a payment is seen as suspicious, it will be flagged, meaning manual approval is required. This is exposed in the payment status with the `manualApprovalRequired` field set to `true`. A transaction in this situation will remain pending until it is either manually approved or rejected by contacting support. Upon confirmation: * If the transaction is approved, processing will continue * If the transaction is rejected, the status is updated to `FAILED` and the failure code is set to `REJECTED` The transaction processing is an asynchronous process and will update the status after an undetermined time. If you have webhooks configured, you'll be notified accordingly. If not, you should poll the transaction until a final status is reached. #### Request * Resource: `/api/v1/transaction/confirm` * Method: `POST` * Content-Type: `application/json` * Authentication: **Required** * Parameters | Name | Required | Description | |------|----------|-------------| |reference|Yes|The transaction to approve| |note|Yes|A text message that will be attached to the transaction| |action|Yes|Possible values: `approve` or `reject`| *Example* ```json { "reference" : "C1507301136356120.1", "note" : "This transaction was considered OK after manual inspection", "action" : "accept" } ``` #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: No content ### Export transactions as MT940 #### MT940 format We support export of [successfully](#transaction-status) completed transactions in ING's MT940-format. The [operating Mode](#operating-mode) of the [Api Key](#api-keys) used decides if the export will contain TEST or LIVE transactions.
An MT940 Customer Statement Message is a message standard for electronic account statements from the Society for Worldwide Interbank Financial Telecommunication (SWIFT). ING MT940 format is based on the standard of SWIFT FIN: Category 9 Cash Management and Customer Status. Many software process the data structured according to this international standard. With this guide, you can deploy the MT940 format itself into your systems.

-- Mijn ING Zakelijk [Download](https://redirect.jforce.be/api/v1/doc/transaction/export/MT940_ING_NL.pdf)
Mapping of Tag 61 subfields with our transaction details. |Subfield|Length|Content|Mapping|Example| |--------|------|-------|-------|-------| |Valuta date|6!n|YYMMDD|Create date|`150930`| |Booking date|4!n|MMDD|If paid out the paid out date, else create date|`0930`| |Credit/Debit|1!x|C or D|type|Sale:`C` or Refund:`D`| |Amount|15n|Transaction amount|Amount|`10.99`| |Transaction type|4!x|The SWIFT transaction code is used and starts with "N" followed by a transaction type. SWIFT Transaction types are available in the attachments|Fixed value: Transfer|`NTRF`| |Payment reference|16x|The payment reference is derived from the transaction during processing. If no payment reference is available, "NONREF" is used|If available your merchant order reference, else `NONREF`|`Order 1234`| |Transaction reference|16!x|Starts with "//" followed by a unique ING reference (14 characters)|If available the paid out reference, else 00000000000000|`//00000000000000`| |Additional details|34x|/TRCD// (See attachments for ING transaction codes)|Fixed value: SEPA Credit Transfer|`/TRCD/00100`| Example ``` :61:1509280928C316,35NTRF1091fbae-c4f7-45//00000000000000 /TRCD/00100/ ``` Mapping of Tag 86 code words with our transaction details. |Code word|Description|Length|Mapping|Example| |---------|-----------|------|-------|-------| |`/EREF/`|End to End reference|35x|Transaction reference|`EREF/I15092816080395614.1/`| |`/CNTP/`|Counterpart ID|131x|If available customer name & customer city|`CNTP///John Doe/Brussel/`| |`/REMI/`|Remittance info|max 255x|Contains custom tags `/MOP/` and `/TXDATE/`. If available the unstructured reference used to collect the sale or pay the refund is prefixed|`REMI/USTD//0ad76e30 AFREK. CPSPi BCMC DAT. 20150923/5266 AANT. 1 MREF. CCV Demo/`| In addition to these tags which are part of the MT940 spec, the remittance info contains custom tags to facilitate parsing useful information about the transaction. |Code word|Description|Length|Mapping|Example| |---------|-----------|------|-------|-------| |`/MOP/`|Method of Payment|3x - 12x|Will contain the payment method or in case of method card the brand. Always uppercase|`/MOP/IDEAL`| |`/TXDATE/`|Transaction date|15x|Contains he creation date of the transaction in format 'YYYYMMDD HHMMSS'|`/TXDATE/20190514 071433`| Example ``` :86:/EREF/I15092816080395614.1/ ``` #### Request * Resource: `/api/v1/transaction/export/mt940` * Method: `GET` * Authentication: **Required** * Parameters |Name|Required|Description| |----|--------|-----------| |from|Conditional|Returns payments created after this timestamp, including payments with this create timestamp. Must be used with until.| |until|Conditional|Returns payments created before this timestamp, excluding payments with this create timestamp. Must be used with from.| |paidoutAfter|Conditional|Returns payments paidout after this timestamp, including payments with this paidout timestamp. Must be used with paidoutBefore.| |paidoutBefore|Conditional|Returns payments paidout before this timestamp, excluding payments with this paidout timestamp. Must be used with paidoutAfter.| |currency|No|Returns payments with the same currency. Possible values: [Currencies](#currencies). Defaults to `EUR`| |customIban|No|This value will override your user's merchant IBAN in the resulting file (if present and not empty)| *Example* ``` {1:F01INGBNL2ABXXX0000000000}{2:I940INGBNL2ABXXXN}{4: :20:0001461842521445 :25:GE62510007547061EUR :28C:00000 :60F:C160428EUR0 :62F:C160428EUR0 :64:C160428EUR0 :65:C160428EUR0 :86:/SUM/0/0/0/0/ ``` ## Method ### Supported Methods We support the following payment methods: - Cards (Debit or Credit) - iDEAL - Sofort - PayPal - Giropay - BankTransfer - Terminal - Payconiq - EPS - OK.APP Additionally our [Landing Page](#landing-page) method allows the customer to select a method of choice. The keys for these are respectively `card`, `ideal`, `sofort`, `paypal`, `giropay`, `banktransfer`, `terminal`, `payconiq`, `eps`, `okit` and `landingpage`. #### Landing Page A payment method where we provide the payment method selection for you. After you create a landing page transaction, a customer can create a child transaction via the landing page form (where a [method](#method) can be selected). This transaction can be retrieved [using the childReferenceId value](#read-a-transaction). A landing page transaction can have multiple attempts which may result in a child transaction. When a child transaction reaches a final [transaction status](#transaction-status) such as `success` or `manualintervention`, the landing page (parent) transaction will be updated with the same status. ##### Flow The general flow will be: 1. You create a `landingpage` payment. 2. The customer reaches the landing page, chooses a payment method, makes the payment and returns to your shop. 3. We give feedback about status changes using [Webhooks](#webhooks). When the payment of the chosen method fails within 30 seconds, the customer can retry again using possibly another method. The default expiration duration is `P2M`, which means: - The customer will be redirected to your shop after this duration. For example, when he opens the payment link again. - We start marking the payment as `expired` one day later. You will be notified with a webhook when the payment eventually expired. ### List all methods #### List The list is a JSON array containing an item per method. Each item contains the method name and method specific options. #### Request * Resource: `/api/v1/method` * Method: `GET` * Authentication: **Required** #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` *Example* ```bash curl https://redirect.jforce.be/api/v1/method -u apikey: ``` ```json [ { "method": "card", "options": [ { "brand": "visa" }, { "brand": "mastercard" }, { "brand": "maestro" }, { "brand": "bcmc" } ] }, { "method": "eps" }, { "method": "okit" }, { "method": "ideal", "options": [ { "group": "Nederland", "grouptype": "country", "issuerdescription": "Issuer Simulation V3 - ING", "issuerid": "INGBNL2A" }, { "group": "Nederland", "grouptype": "country", "issuerdescription": "Issuer Simulation V3 - RABO", "issuerid": "RABONL2U" } ] }, { "method": "sofort" }, { "method": "paypal" }, { "method": "landingpage" }, { "method": "banktransfer" }, { "method": "giropay", "options": [ { "issuerdescription": "Test HBCI PIN/TAN Institut III", "issuerid": "TESTDETT310" }, { "issuerdescription": "Deutsche Bank Fil Berlin", "issuerid": "DEUTDEDBBER" } ] }, { "method": "payconiq", "options": [ { "qr" : "true" } ] } ] ``` ##### Card | Name | Description | |------|-------------| |method|Fixed value: `card`| |options|An array of specific options for the card method| |options[x].brand|Possible values: [Supported Brands](#supported-brands) | |options[x].qr|If payment via QR code is possible. Only shown as `true` when possible.| ###### Supported Brands | Name | API name | |------|-----------| | Visa | visa | | MasterCard | mastercard | | Maestro | maestro | | Bancontact| bcmc | | American Express | amex | ##### iDEAL iDEAL specifications require you to group the issuers. You should group the items with the same `group`, as required by the iDEAL specification (version 3.3.1). This is currently by country. | Name | Description | |------|-------------| |method|Fixed value: `ideal`| |options|An array of specific options for the iDEAL method| |options[x].group|Contains the group specifier, such as for example the country names in the official languages of the country, separated by a '/' (e.g. 'Belgi?/Belgique')| |options[x].grouptype|Specifies the type of group, currently fixed value: `country`| |options[x].issuerdescription|The description of the issuer (as this should be displayed to the customer in the merchant's issuer list, e.g. 'ABN AMRO')| |options[x].issuerid|Unique identifier of the issuer used within iDEAL| ##### Rendering of the issuers *iDEAL Merchant Integration Guide 3.3.1, 4.4 Directoryprotocol* > To ensure that the customer experience of an iDEAL transaction is consistent and recognizable through all Merchant websites; all merchants have to comply with certain presentation standards. These are the guidelines from iDEAL: 1. Show the issuers in a dropdown 2. The first option must be 'Choose your bank...' 3. The first option must be selected by default 4. The first country must be the first entry from the options array: it will be the preferred country of the merchant or the country of the customer (if known) 5. The list of issuers for the same group are ordered alphabetically (like in the response) 7. The merchant should handle the selection of the 'Choose your bank' or 'Country x' correctly as an error. *Example* <select> <option>Choose your bank...</option> <option>Nederland</option> <option>ABN AMRO</option> <option>ASN Bank</option> <option>Belgi?/Belgique</option> <option>Argenta</option> <option>KBC</option> </select> ##### Sofort | Name | Description | |------|-------------| |method|Fixed value: `sofort`| Sofort currently has no options. ##### PayPal | Name | Description | |------|-------------| |method|Fixed value: `paypal`| PayPal currently has no options. ##### LandingPage | Name | Description | |------|-------------| |method|Fixed value: `landingpage`| LandingPage currently has no options. ##### BankTransfer | Name | Description | |------|-------------| |method|Fixed value: `banktransfer`| BankTransfer currently has no options. ##### GiroPay | Name | Description | |------|-------------| |method|Fixed value: `giropay`| |options|An array of specific options for the GiroPay method| |options[x].issuerdescription|The description of the issuer (as this should be displayed to the customer in the merchant's issuer list, e.g. 'Deutsche Bank').| |options[x].issuerid|Unique identifier of the issuer used within GiroPay.| ##### Terminal | Name | Description | |------|-------------| |method|Fixed value: `terminal`| Terminal currently has no options. ##### Payconiq | Name | Description | |------|-------------| |method|Fixed value: `payconiq`| |qr|If payment via QR code is possible. Only shown as `true` when possible.| ##### EPS | Name | Description | |------|-------------| |method|Fixed value: `eps`| EPS currently has no options. ##### OK.APP | Name | Description | |------|-------------| |method|Fixed value: `okit`| OK.APP currently has no options. ## Status ### Status | Name | Description | |------|-------------| |app.name|The name of the application| |app.version|The current version of the application| |server.localtime|The current datetime of the server, epoch timestamp| ### Get Status A simple endpoint to query for the status of the VPOS. The execution will **not** check for the status of the payment methods. To get an indication of what methods are available, see the [Method](#method) resource. #### Request * Resource: `/api/v1/status` * Method: `GET` * Authentication: **Not** Required #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: [Status](#status) *Example* ```bash curl https://redirect.jforce.be/api/v1/method -u apikey: ``` ``` { "app": { "name": "VPOS", "version": "1.1" }, "server": { "localtime": 1420106400000 } } ``` ## Token A token resource represents a tokenized PAN or IBAN. **Note:** if you call the token resource in operating mode *TEST*, you will not get a real token. The simulated token contains the reversed pan with a prefix and should not be used to store in a production system. #### Flow The general flow is: 1. You [create a new token](#create-a-new-token-request) 2. Redirect the customer to us 3. We ask for the PAN or IBAN in order to calculate the token 4. When the calculation is done, we redirect the customer back to your shop 5. You [read a token](#read-a-token) to get the token. #### Status Verification We do not expose the token to the customer. It is up to you to verify the status of the token request and act accordingly. [Webhooks](#webhooks) are provided to give you feedback, but this principle remains. #### Token types Two types of token are supported, being `card` tokens and `web` tokens. ##### Card Token A `card` token is a token calculated from the complete PAN of a credit or debit card. This token will always consist of the prefix `99` followed by 16 characters given a token of 18 characters long. *Example* ```991234567890123456``` ##### Web Token A `web` token is calculated on (part of) the IBAN of a debit card. Reason for this addition to the Token Service Provider is that there are countries where the banks do no print the PAN on their debit cards. Examples are the Netherlands and Germany. ###### Netherlands For the Netherlands the IBAN is as follows *Example* ``` NL91ABNA0417164300 ``` * 2 char country code (`NL`) * 2 char check digits (`91`) * 4 char bank code (`ABNA`) * 10 char account number (`0417164300`) The NL Web Token is calculated using the 10 char account number and is prefixed with `96`. **Note:** The banks BUNQ and KNAB are not supported in the TSP. *Example* ```961234567890123456``` ###### Germany For Germany the IBAN is as follows *Example* ``` DE89370400440532013000 ``` * 2 char country code (`DE`) * 2 char check digits (`89`) * 8 char bank code (`37040044`) * 10 char account number (`0532013000`) The bank code needs to be converted to the institute number using the table from the Bundesbank Germany. The NL Web Token is calculated using the institute number and the account number and is always prefixed with `95`. ###### Others For other countries there is **no** token calculation based on IBAN is supported. #### Token *Definition* | Name | Description | |------|-------------| |type|Fixed value: `token`| |token|The token, a max 18 long string identifying the given PAN/IBAN| |tokenMaskedInput|If a token was created, the input (PAN or IBAN) will be returned, [masked](#masking).| |status|Possible values: [Transaction Status](#transaction-status)| |description|A description to show the customer| |language|The language of the customer. Possible values: `eng`, `nld`, `deu` or `fra`| |metadata|An arbitrary, max 255 long string that can be used to track payments| |payUrl|To complete the tokenization request the customer should be redirected to this URL.| |returnUrl|After tokenization is completed (successfully or otherwise) the customer is redirected to this URL| |reference|A unique reference for the tokenization request| |created|The local server datetime the tokenization request was created, epoch timestamp| |lastUpdate|The local server datetime the tokenization request was updated, epoch timestamp| |failureCode|An error code indication what caused the failure. Possible values: [Failure Codes](#failure-codes)| *Example* ```json { "type" : "token", "token" : "998171576462127534", "tokenMaskedInput" : "DE60xxxxxxxxxxxxxx6789", "status" : "success", "description" : "A token description", "language" : "eng", "metadata" : "CFED8B1C8B9F292500E2E837767900BF2448EE28", "reference" : "AC130090D6C19A09CD4B8B3EECCE199AD895B6E0", "created" : 1420106400000, "lastUpdate" : 1420106700000, "returnUrl" : "http://shop?order=CFED8B1C8B9F292500E2E837767900BF2448EE28" } ``` #### Create a new token request ##### Request * Resource: `/api/v1/token` * Method: `POST` * Content-Type: `application/json` * Authentication: **Required** * Parameters | Name | Required | Method | Description | |------|----------|--------|-------------| |returnUrl|Yes|All|The URL to redirect the customer to after completion of the tokenization request (both success and failure scenarios)| |metadata|No|All|An arbitrary, max 255 long string that can be used to track tokenization requests| |description|No|All|A description to show the customer| |language|Yes|All|The language of the customer. Possible values: `eng`, `nld`, `deu` or `fra`| |webhookUrl|No|All|The [webhook](#webhooks) URL invoked for transaction changes. This overrides the merchant webhook if one is present. We do not validate this url| |tokenType|No|All|The type of token that is requested. Possible values: `card` or `web`. Default is `card`| *Example* ```json { "returnUrl" : "http://shop?order=436D2D8278789F4B2D618E301C875708B58F7A82", "metadata" : "436D2D8278789F4B2D618E301C875708B58F7A82", "description" : "API token description", "language" : "eng", "tokenType" : "card" } ``` ##### Response ##### * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: [Token](#token) #### Read a token ##### Request * Resource: `/api/v1/token?reference={reference}` * Method: `GET` * Authentication: **Required** * Parameters: `reference`: The unique reference of the token request ##### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: [Token](#token) #### Create a new token from a PCI compliant environment If you have a PCI compliant environment you can also choose to transmit the sensitive PAN or IBAN information directly to obtain a token. Either the PAN or the IBAN should be filled in and a token will be calculated accordingly. #### Request * Resource: `/api/v1/token/pci` * Method: `POST` * Content-Type: `application/json` * Authentication: **Required** * Parameters | Name | Required | Description | |------|----------|-------------| |pan|No|The PAN, without spaces or any other separation characters, with a maximum of 19 characters| |iban|No|The IBAN, must be valid, without spaces or any other separation characters| |metadata|No|An arbitrary, max 255 long string that can be used to track token requests| *Example* ```bash curl https://redirect.jforce.be/api/v1/token/pci -u apikey: ``` ```json { "pan" : "6799998900000010062", "metadata" : "436D2D8278789F4B2D618E301C875708B58F7A82" } ``` #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: [Token](#token) ```json { "metadata": "436D2D8278789F4B2D618E301C875708B58F7A82", "reference": "T1506161514118975.1", "token": "995336783076747372", "tokenMaskedInput" : "6799xxxxxxxxxxx0062" } ``` ## Vault The vault resource can be used to store sensitive data in the vault that is contained within the VPOS. This data is stored in an encrypted form. When storing something in the vault, a Vault Access Token will be returned. This Vault Access Token is necessary to access the information again, or to perform actions with it in the rest of the VPOS API. After you create a vault transaction, a new payment is linked as its child transaction if you use the vaultAccessToken in your [request](#create-a-new-payment), and can be retrieved [using the childReferenceId value](#read-a-transaction). A vault transaction can have 1 child transaction. When the child transaction reaches a final [transaction status](#transaction-status) such as `success` or `manualintervention`, the vault (parent) transaction will be updated with the same status. Actions that can be done with the Vault Access Token at the moment are: 1. Retrieve plaintext content (e.g. pan data) 2. Execute payment (sale, authorize, credit, ...) with PAN data stored in the Vault. ### Flow The general flow is: 1. You [create a new vault request](#create-a-new-vault-request) 2. Redirect the customer to us 3. We ask to enter the data that is to be stored in our vault 4. After the data is entered and stored, we redirect the customer back to your shop 5. You [read the transaction](#read-a-transaction) to get the status and the Vault Access Token #### Status Verification We do not expose the status of the vault transaction or any of its details to the customer. It is up to you to verify the status of the vault transaction and act accordingly. [Webhooks](#webhooks) are provided to give you feedback, but this principle remains. ### Vault Access Token #### Transaction Definition [Vault Transaction] | Name | Description | |------|-------------| |status|Possible values: [Transaction Status](#transaction-status)| |merchantOrderReference|A reference, maximum 255 characters, of the order associated with this vault transaction| |description|A description to show the customer| |language|The language of the customer. Possible values: `eng`, `nld`, `deu` or `fra`| |method|Fixed value `vault`| |brand|The brand of the card that was entered by the user. Only included when the dataType is `card`| |metadata|An arbitrary string, maximum 255 characters, that can be used to track vault transactions| |payUrl|To complete the vault request the customer should be redirected to this URL.| |returnUrl|After vault data storage is completed (successfully or otherwise) the customer is redirected to this URL| |reference|A unique reference for the vault transaction| |created|The local server datetime the vault transaction was created, epoch timestamp| |lastUpdate|The local server datetime the vault transaction was updated, epoch timestamp| |failureCode|An error code indication what caused the failure. Possible values: [Failure Codes](#failure-codes)| |details|An optional object listing specific vault details: [Vault Details](#vault-transaction-details) | *Example* ```json { "status" : "success", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Vault description", "language" : "eng", "method" : "vault", "brand" : "bcmc", "metadata" : "my custom metadata", "reference" : "V1505181754007360.1", "created" : 1431964440770, "lastUpdate" : 1431964458858, "payUrl" : "https://redirect.jforce.be/vault/card.html?reference=C1505181754007360.1", "returnUrl" : "http://shop/?order=8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "details" : { "expirationDuration" : "P0Y2M1DT0H0M0.000S", "vaultAccessToken" : "5C810B0AD0B1BC0926EBEA53" } } ``` #### Transaction Details [Vault Transaction Details] The expiration of the vault token is configurable by account. By default this is set to 30 days. In some scenarios you want the default expiration set to the card expiry date. This is also configurable by account. | Name | Description | |------|-------------| |expirationDuration|The time after which the vault access token expires in [ISO 8601 Duration](https://en.wikipedia.org/wiki/ISO_8601#Durations)| |expirationTimestamp|The datetime on which the vault access token will be expired after epoch timestamp| |vaultAccessToken|The Vault Access Token| |dataType|The data type that is stored in the vault for this Vault Access Token. At this moment only `card` is supported| |maskedPan|The [masked](#masking) primary account number. Only included when the dataType is `card`| |expiryDate|The expiry date of the card in format MMYY. Only included when the dataType is `card`| *Example* ```json { "dataType" : "card", "expirationDuration" : "P0Y2M1DT0H0M0.000S", "expirationTimestamp" : 1420106400000, "vaultAccessToken" : "5C810B0AD0B1BC0926EBEA53", "maskedPan": "xxxxxxxxxxxx4242", "expiryDate": "0424" } ``` ### Create a new vault request #### Request * Resource: `/api/v1/vault/initiate` * Method: `POST` * Content-Type: `application/json` * Authentication: **Required** * Parameters | Name | Required | Description | |------|----------|-------------| |dataType|Yes|The data type that should be requested from the customer. At this moment only `card` is supported| |returnUrl|After the payment is completed (successfully or otherwise) the customer is redirected to this URL| |language|Yes|The language of the customer. Defines the language to be used in the payment screens the customer will see. Possible values: `eng`, `nld`, `deu` or `fra`| |metadata|No|An arbitrary string, maximum of 255 characters, that can be used to track payments| |merchantOrderReference|No|A reference, maximum of 255 characters, of the order associated with this payment| |description|No|A description to show the customer| |webhookUrl|No|The [webhook](#webhooks) URL invoked for transaction changes. This overrides the merchant webhook if one is present. We do not validate this url| |billingAddress|No|The billing street address| |billingCity|No|The billing city of the customer| |billingState|No|The billing region/state of the customer| |billingPostalCode|No|The billing postal (zip) code of the customer| |billingCountry|No|The billing country of the customer, an ISO 3166 alpha-2 code. See for more info: [Country Codes - ISO 3166](http://www.iso.org/iso/home/standards/country_codes.htm).| |billingEmail|No|The billing email of the customer.| |billingPhoneNumber|No|The billing phone number of the customer| |billingFirstName|No|The billing first name of the customer| |billingLastName|No|The billing last name of the customer| |billingHouseNumber|No|The billing house number of the customer| |billingHouseExtension|No|The billing house extension of the customer| |shippingAddress|No|The shipping street address| |shippingCity|No|The shipping address city| |shippingState|No|The shipping address region/state| |shippingPostalCode|No|The shipping address postal (zip) code| |shippingCountry|No|The shipping address country, an ISO 3166 alpha-2 code| |shippingEmail|No|The shipping email of the customer| |shippingPhoneNumber|No|The shipping phone number of the customer| |shippingFirstName|No|The shipping first name of the customer| |shippingLastName|No|The shipping last name of the customer| |shippingHouseNumber|No|The shipping house number of the customer| |shippingHouseExtension|No|The shipping house extension of the customer| *Example* ```json { "dataType" : "card", "returnUrl" : "http://shop/?order=8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "metadata" : "my custom metadata", "merchantOrderReference" : "8cdbb73f-6537-4b7f-a6de-6ddab6c283e1", "description" : "API Vault description", "language" : "eng" } ``` #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: [Vault Transaction](#vault-transaction) ### Actions After obtaining a Vault Access Token, there are three actions that can be taken in the system. * [Initiate a payment](#create-a-new-payment) using the Vault Access Token * [Retrieve the sensitive data](#retrieve-data-from-the-vault) (Pan is returned in plain text if allowed by the settings for your merchant) * [Delete the sensitive data](#delete-data-from-the-vault) (if allowed by the settings for your merchant) #### Retrieve data from the vault This operation retrieves the sensitive data that was stored in the vault and returns it in plain text. The sensitive data can only be retrieved in plain text when this is allowed for your account. Default this is turned off, and will only be turned on when requested by the account owner. ##### Vault Token | Name | Sensitive | Description | |------|-----------|-------------| |token|no|The Vault Access Token| |eraseTimestamp|no|The date that this token will be erased from the database, epoch timestamp| |referenceId|no|A unique reference for the vault transaction| |merchantOrderReference|no|An arbitrary string, maximum 255 characters, that can be used to track vault transactions| |pan|yes|The primary account number| |maskedPan|no|The masked primary account number| |expiryDate|no|The expiry date| |cardholderFirstName|no|The first name of the cardholder| |cardholderLastName|no|The last name of the cardholder| ##### Retrieve a token from the vault ###### Request * Resource: `/api/v1/vault/token` * Method: `GET` * Content-Type: `application/json` * Authentication: **Required** * Parameters: `vaultToken`: The vault access token for which the data must be retrieved. ###### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: [Vault Token](#vault-token) | Name | Description | |------|-------------| |token|The Vault Access Token| |eraseTimestamp|The date that this token will be erased from the database, epoch timestamp| |referenceId|A unique reference for the vault transaction| |merchantOrderReference|An arbitrary string, maximum 255 characters, that can be used to track vault transactions| |pan|The primary account number. Only returned when decryption is enabled| |maskedPan|The [masked](#masking) primary account number| |expiryDate|The expiry date| |cardholderFirstName|The first name of the cardholder| |cardholderLastName|The last name of the cardholder| |created|The local server datetime the vault transaction was created, epoch timestamp| *Example of retrieval with non-sensitive data because not allowed by configuration* ```bash curl /api/v1/vault/token?vaultToken=TOKEN1 -u apikey: ``` ```json { "eraseTimestamp" : 1543155649042, "referenceId" : "V181026162049038CB87E190.1", "merchantOrderReference" : "321", "maskedPan" : "4111XXXXXXXX1111", "expiryDate" : "1221", "cardholderFirstName" : "John", "cardholderLastName" : "Doe" } ``` #### Delete data from the vault This operation explicitly erases the sensitive data from the vault. ##### Request * Resource: `/api/v1/vault/token` * Method: `DELETE` * Authentication: **Required** * Parameters | Name | Required | Description | |------|----------|-------------| |vaultToken|Conditional |The [vault access token](#vault-transaction-details). If present, `merchantOrderReference` must not be present | |merchantOrderReference|Conditional|The [merchant order reference](#vault-transaction). If present `vaultToken` must not be present.| *Example* ```bash # Delete the vault token using the merchant order reference 321 curl https://redirect.jforce.be/api/v1/vault/token?merchantOrderReference=321 -u apikey: ``` #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` #### Create a new vault request from a PCI compliant environment * Resource: `/api/v1/vault/token` * Method: `POST` * Content-Type: `application/json` * Authentication: **Required** | Name | Required | Description | |------|----------|-------------| |merchantOrderReference|No|An arbitrary string, maximum 255 characters, that can be used to track vault transactions| |pan|Yes|The primary account number| |expiryDate|Yes|The expiry date| |cardholderFirstName|No|The first name of the cardholder| |cardholderLastName|No|The last name of the cardholder| *Example* ```json { "merchantOrderReference" : "abcddd", "pan" : "6799998900000123456", "expiryDate" : "1803" } ``` #### Response * Status Code: `200` * Content Type: `application/json;charset=UTF-8` * Content: | Name | Description | |------|-------------| |token|The Vault Access Token| |eraseTimestamp|The date that this token will be erased from the database, in the format [ISO 8601 DateTime](https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations)| |referenceId|A unique reference for the vault transaction| |merchantOrderReference|An arbitrary string, maximum 255 characters, that can be used to track vault transactions| |created|The local server datetime the vault transaction was created, epoch timestamp| |lastUpdate|The local server datetime the vault transaction was updated, epoch timestamp| # Webhooks ## Description A Webhook is a callback mechanism to inform you of changes occurring to your transaction in our system. This is accomplished by making a HTTP call to an endpoint in your system at the moment these changes occur. We will not send any information to the webhook, but instead expect the merchant system to make a status call to retrieve the status of the transaction. ## Status changes Your webhook will be called when the transaction changes status or requires immediate attention. These status changes can be triggered by, for instance, successful completion of the payment, failed completion of the payment, a time out, fraud detection, and so on. The transaction [should be read](#read-a-transaction) and its status should be inspected. ## Security [Webhook Security] Due to security restrictions we will only support `https://` URLs. If you are technically not able to support this, please contact us. For a more secure internet, you can look at services like [Let's Encrypt](https://letsencrypt.org/) that provide you free certificates issued by a free **and** trusted Certificate Authority! ## Communication ### Request [Webhook Request] * Method: `POST` * Content-Type: `application/json` * Parameters | Name | Description | |------|-------------| |id|The unique `reference` of the transaction| *Example* ```json { "id" : "AC130090D6C19A09CD4B8B3EECCE199AD895B6E0" } ``` No other information is shared through the webhook. We expect the merchant system to make a status call to our system to retrieve the status of the transaction. This ensures that we will not disclose (possible) sensitive data to an attacker. If you need more information in the webhook, you can define a webhook URL [per transaction](#webhook-config-per-transaction) and add additional data in the URL. ### Response [Webhook Response] We expect a HTTP 2XX Success code and the content will be ignored. If no 2XX code is returned, we will retry. ### Retry [Webhook Retry] We will keep trying the webhook until we get a HTTP response code 2xx, which would indicate a success at your end. Any other HTTP status code will be treated as a failure and will result in a retry. Retrying will be done in increasing intervals until the final time out is reached, after which we will no longer try to call the webhook for this status change. Should the transaction change state again, we will again try until the final time out is reached. ## Config [Webhook Config] ### Global [Webhook Config Global] The webhook URL can be configured in the Merchant Backoffice. We support one URL per merchant and we will send all status changes to this URL. ### Per transaction [Webhook Config Per Transaction] We support the overriding of the global configuration by specifying a different webhook URL in the payment, refund or token request. If this URL is specified in the request, we will call this URL instead. This is appropriate if you want to include additional parameters per webhook like the merchant order reference. This would result in a webhook URL like `https://shop/webhook?order=123456&foo=bar` # Currencies We support 3 currencies. The code is the alphabetic 3 letter code as defined by ISO 4217. See for more info: [Table A. 1](http://www.currency-iso.org/en/home/tables/table-a1.html). | Name | Code | Exponent | |------|------|----------| |Euro | eur | 2 | |Swiss Franc | chf | 2 | |British Pound | gbp | 2 | These currencies require the same correct amount format with maximum 2 decimals as reflected by the exponents, including trailing zeroes, e.g. `10`, `10.1`, `10.10` or `10.01`. Any amount value with more than 2 decimals will cause an `input_error`. # Security and privacy [Masking] ## Masking Due to PCI compliance requirements and [GDPR](https://eugdpr.org/the-regulation/gdpr-faqs/) regulations we are required to delete certain types of data as soon as possible or only keep it encrypted or masked. When such data is later requested is it therefore returned in the same secured format. Pan and IBAN are masked in the same manner: if possible we will provide the first and last 4 characters, masking the rest. Example PAN `4111111111111111` becomes `4111XXXXXXXX1111`. Example IBAN `NL91ABNA0417164300` becomes `NL91XXXXXXXXXX4300`. When the value is too short, less than or equal to 8 characters, only the last 4 characters are returned. These values would likely be invalid but are safely masked nonetheless. # Idempotency Using idempotent requests is best used if there is no way to avoid duplicate requests. Time-outs are often the cause of retransmission and must be possible without side-effects like processing the request twice. [Idempotency](https://en.wikipedia.org/wiki/Idempotence#Computer_science_meaning) for [payment](#payment), [capture](#capture), [reversal](#reversal) and [refund](#refund-an-existing-payment) requests can be enabled by adding the optional request header `Idempotency-Reference`, which should contain a non-empty unique value of maximum 50 characters generated for each transaction. GET requests are idempotent by definition. We do not enforce a minimum length but we recommend a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) generated for each new transaction and not for example a database id. We treat a request as identical to another for idempotency when the exact same request header is used, and the following fields all match (also including empty or null values) for the selected operation: [Payment](#payment): - transactionType - method - brand - amount - currency - issuer - storeInVault [Capture](#capture) - reference - amount [Refund](#refund) - reference - amount **Example payment request with idempotency header** ```bash curl --basic --user apikey: -H "User-Agent: Shop123456" -H "Idempotency-Reference: 123e4567-e89b-12d3-a456-426655440000" -H "Content-Type: application/json" --data '{ "amount" : 9.99, "currency" : "eur", "method" : "card", "brand" : "visa", "returnUrl" : "http://shop/return?order=123456", "merchantOrderReference" : "123456", "description" : "Order 123456", "language" : "eng" }' https://redirect.jforce.be/api/v1/payment ``` **Example capture request with idempotency header** ```bash curl --basic --user apikey: -H "User-Agent: Shop123456" -H "Idempotency-Reference: 123e4567-e89b-12d3-a456-426655440001" -H "Content-Type: application/json" --data '{ "reference": "C1505181754007360.1", "amount" : 9.99, "description" : "Capture Order 123456"}' https://redirect.jforce.be/api/v1/capture ``` **Example refund request with idempotency header** ```bash curl --basic --user apikey: -H "User-Agent: Shop123456" -H "Idempotency-Reference: 123e4567-e89b-12d3-a456-426655440002" -H "Content-Type: application/json" --data '{ "reference": "C1505181754007360.1", "amount" : 9.99, "description" : "Refund Order 123456" }' https://redirect.jforce.be/api/v1/refund ``` If we find an existing, identical request with the same idempotency reference for the same merchant account, we can guarantee the result will be the same as for the initial request for the same transaction and will not create a new one. Any differences in the request using an existing idempotency reference will result in an `input error`. A reference will expire after 24 hours after which the same request with the same idempotency reference will result in a new transaction. The only input that is used is the one provided in the very first idempotent request and further attempts using the same idempotency header value will never override or replace that input. For support concerning idempotent requests we suggest you provide us with your [error](#error-handling) reference and the used idempotency reference. # Examples To ease your integration and give you some ideas of how the API can be used, we provide you with some [examples](https://redirect.jforce.be/api/v1/doc/examples). # Changelog The changelog is an overview of all changes made to the API. Not every version contains API changes and therefore not listed. ## 3.28.0 - 2019-01-15 ### Added * Reversal of card authorisations. More info [here](#reverse-an-existing-authorisation) * Authorised amount in transaction response for authorisations. More info [here](#card-payment-details) * Return of a `urlIntent` for card schemes that support mobile payment. More info [here](#card-payment-details) ## 3.27.0 - 2018-10-29 ### Added * Explicit amount format specification based on used currency More info [here](#currencies) * Failure code `unsupported_currency`. More info [here](#failure-codes) * [Idempotency](#idempotency) * Custom IBAN for MT940 export. More info [here](#export-transactions-as-mt940) # Testing The features below must be used in operating mode **TEST** and can be used to test VPOS functionality in a JForce simulated environment. The operating mode is associated with your API key. Once you have completed your integration, you must use your **LIVE** key for production usage. ## Method Card For card transactions you need to use a specific card: | Brand | PAN | |-------|-----| | `visa` | 4242 4242 4242 4242 | | `visa` | 4111 1111 1111 1111 | | `visa` | 4012 8888 8888 1881 | | `visa` | 4222 2222 2222 2 | | `visa` | 4917 3008 0000 0000 | | `visa electron` | 4245 1900 0000 0311 | | `vpay` | 4370 0000 0000 0061 | | `mastercard` | 5555 5555 5555 4444 | | `mastercard` | 5105 1051 0510 5100 | | `mastercard` | 2223 0000 1002 9657 | | `maestro` | 6759 6498 2643 8453 | | `bcmc` (Maestro co-branded) | 6703 2222 2222 2222 7 | | `bcmc` (Maestro co-branded) | 6703 3333 3333 3333 9 | | `bcmc` (VPay co-branded) | 4796 5899 9999 9917 | | `amex` | 3782 822463 10005 | _We will fail all payments that use an unknown card._ ### General | Amount | Simulator Response | VPOS status | | ------ | ------------------ | ------------- | | 8.00 | `timeout` | `pending` | | 8.01 | `failed` | `failed` with failure code `INSUFFICIENT_FUNDS` | | 8.02 | `failed` | `failed` with failure code `CARD_REFUSED` | | 9.00 | `failed` | `failed` | | other | `success` | `success` | ### Authorise - Capture Note: Our simulators only store transactions for a limited amount of time. As a result, a capture following an authorisation might not have the expected behaviour due to the unknown state of the authorisation. #### Authorise | Brand | Amount | Simulator Response | VPOS status | | ----- | ------ | ------------------ | ----------- | | `bcmc`| 125.00 | `success` | `success` with partial approval of 100.00 | | other | 125.00 | `failed` | `failed` | | other | other | `success` | `success` | #### Capture * A full capture is allowed * A capture of more than the authorised amount is not allowed ## Method iDEAL For iDEAL transactions you can pass specific amounts: | Amount | Simulator response | VPOS status | |--------|--------------------|---------------| | 5.00 | `Failure` | `failed` | | 6.00 | `Cancelled` | `failed` with failure code `cancelled` | | 7.00 | `Expired` | `failed` with failure code `expired` | | 8.00 | `Open` | `pending` | | 9.00 | `Success` after 10 seconds | `success` | | 10.00 | `Failure` after 10 seconds | `failed` | | 11.00 | `Open` after 10 seconds | `pending` | | other | `Success` | `success` | ## Method PayPal For PayPal transactions you can pass specific amounts: | Amount | Simulator response | VPOS status | |--------|--------------------|---------------| | 5.00 | `failed` | `failed` with failure code `processing_error` | | 6.00 | `canceled` | `failed` with failure code `cancelled` | | 7.00 | `expired` | `failed` with failure code `expired` | | 8.00 | `pending` | `pending` | | 9.00 | `approved` | `success` | | 10.00 | `created` | `pending` | | 11.00 | `denied` | `failed` with failure code `rejected` | | other | `completed` | `success` | ## Method GiroPay For transactions with a Test API key, the chosen BIC does not matter. Any value will be accepted. | Amount | Simulator response | VPOS status | |--------|--------------------|-------------| | 5.00 | `bank offline` (4001) | `failed` | | 6.00 | `Zahlungsaugang unbekannt` (4500) | `failed` | | 7.00 | `online banking account invalid` (4002) | `failed` | | other | `transaction successful` (4000) | `success` | ## Method SOFORT The redirect to the VPOS will result in a redirect to your shop. | Amount | Simulator response | VPOS status | |--------|--------------------|--------------| | 44.00 | `error` | `failed` with failure code `processing_error` | | 45.00 | `loss` with reason `not_credited` | `failed` with failure code `processing_error` | | 46.00 | `pending` with reason `not_credited_yet` | `pending` | | 47.00 | `received` with reason `credited` | `success` | | 48.00 | `refunded` with reason `compensation` | `success` | | 49.00 | `refunded` with reason `refunded` | `success` | | 50.00 | redirect to VPOS | `failed` with failure code `abort` | | 51.00 | redirect to VPOS | `failed` with failure code `expired` | | 52.00 | redirect to VPOS | `pending`, eventually `failed` with failure code `expired` after timeout | | other | `untraceable` with reason `sofort_bank_account_needed` | `pending` | ## Method Terminal A simulated terminal is available to test your integration with a test api key: * host: shop-vpos-test.jforce.be * ip: 93.188.251.249 * port: 6235 * terminal id: random * management system id: random * access protocol: OPI_NL * operatingEnvironment: SEMI_UNATTENDED or ATTENDED * merchantLanguage: ENG, NLD, FRA, DEU | Amount | Simulator response | VPOS status | |--------|--------------------|--------------| | 4 | An error with code `unknown` | `failed` with failure code `processing_error` | | 5 | `failure` | `failed` with failure code `processing_error` | | 8 | `unknown` | `manualintervention` | | 9 | `success` after 10 seconds | `success` | | 10 | `failure` after 10 seconds | `failed` | | 11 | `unknown` after 10 seconds | `manualintervention` | | 12 | `success` with no callback | `success` after status update | | 13 | `success` after VPOS performs status check | `success` after status update TAS callback | | 14 | `success` after VPOS performs multiple status checks | `success` after status update TAS callback | | 15 | `success` after 10 seconds and not responding to abort attempt | `success` | | 16 | `failed` after 10 seconds and not responding to abort attempt | `failed` | | 17 | `success` after 10 seconds when abort is not attempted, `failed` after 10 seconds when abort is attempted | `success` / `failed` | | other | `success ` | `success ` | ## Method Payconiq For Payconiq transactions you can pass specific amounts: | Amount | Simulator response | VPOS status | |--------|--------------------|---------------| | 6.00 | `canceled` | `failed` with failure code `cancelled` and cancelled by `consumer`| | 7.00 | `expired` | `failed` with failure code `expired` | | 9.00 | `failed` | `failed` with failure code `processing_error` | | other | `completed` | `success` | For Payconiq transactions you can also call the cancel url, and the simulator will respond with the following behavior: | Amount | Simulator response | VPOS status | |--------|--------------------|---------------| | 8.00 | `not allowed` | `pending` | | other | `allowed` | `failed` with failure code `cancelled` with cancelled by `merchant` | ## Method EPS For EPS transactions you can pass specific amounts: | Amount | Simulator response | VPOS status | |--------|--------------------|---------------| | 8.00 | `failed` | `failed` with failure code `processing_error` | | other | `completed` | `success` | ## Method OK.APP For OK.APP transactions you can pass specific amounts: | Amount | Simulator response | VPOS status | |--------|--------------------|---------------| | 8.00 | `failed` | `failed` with failure code `processing_error` | | other | `completed` | `success` | For OK.APP transactions you can call the cancel url, and the simulator will respond with the following behavior: | Amount | Simulator response | VPOS status | |--------|--------------------|---------------| | 9.00 | `rejected - rejected by OK.APP` | `pending` | | other | `allowed` | `failed` with failure code `cancelled` with cancelled by `merchant` | OK.APP supports refunds, and the simulator will respond with the following behavior: | Amount | Simulator response | VPOS status | |--------|--------------------|---------------| | 10.00 | `rejected - rejected by OK.APP` | `pending` | | other | `allowed` | `failed` with failure code `cancelled` with cancelled by `merchant` | ## Fraud detection All the payments are screened for fraud. The following amounts are applicable for **all** payment methods. | Amount | Simulator Response | VPOS status | |--------|--------------------|-------------| | 66.00 | `reject` | `failed` with failure code `fraud_detected` | | Other | `accept` | Depending on the chosen method |