NAV Navbar
Java JavaScript PHP
  • Introduction
  • Development Sandbox
  • Form API
  • Payment API
  • Response and Status Codes
  • Data Types
  • Change log
  • Introduction

    This is the API reference and example documentation for Payment Highway. The easy and enjoyable card payment solution for mobile and online.

    Payment Highway API consists of two parts:

    Client Libraries

    Java

    https://github.com/PaymentHighway/paymenthighway-java-lib

    PHP

    https://github.com/PaymentHighway/paymenthighway-php-lib

    JavaScript

    https://github.com/PaymentHighway/paymenthighway-javascript-lib

    Examples

    Live example. Try it out here!

    JavaScript

    A simple JavaScript example using the JavaScript client library @ GitHub

    Usage

    Make a Payment

    1. Show the form with Form API POST /form/view/pay_with_card
      —> returns an sph-transaction-id and signature as a GET parameters to the given success-url
    2. Commit the payment with Payment API POST /transaction/<sph-transaction-id>/commit
      —> returns a result in JSON formatting

    Store a Card

    1. Show the form with Form API POST /form/view/add_card
      —> returns an sph-tokenization-id and signature as a GET parameters to the given success-url
    2. Get the card token with Payment API GET /tokenization/<sph-tokenization-id>
      —> returns a card_token and card information in JSON formatting

    Pay with a Stored Card

    1. Initialize a transaction with Payment API POST /transaction
      —> returns a transaction id in JSON formatting
    2. Charge the card with Payment API POST /transaction/<id>/debit
      —> returns a result in JSON formatting

    Pay with MobilePay

    1. Open MobilePay with Form API POST /form/view/mobilepay
      -> return an sph-transaction-id and signature as a GET parameters to the given success-url
    2. Commit payment with Payment API POST /transaction/<sph-transaction-id>/commit
      —> returns a result in JSON formatting

    Development Sandbox

    Base URL

    The Payment Highway Sandbox environment is accessed on
    https://v1-hub-staging.sph-test-solinor.com/

    Merchant Account

    The Sandbox Merchant Account uses the following credentials:

    Parameter Value
    sph-account test
    sph-merchant test_merchantId
    Account key testKey
    Account secret testSecret

    Take a look at the signature calculation examples in the Form API and in the Payment API.

    Sandbox credit cards

    There are predefined card numbers that are accepted in the sandbox environment. Each card serves a different purpose in testing the API. For general declines, just input an incorrect CVC or expiry date.

    Card abilities Card Number Expiry date CVC Specialties
    Tokenization OK
    Payment OK
    4153013999700313 11/2026 313 Successful 3D Secure. 3DS form password "secret".
    Tokenization OK
    Payment OK
    4153013999700321 11/2026 321 Successful 3D Secure. 3DS form will be automatically completed.
    Tokenization OK
    Payment OK
    4153013999700339 11/2026 339 3D Secure attempt. 3DS will be automatically attempted.
    Tokenization (OK)
    Payment (OK)
    4153013999700347 11/2026 347 3D Secure fails. The "cardholder_authentication" response parameter will be "no". It is at discretion of the merchant to accept or reject unauthentication transactions. If the merchant decides to decline the payment, the transaction should be reverted.
    Tokenization OK
    Payment FAIL
    4153013999700354 11/2026 354 Successful 3D Secure. 3DS form password "secret". Insufficient funds in the test bank account.
    Tokenization OK
    Payment OK with 3DS
    4153013999701162 11/2026 162 Soft decline when charging saved card using Customer Initiated Transaction (requires 3DS). 3DS form password "secret".
    Tokenization OK
    Payment OK with 3DS
    4153013999701170 11/2026 170 Soft decline when charging saved card using Customer Initiated Transaction (requires 3DS). 3DS form will be automatically completed.
    Tokenization OK
    Payment OK
    4153013999700024 11/2026 024 Non-EU - "one leg out" card, not enrolled to 3DS. The "cardholder_authentication" response parameter will be "attempted".
    Tokenization OK
    Payment FAIL
    4153013999700156 11/2026 156 Non-EU - "one leg out" card, not enrolled to 3DS. Insufficient funds in the test bank account.
    Tokenization OK
    Payment OK
    4153013999703002 Any month and year Any CVC Partial approval on amount greater than 2. Returns partial approval of half the amount. Only for AFD customers.
    Tokenization OK
    Payment OK
    4153013999704000 Any month and year Any CVC Provides a network token, if enabled for the test merchant.
    Tokenization OK
    Payment FAIL
    4153013999704018 Any month and year Any CVC Provides a network token, if enabled for the test merchant. Insufficient funds in the test bank account for payments.
    Tokenization OK
    Payment OK with 3DS
    4153013999704026 Any month and year Any CVC Provides a network token, if enabled for the test merchant. Soft decline when charging saved card using Customer Initiated Transaction (requires 3DS). 3DS form password "secret".
    Tokenization OK
    Payment OK with 3DS
    4153013999704034 Any month and year Any CVC Provides a network token, if enabled for the test merchant. Soft decline when charging saved card or network token using Customer Initiated Transaction (requires 3DS). 3DS form password "secret".

    Form API

    Payment Highway Form API allows merchants to tokenize payment cards and create payments using an HTML form interface.

    Request and Response format

    // Create a FormBuilder
    
    String method = "POST";
    String signatureKeyId = "testKey";
    String signatureSecret = "testSecret";
    String account = "test";
    String merchant = "test_merchantId";
    String serviceUrl = "https://v1-hub-staging.sph-test-solinor.com";
    
    FormBuilder formBuilder = new FormBuilder(
      method, signatureKeyId, signatureSecret, account, merchant,
      serviceUrl
    );
    
    // Create a FormBuilder
    
    signature_key_id = "testKey"
    signature_secret = "testSecret"
    account = "test"
    merchant = "test_merchantId"
    service_url = "https://v1-hub-staging.sph-test-solinor.com"
    success_url = "https://www.paymenthighway.fi/"
    failure_url = "https://paymenthighway.fi/dev/"
    cancel_url = "https://solinor.com/"
    language = "EN"
    
    form_builder = PaymentHighway::FormBuilder.new(
      signature_key_id, signature_secret, account, merchant,
      service_url, success_url, failure_url, cancel_url, language)
    
    
    var paymentHighway = require('paymenthighway-javascript-lib');
    
    var method = 'POST';
    var testKey = 'testKey';
    var testSecret = 'testSecret';
    var account = 'test';
    var merchant = 'test_merchantId';
    var serviceUrl = 'https://v1-hub-staging.sph-test-solinor.com';
    
    var formBuilder = new paymentHighway.FormBuilder(
            method,
            testKey,
            testSecret,
            account,
            merchant,
            serviceUrl
        );
    
    <?php
    use \Solinor\PaymentHighway\FormBuilder;
    
    $method = "POST";
    $signatureKeyId = "testKey";
    $signatureSecret = "testSecret";
    $account = "test";
    $merchant = "test_merchantId";
    $baseUrl = "https://v1-hub-staging.sph-test-solinor.com";
    $successUrl = "https://example.com/success";
    $failureUrl = "https://example.com/failure";
    $cancelUrl = "https://example.com/cancel";
    $language = "EN";
    
    $formBuilder = new FormBuilder($method,
        $signatureKeyId,
        $signatureSecret,
        $account,
        $merchant,
        $baseUrl,
        $successUrl,
        $failureUrl,
        $cancelUrl,
        $language);
    

    Requests

    The “sph”-prefixed form fields and the request signature should be calculated server side and set in the html form as hidden fields.

    Responses

    Responses are delivered to URLs given in the request and signed by using the same key as in the request. Response parameters are added as GET parameters to the URL.

    When a user is redirected to the success-url, it means we have successfully completed processing of the request. It does not however mean the card payment or tokenization was accepted by the authorizing parties. You will find out the actual result using the PaymentAPI (server-to-server) commit or tokenization requests.

    A user is redirected to the failure-url, if processing of the request failed for example due to missing parameters, authentication issues or connectivity issues to the authorizing parties.

    Important! Always validate the form redirection signature parameter to prevent tampering of the values!

    Authentication

    Authentication is based on a signature calculated from the merchant account information and from the other parameters prefixed with 'sph'.

    Request signature calculation

    Original POST data

    POST
    /form/view/pay_with_card
    sph-account=test
    sph-merchant=test_merchantId
    sph-order=1000123A
    sph-request-id=f47ac10b-58cc-4372-a567-0e02b2c3d479
    sph-amount=990
    sph-currency=EUR
    sph-timestamp=2014-09-18T10:32:59Z
    sph-success-url=https://merchant.example.com/payment/success
    sph-failure-url=https://merchant.example.com/payment/failure
    sph-cancel-url=https://merchant.example.com/payment/cancel
    language=fi
    description=Example payment of 10 balloons á 0,99EUR
    signature=SPH1 testKey 960aeec47d172637325b15513b3a526e95c93ba74b5067da766f282573464d58
    

    POST data included in the signature calculation, parameters sorted alphabetically

    "POST
    /form/view/pay_with_card
    sph-account:test
    sph-amount:990
    sph-cancel-url:https://merchant.example.com/payment/cancel
    sph-currency:EUR
    sph-failure-url:https://merchant.example.com/payment/failure
    sph-merchant:test_merchantId
    sph-order:1000123A
    sph-request-id:f47ac10b-58cc-4372-a567-0e02b2c3d479
    sph-success-url:https://merchant.example.com/payment/success
    sph-timestamp:2014-09-18T10:32:59Z
    "
    

    Authentication hash using "testSecret" as the keyValue and POST data from above:
    HMAC-SHA256(keyValue, data) =>
    960aeec47d172637325b15513b3a526e95c93ba74b5067da766f282573464d58

    Signature is calculated from the request parameters with HMAC-SHA256 algorithm using one of the merchant secret keys. The signature value contains “SPH1”, the key ID and the calculated authentication hash as a hexadecimal string separated with spaces “ ” (0x20).

    The authentication hash value is calculated from the authentication string using the chosen merchant secret key. The authentication string is formed from the request method, URI and the request parameters beginning with “sph-”-prefix. Values are trimmed and the key-value pairs are concatenated in alphabetical order by the key name. The parameter keys must be in lowercase. Each key and value is separated with a colon (“:”) and the different parameters are separated with a new line (“\n”) at the end of each value.

    Response redirection signature calculation (success, failure and cancel urls)

    Form redirection response example:
    

    http://merchant-example-spring.sph-test-solinor.com/pay_with_card/success?sph-amount=1990&signature=SPH1+testKey+8b9b2eb519e289016ff8b6bb6112901ad64238a8035b6b06a179a1bcb178947e&sph-account=test&sph-currency=EUR&sph-merchant=test_merchantId&sph-transaction-id=24806fe4-c0ed-4baa-9044-14b15457ea6e&sph-order=1000123A&sph-timestamp=2016-05-17T07%3A08%3A27Z&sph-request-id=7475777a-b9f8-4c09-958c-b1ea47bdc0cb&sph-success=OK

    "GET
    
    sph-account:test
    sph-amount:1990
    sph-currency:EUR
    sph-merchant:test_merchantId
    sph-order:1000123A
    sph-request-id:7475777a-b9f8-4c09-958c-b1ea47bdc0cb
    sph-success:OK
    sph-timestamp:2016-05-17T07:08:27Z
    sph-transaction-id:24806fe4-c0ed-4baa-9044-14b15457ea6e
    "
    

    Authentication hash using "testSecret" as the keyValue and GET data from above:
    HMAC-SHA256(keyValue, data) =>
    8b9b2eb519e289016ff8b6bb6112901ad64238a8035b6b06a179a1bcb178947e

    // Validate the response signature
    
    SecureSigner secureSigner = new SecureSigner(signatureKeyId, signatureSecret);
    
    if ( ! secureSigner.validateFormRedirect(requestParams)) {
        throw new Exception("Invalid signature!");
    }
    
    // Validate the response signature
    
    var secureSigner = new paymentHighway.SecureSigner(testKey, testSecret);
    
    if(!secureSigner.validateFormRedirect(requestParams)) {
        // Handle error
    }
    
    <?php
    use Solinor\PaymentHighway\Model\Security\SecureSigner;
    
    $secureSigner = new SecureSigner(signatureKeyId, signatureSecret);
    
    try{
        $secureSigner->validateFormRedirect($params)) {
    }
    catch(Exception $e) {
        // Validation failed, handle here
    }
    

    Response parameters are formatted into a single value and HMAC-SHA256 signature is calculated with the same secret key as in the request. The signature value contains “SPH1”, the key ID and the calculated authentication hash as a hexadecimal string separated with spaces “ ” (0x20).

    The authentication hash value is calculated from the authentication string using the chosen merchant secret key. The authentication string is formed from the method "GET", an empty URI "", the response parameters beginning with “sph-”-prefix and an empty body "". Values are trimmed and the key-value pairs are concatenated in alphabetical order (by the key name). The parameter keys must be in lowercase. Each key and value is separated with a colon (“:”) and the different parameters are separated with a new line (“\n”) at the end of each value.

    Add Card

    curl -i --data-urlencode '
    sph-account=test
    sph-merchant=test_merchantId
    sph-request-id=f47ac10b-58cc-4372-a567-0e02b2c3d479
    sph-timestamp=2014-09-18T10:32:59Z
    sph-success-url=https://merchant.example.com/payment/success
    sph-failure-url=https://merchant.example.com/payment/failure
    sph-cancel-url=https://merchant.example.com/payment/cancel
    language=fi
    signature= SPH1 testKey 4eab87a16e3ee7bd530d778af0cb6c680dcaa52ed1913a9c1bd8ed5a8d689e3e' \
        https://v1-hub-staging.sph-test-solinor.com/form/view/add_card
    
    // Example common parameters for the following form generation functions
    
    String successUrl = "https://www.paymenthighway.fi/";
    String failureUrl = "https://paymenthighway.fi/dev/";
    String cancelUrl = "https://solinor.com/";
    String language = "EN";
    
    // Generate Add Card form parameters
    
    FormContainer formContainer = formBuilder.addCardParameters(successUrl, failureUrl, cancelUrl)
        .language(language)
        .build();
    
    // read form parameters
    String httpMethod = formContainer.getMethod();
    String actionUrl = formContainer.getAction();
    List<NameValuePair> fields = formContainer.getFields();
    
    for (NameValuePair field : fields) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="field.getName()" value="field.getValue()">
        * Or create GET-url:
        * ?field.getName()=field.getValue()&...
        */
        field.getName();
        field.getValue();
    }
    
    // Generate Add Card form parameters
    
    form_container = form_builder.add_card_parameters
    
    // read form parameters
    http_method = form_container.method
    action_url = form_container.action
    pairs = form_container.pairs // an array of PaymentHighway::NameValuePair
    
    pairs.each do |pair|
        name = pair.name
        value = pair.value
    end
    
    // Example common parameters for the following form generation functions
    
    var successUrl = 'https://example.com/success';
    var failureUrl = 'https://example.com/failure';
    var cancelUrl = 'https://example.com/cancel';
    var language = 'EN';
    
    // Generate Add Card form parameters
    
    var formContainer = formBuilder.generateAddCardParameters(
                          successUri,
                          failureUri,
                          cancelUri,
                          language
                        );
    
    // read form parameters
    var httpMethod = formContainer.method;
    var actionUrl = formContainer.getAction();
    var fields = formContainer.nameValuePairs;
    
    fields.forEach(function(field) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="name" value="value">
        * Or create GET-url:
        * ?name=value&...
        */
        var name = field.first;
        var value = field.second;
    });
    
    
    <?php
    $form = $formBuilder->generateAddCardParameters();
    
    // read form parameters
    $httpMethod = $form->getMethod();
    $actionUrl = $form->getAction();
    $parameters = $form->getParameters();
    
    foreach ($parameters as $key => $value) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="$key" value="$value">
        * Or create GET-url:
        * ?$key=$value&...
        */
        echo $key .":". $value;
    }
    

    Adding a new card stores the payment card information to Payment Highway and returns a tokenization id that can be used to fetch a card token for payments.

    Simple flow

    1. Show the form with Form API POST /form/view/add_card
      —> returns an sph-tokenization-id and signature as a GET parameters to the given success-url
    2. Get the card token with Payment API GET /tokenization/<sph-tokenization-id>
      —> returns a card_token and card information in JSON formatting

    HTTP Request

    POST /form/view/add_card

    Parameter Data type M/O Description
    sph-account AN M Account identifier
    sph-merchant AN M Account merchant identifier
    sph-request-id UUID4 M Request identifier
    sph-timestamp TIMESTAMP M Request timestamp in ISO 8601
    combined date and time in UTC.
    E.g. "2025-09-18T10:32:59Z"
    sph-success-url URL M Success URL the user is redirected to on success
    sph-failure-url URL M Failure URL the user is redirected to on failure
    sph-cancel-url URL M Cancel URL the user is redirected to on cancel
    sph-webhook-success-url URL O On success, server to server GET request will be made to this url with same parameters as success redirect.
    sph-webhook-failure-url URL O On failure, server to server GET request will be made to this url with same parameters as failure redirect.
    sph-webhook-cancel-url URL O On cancel, server to server GET request will be made to this url with same parameters as cancel redirect.
    sph-webhook-delay N O webhook call delay in seconds (MAX. 900). If omitted, default value 0 will be used.
    sph-accept-cvc-required BOOLEAN O Allow adding a card even if it requires CVC for payments. Defaults to false.
    sph-api-version VERSION O API version number
    language A O Two letter language code (ISO 639-1). Supported languages are DE, EN, ES, FI, FR, IT, NL, PT, PL, RU, SV. Defaults to browser language.
    sph-skip-form-notifications BOOLEAN O Skip errors displayed on the Payment Highway form and redirect directly to result URL (E.g. "Ecom payments disabled") . Default false.
    sph-exit-iframe-on-result BOOLEAN O Exit from iframe after redirection to result URLs.
    sph-exit-iframe-on-three-d-secure BOOLEAN O Exit from iframe when redirecting user to 3DS.
    sph-use-three-d-secure BOOLEAN O Force enable/disable 3DS authentication. Omit / null to use default configured parameter. Disable only if permitted by Your acquiring contract!
    signature ANS M Message signature in the format 'SPH1 key-id authentication-string'

    Webhooks have same parameters as success, failure and cancel responses.

    Success Response for Add Card

    On a successful operation the user is redirected to the given success URL sph-success-url.

    When a user is redirected to the success-url, it means we have successfully completed processing of the request. It does not however mean the card payment or tokenization was accepted by the authorizing parties. You will find out the actual result using the PaymentAPI (server-to-server) commit or tokenization requests.

    Parameter Data type Description
    sph-account AN Account identifier from request
    sph-merchant AN Account merchant identifier from request
    sph-request-id UUID4 Request identifier from request
    sph-api-version VERSION API version number used in the request
    sph-session-id UUID4 Reference to the form session
    sph-tokenization-id UUID4 Generated sph-tokenization-id
    sph-timestamp TIMESTAMP Response timestamp in ISO 8601
    combined date and time in UTC.
    E.g. 2025-09-18T10:33:49Z
    sph-success AN Static text “OK”
    signature ANS Message signature

    Failure Response for Add Card

    On failure the user is redirected to the given failure URL sph-failure-url.

    A user is redirected to the failure-url, if processing of the request failed for example due to missing parameters, authentication issues or connectivity issues to the authorizing parties.

    Parameter Data type Description
    sph-account AN Account identifier from request
    sph-merchant AN Account merchant identifier from request
    sph-request-id UUID4 Request identifier from request
    sph-api-version VERSION API version number used in the request
    sph-session-id UUID4 Reference to the form session
    sph-timestamp TIMESTAMP Response timestamp in ISO 8601
    combined date and time in UTC.
    E.g. 2025-09-18T10:33:49Z
    sph-failure AN Failure reason, one of:
    • "UNAUTHORIZED"
    • "INVALID"
    • "FAILURE"
    • "NO_ROUTE" (Equivalent to response code 940)
    • "THREE_D_SECURE" (Technical failure in 3D secure)
    • "SESSION_EXPIRED" (Payment or Tokenization form was expired before completion)
    signature ANS Message signature

    Cancel Response for Add Card

    If the user cancels the operation they are redirected to the given cancel URL sph-cancel-url.

    Parameter Data type Description
    sph-account AN Account identifier from request
    sph-merchant AN Account merchant identifier from request
    sph-request-id UUID4 Request identifier from request
    sph-api-version VERSION API version number used in the request
    sph-session-id UUID4 Reference to the form session
    sph-timestamp TIMESTAMP Response timestamp in ISO 8601
    combined date and time in UTC.
    E.g. 2025-09-18T10:33:49Z
    sph-cancel AN Cancel reason "CANCEL"
    signature ANS Message signature

    Payment

    curl -i --data-urlencode '
    sph-account=test
    sph-merchant=test_merchantId
    sph-order=1000123A
    sph-request-id=f47ac10b-58cc-4372-a567-0e02b2c3d479
    sph-amount=990
    sph-currency=EUR
    sph-timestamp=2014-09-18T10:32:59Z
    sph-success-url=https://merchant.example.com/payment/success
    sph-failure-url=https://merchant.example.com/payment/failure
    sph-cancel-url=https://merchant.example.com/payment/cancel
    language=fi
    description=Example payment of 10 balloons á 0,99EUR
    signature= SPH1 testKey 960aeec47d172637325b15513b3a526e95c93ba74b5067da766f282573464d58' \
        https://v1-hub-staging.sph-test-solinor.com/form/view/pay_with_card
    
    // Generate Payment form parameters
    
    String amount = "1990";
    String currency = "EUR";
    String orderId = "1000123A";
    String description = "A Box of Dreams. 19,90€";
    
    FormContainer formContainer = formBuilder.paymentParameters(successUrl, failureUrl, cancelUrl, amount, currency, orderId, description)
            .build();
    
    // read form parameters
    String httpMethod = formContainer.getMethod();
    String actionUrl = formContainer.getAction();
    List<NameValuePair> fields = formContainer.getFields();
    
    for (NameValuePair field : fields) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="field.getName()" value="field.getValue()">
        * Or create GET-url:
        * ?field.getName()=field.getValue()&...
        */
        field.getName();
        field.getValue();
    }
    
    // Generate Payment form parameters
    
    amount = 1990
    currency = "EUR"
    order_id = "1000123A"
    description = "A Box of Dreams. 19,90€"
    
    form_container = form_builder.pay_with_card_parameters(amount, currency, order_id, description)
    
    // read form parameters
    http_method = form_container.method
    action_url = form_container.action
    pairs = form_container.pairs // an array of PaymentHighway::NameValuePair
    
    pairs.each do |pair|
        name = pair.name
        value = pair.value
    end
    
    var amount = 1990;
    var currency = 'EUR';
    var orderId = '1000123A';
    var description = 'A Box of Dreams. 19,90€';
    
    var formContainer = formBuilder.generatePaymentParameters(
            successUri,
            failureUri,
            cancelUri,
            language,
            amount,
            currency,
            orderId,
            description
        );
    
    // read form parameters
    var httpMethod = formContainer.method;
    var actionUrl = formContainer.getAction();
    var fields = formContainer.nameValuePairs;
    
    fields.forEach(function(field) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="name" value="value">
        * Or create GET-url:
        * ?name=value&...
        */
        var name = field.first;
        var value = field.second;
    });
    
    <?php
    $amount = "1990";
    $currency = "EUR";
    $orderId = "1000123A";
    $description = "A Box of Dreams. 19,90€";
    
    $form = $formBuilder->generatePaymentParameters($amount, $currency, $orderId, $description);
    
    // read form parameters
    $httpMethod = $form->getMethod();
    $actionUrl = $form->getAction();
    $parameters = $form->getParameters();
    
    foreach ($parameters as $key => $value) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="$key" value="$value">
        * Or create GET-url:
        * ?$key=$value&...
        */
        echo $key .":". $value;
    }
    

    The payment card form is shown in the Payment Highway. The response to the success-url contains a sph-transaction-id for committing the transaction through the Payment API.

    Simple flow

    1. Show the form with Form API POST /form/view/pay_with_card
      —> returns an sph-transaction-id and signature as a GET parameters to the given success-url
    2. Commit the payment with Payment API POST /transaction/<sph-transaction-id>/commit
      —> returns a result in JSON formatting

    HTTP Request

    POST /form/view/pay_with_card

    Parameter Data type M/O Description
    sph-account AN M Account identifier
    sph-merchant AN M Account merchant identifier
    sph-order ORDER-ID M Merchant defined order identifier. Should be unique per transaction.
    sph-request-id UUID4 M Request identifier
    sph-amount N M Amount in the lowest currency unit. E.g. 99,00 € = 9900
    sph-currency A M Currency code "EUR"
    sph-timestamp TIMESTAMP M Request timestamp in ISO 8601
    combined date and time in UTC.
    E.g. "2025-09-18T10:32:59Z"
    sph-success-url URL M Success URL user is redirected to on success
    sph-failure-url URL M Failure URL user is redirected to on failure
    sph-cancel-url URL M Cancel URL user is redirected to on cancel
    sph-webhook-success-url URL O On success, server to server GET request will be made to this url with same parameters as success redirect.
    sph-webhook-failure-url URL O On failure, server to server GET request will be made to this url with same parameters as failure redirect.
    sph-webhook-cancel-url URL O On cancel, server to server GET request will be made to this url with same parameters as cancel redirect.
    sph-webhook-delay N O Webhook call delay in seconds (MAX. 900). If omitted, default value 0 will be used.
    sph-api-version VERSION O API version number
    language A O Language code (ISO 639-1). Supported languages are DE, EN, ES, FI, FR, IT, NL, PT, PL, RU, SV. Defaults to browser language.
    description ANS O The order description shown to the user
    sph-skip-form-notifications BOOLEAN O Skip errors displayed on the Payment Highway form and redirect directly to result URL (E.g. "Ecom payments disabled") . Default false.
    sph-exit-iframe-on-result BOOLEAN O Exit from iframe after redirection to result URLs.
    sph-exit-iframe-on-three-d-secure BOOLEAN O Exit from iframe when redirecting user to 3DS.
    sph-use-three-d-secure BOOLEAN O Force enable/disable 3DS authentication. Omit / null to use default configured parameter. Disable only if permitted by Your acquiring contract!
    sph-reference-number AN O Reference number. In RF-format or in Finnish reference number format. Used only when transactions are configured to be settled one by one.
    sph-splitting-merchant-id N O Sub-merchant ID from the settlements provider. Not to be confused with the sph-merchant value.
    sph-splitting-amount N O The amount settled to the sub-merchant's account. The rest will be considered as the main merchant's commission. In the smallest currency unit. E.g. 99.99 € = 9999.
    signature ANS M Message signature in the format 'SPH1 key-id authentication-string'

    Webhooks have same parameters as success, failure and cancel responses.

    Success Response for Payment

    On a successful operation the user is redirected to the given success URL sph-success-url.

    When a user is redirected to the success-url, it means we have successfully completed processing of the request. It does not however mean the card payment or tokenization was accepted by the authorizing parties. You will find out the actual result using the PaymentAPI (server-to-server) commit or tokenization requests.

    Parameter Data type Description
    sph-account AN Account identifier
    sph-merchant AN Account merchant identifier
    sph-order ORDER-ID Merchant defined order identifier
    sph-request-id UUID4 Request identifier
    sph-api-version VERSION API version number used in the request
    sph-session-id UUID4 Reference to the form session
    sph-amount N Amount in the lowest currency unit. E.g. 99,00 € = 9900
    sph-currency A Currency code "EUR"
    sph-transaction-id UUID4 Payment transaction identifier
    sph-timestamp TIMESTAMP Request timestamp in ISO 8601
    combined date and time in UTC.
    E.g. "2025-09-18T10:32:59Z"
    sph-success AN Static text “OK”
    signature ANS Message signature

    Failure Response for Payment

    On failure the user is redirected to the given failure URL sph-failure-url.

    A user is redirected to the failure-url, if processing of the request failed for example due to missing parameters, authentication issues or connectivity issues to the authorizing parties.

    Parameter Data type Description
    sph-account AN Account identifier from request
    sph-merchant AN Account merchant identifier from request
    sph-order ORDER-ID Merchant defined order identifier
    sph-request-id UUID4 Request identifier from request
    sph-api-version VERSION API version number used in the request
    sph-session-id UUID4 Reference to the form session
    sph-timestamp TIMESTAMP Response timestamp in ISO 8601
    combined date and time in UTC.
    E.g. 2025-09-18T10:33:49Z
    sph-failure AN Failure reason, one of:
    • "UNAUTHORIZED"
    • "INVALID"
    • "FAILURE"
    • "NO_ROUTE" (Equivalent to response code 940)
    • "MASTERPASS_NOT_SUPPORTED"
    • MASTERPASS
    • "THREE_D_SECURE" (Technical failure in 3D secure)
    • "SESSION_EXPIRED" (Payment or Tokenization form was expired before completion)
    signature ANS Message signature

    Cancel Response for Payment

    If the user cancels the operation they are redirected to the given cancel URL sph-cancel-url.

    Parameter Data type Description
    sph-account AN Account identifier from request
    sph-merchant AN Account merchant identifier from request
    sph-order ORDER-ID Merchant defined order identifier
    sph-request-id UUID4 Request identifier from request
    sph-api-version VERSION API version number used in the request
    sph-session-id UUID4 Reference to the form session
    sph-timestamp TIMESTAMP Response timestamp in ISO 8601
    combined date and time in UTC.
    E.g. 2025-09-18T10:33:49Z
    sph-cancel AN Cancel reason "CANCEL"
    signature ANS Message signature

    Payment & Add Card

    curl -i --data-urlencode '
    sph-account=test
    sph-merchant=test_merchantId
    sph-order=1000123A
    sph-request-id=f47ac10b-58cc-4372-a567-0e02b2c3d479
    sph-amount=990
    sph-currency=EUR
    sph-timestamp=2014-09-18T10:32:59Z
    sph-success-url=https://merchant.example.com/payment/success
    sph-failure-url=https://merchant.example.com/payment/failure
    sph-cancel-url=https://merchant.example.com/payment/cancel
    language=fi
    description=Example payment of 10 balloons á 0,99EUR
    signature= SPH1 testKey af9cf1b9a967f6415bb8c4dea8629db0d47edf8ee037c8af1a8bb0eb5aca68e1' \
        https://v1-hub-staging.sph-test-solinor.com/form/view/add_and_pay_with_card
    
    // Generate Add Card And Payment form parameters
    
    String amount = "1990";
    String currency = "EUR";
    String orderId = "1000123A";
    String description = "A Box of Dreams. 19,90€";
    
    FormContainer formContainer = formBuilder.addCardAndPaymentParameters(
                successUrl,
                failureUrl,
                cancelUrl,
                amount,
                currency,
                orderId,
                description
            )
            .build();
    
    // read form parameters
    String httpMethod = formContainer.getMethod();
    String actionUrl = formContainer.getAction();
    List<NameValuePair> fields = formContainer.getFields();
    
    for (NameValuePair field : fields) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="field.getName()" value="field.getValue()">
        * Or create GET-url:
        * ?field.getName()=field.getValue()&...
        */
        field.getName();
        field.getValue();
    }
    
    // Generate Add Card And Payment form parameters
    
    amount = 1990
    currency = "EUR"
    order_id = "1000123A"
    description = "A Box of Dreams. 19,90€"
    
    form_container = form_builder.add_and_pay_with_card_parameters(amount, currency, order_id, description)
    
    // read form parameters
    http_method = form_container.method
    action_url = form_container.action
    pairs = form_container.pairs // an array of PaymentHighway::NameValuePair
    
    pairs.each do |pair|
        name = pair.name
        value = pair.value
    end
    
    // Generate Add Card And Payment form parameters
    
    var amount = 1990;
    var currency = 'EUR';
    var orderId = '1000123A';
    var description = 'A Box of Dreams. 19,90€';
    
    var formContainer = formBuilder.generateAddCardAndPaymentParameters(
            successUri,
            failureUri,
            cancelUri,
            language,
            amount,
            currency,
            orderId,
            description
        );
    
    // read form parameters
    var httpMethod = formContainer.method;
    var actionUrl = formContainer.getAction();
    var fields = formContainer.nameValuePairs;
    
    fields.forEach(function(field) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="name" value="value">
        * Or create GET-url:
        * ?name=value&...
        */
        var name = field.first;
        var value = field.second;
    });
    
    <?php
    $amount = "1990";
    $currency = "EUR";
    $orderId = "1000123A";
    $description = "A Box of Dreams. 19,90€";
    
    $form = $formBuilder->generateAddCardAndPaymentParameters($amount, $currency, $orderId, $description);
    
    // read form parameters
    $httpMethod = $form->getMethod();
    $actionUrl = $form->getAction();
    $parameters = $form->getParameters();
    
    foreach ($parameters as $key => $value) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="$key" value="$value">
        * Or create GET-url:
        * ?$key=$value&...
        */
        echo $key .":". $value;
    }
    

    This method combines a payment and adding a new card to allow getting the card token after a successful payment with a single request.

    HTTP Request

    POST /form/view/add_and_pay_with_card

    The request and response parameters are exactly the same as in the Payment.

    Payment with token and CVC

    The CVC Form is shown in the Payment Highway. The response to the success-url contains a sph-transaction-id for committing the transaction through the Payment API.

    HTTP Request

    POST /form/view/pay_with_token_and_cvc

    Parameter Data type M/O Description
    sph-account AN M Account identifier
    sph-merchant AN M Account merchant identifier
    sph-order ORDER-ID M Merchant defined order identifier. Should be unique per transaction.
    sph-request-id UUID4 M Request identifier
    sph-amount N M Amount in the lowest currency unit. E.g. 99,00 € = 9900
    sph-currency A M Currency code "EUR"
    sph-timestamp TIMESTAMP M Request timestamp in ISO 8601
    combined date and time in UTC.
    E.g. "2025-09-18T10:32:59Z"
    sph-success-url URL M Success URL user is redirected to on success
    sph-failure-url URL M Failure URL user is redirected to on failure
    sph-cancel-url URL M Cancel URL user is redirected to on cancel
    sph-webhook-success-url URL O On success, server to server GET request will be made to this url with same parameters as success redirect.
    sph-webhook-failure-url URL O On failure, server to server GET request will be made to this url with same parameters as failure redirect.
    sph-webhook-cancel-url URL O On cancel, server to server GET request will be made to this url with same parameters as cancel redirect.
    sph-webhook-delay N O webhook call delay in seconds (MAX. 900). If omitted, default value 0 will be used.
    sph-token UUID4 M The card token to charge.
    sph-api-version VERSION O API version number
    language A O Language code (ISO 639-1). Supported languages are DE, EN, ES, FI, FR, IT, NL, PT, PL, RU, SV. Defaults to browser language.
    description ANS O The order description shown to the user
    sph-skip-form-notifications BOOLEAN O Skip errors displayed on the Payment Highway form and redirect directly to result URL (E.g. "Ecom payments disabled") . Default false.
    sph-exit-iframe-on-result BOOLEAN O Exit from iframe after redirection to result URLs.
    sph-exit-iframe-on-three-d-secure BOOLEAN O Exit from iframe when redirecting user to 3DS.
    sph-use-three-d-secure BOOLEAN O Force enable/disable 3DS authentication. Omit / null to use default configured parameter. Disable only if permitted by Your acquiring contract!
    sph-reference-number AN O Reference number. In RF-format or in Finnish reference number format. Used only when transactions are configured to be settled one by one.
    sph-splitting-merchant-id N O Sub-merchant ID from the settlements provider. Not to be confused with the sph-merchant value.
    sph-splitting-amount N O The amount settled to the sub-merchant's account. The rest will be considered as the main merchant's commission. In the smallest currency unit. E.g. 99.99 € = 9999.
    signature ANS M Message signature in the format 'SPH1 key-id authentication-string'

    Webhooks have same parameters as success, failure and cancel responses.

    Failure Response for Payment with token and CVC

    On failure the user is redirected to the given failure URL sph-failure-url.

    A user is redirected to the failure-url, if processing of the request failed for example due to missing parameters, authentication issues or connectivity issues to the authorizing parties.

    Parameter Data type Description
    sph-account AN Account identifier from request
    sph-merchant AN Account merchant identifier from request
    sph-order ORDER-ID Merchant defined order identifier
    sph-request-id UUID4 Request identifier from request
    sph-api-version VERSION API version number used in the request
    sph-session-id UUID4 Reference to the form session
    sph-timestamp TIMESTAMP Response timestamp in ISO 8601
    combined date and time in UTC.
    E.g. 2025-09-18T10:33:49Z
    sph-failure AN Failure reason, one of:
    • "UNAUTHORIZED"
    • "INVALID"
    • "FAILURE"
    • "NO_ROUTE" (Equivalent to response code 940)
    • "TOKEN_NOT_FOUND"
    • "THREE_D_SECURE" (Technical failure in 3D secure)
    • "MASTERPASS_NOT_SUPPORTED"
    • MASTERPASS
    • "SESSION_EXPIRED" (Payment or Tokenization form was expired before completion)
    signature ANS Message signature

    Success and Cancel Responses

    The Success and Cancel Responses are exactly the same as in the Payment.

    When a user is redirected to the success-url, it means we have successfully completed processing of the request. It does not however mean the card payment or tokenization was accepted by the authorizing parties. You will find out the actual result using the PaymentAPI (server-to-server) commit or tokenization requests.

    Payment with MobilePay

    curl -i --data-urlencode '
    sph-account=test
    sph-merchant=test_merchantId
    sph-order=1000123A
    sph-request-id=f47ac10b-58cc-4372-a567-0e02b2c3d479
    sph-amount=990
    sph-currency=EUR
    sph-timestamp=2014-09-18T10:32:59Z
    sph-success-url=https://merchant.example.com/payment/success
    sph-failure-url=https://merchant.example.com/payment/failure
    sph-cancel-url=https://merchant.example.com/payment/cancel
    language=fi
    description=Example payment of 10 balloons á 0,99EUR
    signature= SPH1 testKey af9cf1b9a967f6415bb8c4dea8629db0d47edf8ee037c8af1a8bb0eb5aca68e1' \
        https://v1-hub-staging.sph-test-solinor.com/form/view/mobilepay
    
    // Generate Add Card And Payment form parameters
    
    String amount = "1990";
    String currency = "EUR";
    String orderId = "1000123A";
    String description = "A Box of Dreams. 19,90€";
    Boolean exitIframeOnResult = null;
    String shopLogoUrl = "https://foo.bar/biz.png";
    
    FormContainer formContainer = formBuilder.mobilePayParametersBuilder(
                successUrl,
                failureUrl,
                cancelUrl,
                amount,
                currency,
                orderId,
                description,
                exitIframeOnResult,
                shopLogoUrl
            )
            .build();
    
    // read form parameters
    String httpMethod = formContainer.getMethod();
    String actionUrl = formContainer.getAction();
    List<NameValuePair> fields = formContainer.getFields();
    
    for (NameValuePair field : fields) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="field.getName()" value="field.getValue()">
        * Or create GET-url:
        * ?field.getName()=field.getValue()&...
        */
        field.getName();
        field.getValue();
    }
    
    // Generate Add Card And Payment form parameters
    
    var amount = 1990;
    var currency = 'EUR';
    var orderId = '1000123A';
    var description = 'A Box of Dreams. 19,90€';
    var exitIframeOnResult = undefined;
    var shopLogoUrl = 'https://foo.bar/biz.png';
    
    var formContainer = formBuilder.generatePayWithMobilePayParameters(
            successUri,
            failureUri,
            cancelUri,
            language,
            amount,
            currency,
            orderId,
            description,
            exitIframeOnResult,
            shopLogoUrl
        );
    
    
    // read form parameters
    var httpMethod = formContainer.method;
    var actionUrl = formContainer.getAction();
    var fields = formContainer.nameValuePairs;
    
    fields.forEach(function(field) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="name" value="value">
        * Or create GET-url:
        * ?name=value&...
        */
        var name = field.first;
        var value = field.second;
    });
    
    <?php
    $amount = "1990";
    $currency = "EUR";
    $orderId = "1000123A";
    $description = "A Box of Dreams. 19,90€";
    $exitIframeOnResult = null;
    $shopLogoUrl = "https://foo.bar/biz.png";
    
    $form = $formBuilder->generatePayWithMobilePayParameters(
            $amount,
            $currency,
            $orderId,
            $description,
            $exitIframeOnResult,
            $shopLogoUrl
        );
    
    // read form parameters
    $httpMethod = $form->getMethod();
    $actionUrl = $form->getAction();
    $parameters = $form->getParameters();
    
    foreach ($parameters as $key => $value) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="$key" value="$value">
        * Or create GET-url:
        * ?$key=$value&...
        */
        echo $key .":". $value;
    }
    

    This method opens either Danske Bank's MobilePay page or Danske Bank's MobilePay application, depending if user is making payment with handheld device or PC.


    Your card will not be charged.

    Simple flow

    1. Open MobilePay with Form API POST /form/view/mobilepay
      -> return an sph-transaction-id and signature as a GET parameters to the given success-url
    2. Commit payment with Payment API POST /transaction/<sph-transaction-id>/commit
      —> returns a result in JSON formatting

    HTTP Request

    POST /form/view/mobilepay

    Parameter Data type M/O Description
    sph-account AN M Account identifier
    sph-merchant AN M Account merchant identifier
    sph-order ORDER-ID M Merchant defined order identifier. Should be unique per transaction.
    sph-request-id UUID4 M Request identifier
    sph-amount N M Amount in the lowest currency unit. E.g. 99,00 € = 9900
    sph-currency A M Currency code "EUR"
    sph-shop-logo-url URL O The logo must be 250x250 pixel in .png format and must be hosted on a HTTPS (secure) server.
    sph-mobilepay-phone-number AN O Customer phone number with country code e.q. +358449876543. Makes it easier for the customer to identify himself toward the MPO Website.
    sph-mobilepay-shop-name Max 100 AN O Name of the shop/merchant. MobilePay app displays this under the shop logo. If omitted, the merchant name from PH is used.
    sph-timestamp TIMESTAMP M Request timestamp in ISO 8601
    combined date and time in UTC.
    E.g. "2025-09-18T10:32:59Z"
    sph-success-url URL M Success URL user is redirected to on success
    sph-failure-url URL M Failure URL user is redirected to on failure
    sph-webhook-success-url URL O On success, server to server GET request will be made to this url with same parameters as success redirect.
    sph-webhook-failure-url URL O On failure, server to server GET request will be made to this url with same parameters as failure redirect.
    sph-webhook-cancel-url URL O On cancel, server to server GET request will be made to this url with same parameters as cancel redirect.
    sph-webhook-delay N O webhook call delay in seconds (MAX. 900). If omitted, default value 0 will be used.
    sph-cancel-url URL M Cancel URL user is redirected to on cancel
    sph-api-version VERSION O API version number
    language A O Language code (ISO 639-1). Supported languages are DE, EN, ES, FI, FR, IT, NL, PT, PL, RU, SV. Defaults to browser language.
    description ANS O The order description shown to the user
    sph-exit-iframe-on-result BOOLEAN O Exit from iframe after redirection to result URLs.
    sph-reference-number AN O Reference number. In RF-format or in Finnish reference number format. Used only when transactions are configured to be settled one by one.
    sph-splitting-merchant-id N O Sub-merchant ID from the settlements provider. Not to be confused with the sph-merchant value.
    sph-splitting-amount N O The amount settled to the sub-merchant's account. The rest will be considered as the main merchant's commission. In the smallest currency unit. E.g. 99.99 € = 9999.
    signature ANS M Message signature in the format 'SPH1 key-id authentication-string'

    About shop logo in MobilePay

    Webhooks have same parameters as success, failure and cancel responses.

    Failure Response for Payment with MobilePay

    On failure the user is redirected to the given failure URL sph-failure-url.

    A user is redirected to the failure-url, if processing of the request failed for example due to missing parameters, authentication issues or connectivity issues to the authorizing parties.

    Parameter Data type Description
    sph-account AN Account identifier from request
    sph-merchant AN Account merchant identifier from request
    sph-order ORDER-ID Merchant defined order identifier
    sph-request-id UUID4 Request identifier from request
    sph-api-version VERSION API version number used in the request
    sph-session-id UUID4 Reference to the form session
    sph-timestamp TIMESTAMP Response timestamp in ISO 8601
    combined date and time in UTC.
    E.g. 2025-09-18T10:33:49Z
    sph-failure AN Failure reason, one of:
    • "UNAUTHORIZED"
    • "INVALID"
    • "FAILURE"
    • "NO_ROUTE" (Equivalent to response code 940)
    • "MOBILEPAY_NOT_SUPPORTED"
    • "MOBILEPAY"
    signature ANS Message signature

    Success and Cancel Responses

    The Success and Cancel Responses are exactly the same as in the Payment.

    When a user is redirected to the success-url, it means we have successfully completed processing of the request. It does not however mean the card payment or tokenization was accepted by the authorizing parties. You will find out the actual result using the PaymentAPI (server-to-server) commit or tokenization requests.

    Using Payment Highway and MobilePay in Mobile application

    Payment with Pivo

    
    // Generate Pivo form parameters
    
    Long amount = 1999;
    String orderId = "1000123A";
    String description = "A Box of Dreams. 19,90€";
    String phoneNumber = "+358441234567";
    String referenceNumber = "1313";
    
    FormContainer formContainer = formBuilder.pivoParametersBuilder(
        successUrl,
        failureUrl,
        cancelUrl,
        amount,
        orderId,
        description
    )
        .referenceNumber(referenceNumber)
        .phoneNumber(phoneNumber)
        .build();
    
    // read form parameters
    String httpMethod = formContainer.getMethod();
    String actionUrl = formContainer.getAction();
    List<NameValuePair> fields = formContainer.getFields();
    
    for (NameValuePair field : fields) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="field.getName()" value="field.getValue()">
        * Or create GET-url:
        * ?field.getName()=field.getValue()&...
        */
        field.getName();
        field.getValue();
    }
    
    
    // Generate Pivo form parameters
    
    var amount = 1990;
    var orderId = '1000123A';
    var description = 'A Box of Dreams. 19,90€';
    var phoneNumber = "+358441234567";
    var referenceNumber = "1313";
    
    var formContainer = formBuilder.generatePivoParameters(
        successUrl,
        failureUrl,
        cancelUrl,
        language,
        amount,
        orderId,
        description,
        referenceNumber,
        phoneNumber
    );
    
    // read form parameters
    var httpMethod = formContainer.method;
    var actionUrl = formContainer.getAction();
    var fields = formContainer.nameValuePairs;
    
    
    fields.forEach(function(field) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="name" value="value">
        * Or create GET-url:
        * ?name=value&...
        */
        var name = field.first;
        var value = field.second;
    });
    
    <?php
    $amount = "1990";
    $currency = "EUR";
    $orderId = "1000123A";
    $description = "A Box of Dreams. 19,90€";
    $phoneNumber = "+358441234567";
    $referenceNumber = "1313";
    
    $form = $formbuilder->generatePivoParameters(
                $amount,
                $orderId,
                $description,
                $phoneNumber,
                $referenceNumber
            );
    
    // read form parameters
    $httpMethod = $form->getMethod();
    $actionUrl = $form->getAction();
    $parameters = $form->getParameters();
    
    foreach ($parameters as $key => $value) {
        /*
        * Build the form for POST-request:
        * <input type="hidden" name="$key" value="$value">
        * Or create GET-url:
        * ?$key=$value&...
        */
        echo $key .":". $value;
    }
    

    Pivo is a Finnish mobile wallet. With different acquiring agreements, Pivo payments can be made with credit card, Siirto or bank transfer.

    HTTP Request

    POST /form/view/pivo

    Parameter Data type M/O Description
    sph-account AN M Account identifier
    sph-merchant AN M Account merchant identifier
    sph-order ORDER-ID M Merchant defined order identifier. Should be unique per transaction.
    sph-request-id UUID4 M Request identifier
    sph-amount N M Amount in the lowest currency unit. E.g. 99,00 € = 9900
    sph-currency A M Currency code. Only “EUR” supported.
    sph-timestamp TIMESTAMP M Request timestamp in ISO 8601
    combined date and time in UTC.
    E.g. "2025-09-18T10:32:59Z"
    sph-success-url URL M Success URL user is redirected to on success
    sph-failure-url URL M Failure URL user is redirected to on failure
    sph-cancel-url URL M Cancel URL user is redirected to on cancel
    sph-webhook-success-url URL O On success, server to server GET request will be made to this url with same parameters as success redirect.
    sph-webhook-failure-url URL O On failure, server to server GET request will be made to this url with same parameters as failure redirect.
    sph-webhook-cancel-url URL O On cancel, server to server GET request will be made to this url with same parameters as cancel redirect.
    sph-webhook-delay N O Webhook call delay in seconds (MAX. 900). If omitted, default value 0 will be used.
    sph-api-version VERSION O API version number
    description ANS O The order description shown to the user
    sph-exit-iframe-on-result BOOLEAN O Exit from iframe after redirection to result URLs.
    sph-reference-number AN O Reference number. In RF-format or in Finnish reference number format. If omitted, random reference number will be generated by us. Reference number is used when payment type is "siirto" or "account", but not in card payments. With contract where transactions are configured to be settled one by one, reference number is used in every payment method.
    sph-phone-number AN O When used, phone number will be prefilled to form. Use international format e.g. "+358441234567"
    sph-splitting-merchant-id N O Sub-merchant ID from the settlements provider. Not to be confused with the sph-merchant value.
    sph-splitting-amount N O The amount settled to the sub-merchant's account. The rest will be considered as the main merchant's commission. In the smallest currency unit. E.g. 99.99 € = 9999.
    signature ANS M Message signature in the format 'SPH1 key-id authentication-string'

    Webhooks have same parameters as success, failure and cancel responses.

    Success, Cancel and Failure Responses

    The Success, Cancel and Failure Responses are exactly the same as in the Payment. When a user is redirected to the success-url, it means we have successfully completed processing the payment request. Pivo transaction must not be committed.

    Pivo transactions must not be committed. After getting success-response, You should use Pivo transaction result- or Transaction status-query to get info about payment status.

    Payment API

    HTTP Interface

    The system consists of different resources accessible via HTTPS protocol using the defined mandatory headers for authentication and UTF-8 JSON body for the POST requests.

    HTTP response code is always 200 for successful HTTP calls. Anything else indicates a system or communication level failure.

    Mandatory headers for both requests and responses are Content-Type, Content-Length and the Custom Headers. Valid values for Content-Type and Content-Length are "application/json; charset=utf-8" and the correct body byte length using UTF-8 encoding.

    Headers

    In addition to the standard headers, the following custom headers are used.

    All the HTTP requests must contain the following headers:

    1. Signature: ”” = The signature header used for authentication and message consistency, see the following section.
    2. SPH-Account: ”example_account”= (High level) account name associated with the authentication key.
    3. SPH-Merchant: ”example_merchant” = The account’s sub-account, which provides optional merchant level customization.
    4. SPH-Timestamp: “yyyy-MM-dd'T'HH:mm:ss'Z'” = Contains the client’s request time in UTC format. Server will check the timestamp does not differ more than five (5) minutes from the correct global UTC time.
    5. SPH-Request-Id: ”12ade018-c562-40bc-a4e6-7f63c69fd90a” = Unique one-time- use Request ID in UUID4 format.

    Optionally the HTTP request may contain the following headers:

    1. Sph-Api-Version: “yyyyMMdd” = The version date of the JSON response schema. Defaults to “20141215”.

    All the HTTP responses contain the following headers:

    1. Signature: ”” see the following section.
    2. SPH-Response-Id: ”03c15388-bebc-4872-b3f5-faed0ca65ff6” = Unique one-time- use Response ID in UUID4 format.
    3. SPH-Timestamp: “yyyy-MM-dd'T'HH:mm:ss'Z'” which contains the servers response time in UTC format. When the client receives the response, the timestamp must be checked and it must not differ more than five (5) minutes from the correct global UTC time.
    4. SPH-Request-Id: ”12ade018-c562-40bc-a4e6-7f63c69fd90a” = Same as the request UUID4.

    Errors

    try {
      // Use Payment Highway's bindings...
    } catch (AuthenticationException e) {
      // signals a failure to authenticate Payment Highway response
    } catch (HttpResponseException e) {
      // Signals a non 2xx HTTP response.
      // Invalid parameters were supplied to Payment Highway's API
    } catch (IOException e) {
      // Signals that an I/O exception of some sort has occurred
    } catch (Exception e) {
      // Something else happened
    }
    
    begin
      // Use Payment Highway's bindings...
    rescue PaymentHighway::Exception::AuthenticationException => e
      // Signals a failure to authenticate Payment Highway response
    rescue PaymentHighway::Exception::HttpResponseException => e
      // Signals a non 2xx HTTP response or a 2xx HTTP response not containing the required headers
      // Invalid parameters were supplied to Payment Highway's API
    rescue ArgumentError => e
      // A function was called with an argument of invalid type
    rescue RuntimeError => e
      // PaymentHighway functioned in an unexpected way
    rescue Exception => e
      // Something else happened
    
    PaymentHighwayAPI.initTransaction()
      .then(function(initResponse){
        // handle response
        ...
      })
      .catch(function(error) {
        // handle errors
        ...
      });
    
    <?php
    try {
        // Use Payment Highway's bindings...
    }
    catch (Exception $e) {
        // Something else happened
    }
    

    Payment Highway clients can raise exceptions for several reasons. Payment Highway authenticates each request and if there is invalid parameters or a signature mismatch, a HttpResponseException is raised.

    The Payment Highway clients also authenticate response messages, and in case of signature mismatch an AuthenticationException will be raised.

    It is recommended to gracefully handle exceptions from the API.

    Authentication

    String serviceUrl = "https://v1-hub-staging.sph-test-solinor.com";
    String signatureKeyId = "testKey";
    String signatureSecret = "testSecret";
    String account = "test";
    String merchant = "test_merchantId";
    
    try (PaymentAPI paymentAPI = new PaymentAPI(serviceUrl, signatureKeyId, signatureSecret, account, merchant)) {
      // Use paymentAPI to create debit requests etc.
    }
    
    service_url = "https://v1-hub-staging.sph-test-solinor.com"
    signature_key_id = "testKey"
    signature_secret = "testSecret"
    account = "test"
    merchant = "test_merchantId"
    
    payment_api = PaymentHighway::PaymentApi.new(service_url, signature_key_id, signature_secret, account, merchant)
      // Use payment_api to create debit requests etc.
    
    var serviceUrl = "https://v1-hub-staging.sph-test-solinor.com";
    var testKey = 'testKey';
    var testSecret = 'testSecret';
    var account = 'test';
    var merchant = 'test_merchantId';
    
    var paymentAPI = new PaymentAPI(
                    serviceUrl,
                    testKey,
                    testSecret,
                    account,
                    merchant
            );
    // Use paymentAPI to create debit requests etc.
    
    <?php
    use Solinor\PaymentHighway\PaymentApi;
    
    $serviceUrl = "https://v1-hub-staging.sph-test-solinor.com";
    $signatureKeyId = "testKey";
    $signatureSecret = "testSecret";
    $account = "test";
    $merchant = "test_merchantId";
    
    $paymentApi = new PaymentApi(
                        $serviceUrl,
                        $signatureKeyId,
                        $signatureSecret,
                        $account,
                        $merchant
                    );
    
    

    Signatures

    Request authentication and the response signatures are calculated by applying the HMAC- SHA256 method (RFC 2104 - Keyed-Hashing for Message Authentication, http://www.ietf.org/rfc/rfc2104.txt) to the defined concatenated string using the secret key provided to the account user.

    A signature is transmitted Hex encoded in the ”Signature” HTTP header with the signature value prefixed with the strings “SPH1” and “secretKeyID”, where the secretKeyID is the ID of the key used in the HMAC calculation. The strings are separated with blank spaces (0x20) thus the header would look like: “Signature: SPH1 secretKeyId signature”

    The concatenated string consists of the following fields separated with a new line (“\n”):

    # Example of a string used for signature calculation
    POST
    /transaction/859cefdf-41fa-453a-a6a5-beff35e2f3b8/debit
    sph-account:test
    sph-merchant:test_merchantId
    sph-request-id:12ade018-c562-40bc-a4e6-7f63c69fd90a
    sph-timestamp:2014-09-18T14:09:25Z
    {”some”:”body”{”json”:1}}
    

    The client must check the response signature in order to verify the authenticity of the response.

    Message body

    The messaging format is standard compliant JSON using UTF-8 encoding. Each request and response has a set of mandatory and optional fields, which values are validated using the included regular expression rules. A GET request does not have a request body whereas a POST request often does, and both of these always receive response body.

    Initialize Add Card Form via Backend

    
    
    
    
    
    

    Initialize a new Add Card form via Payment API (backend-to-backend).

    The Add Card form allows the end user to submit their payment card information, which is then securely stored to Payment Highway. The merchant receives tokenization ID via the given redirection success url and optionally the webhook. The tokenization ID is used to fetch the actual card token, used to charge the card.

    Technically this is the same as add card via Form API, but the URL for the Add Card form is immediately returned in the response of this request, instead of requiring the end user's browser to POST the details via an HTML page, in order to initialize the Add Card form.

    when using API version "20210412" or above, sph-session-id and sph-api-version query parameter are included in the success, cancel and failure redirections and webhook calls.

    HTTP Request

    POST /form/init/add_card

    Object request fields
    1. return_urlsmandatoryobject

      The URLs where to redirect the user and send the webhook requests to, upon completion of the form.

      child fields
    2. strong_customer_authenticationmandatoryobject

      Information used in transaction risk analysis (TRA) and can increase the likelihood of the transaction being considered low risk, possibly skipping the requirements of strong customer authentication.

      child fields
    3. languageANS

      Two letter language code (ISO 639-1). Supported languages are DE, EN, ES, FI, FR, IT, NL, PT, PL, RU, SV. Defaults to browser language.

    4. customerobject

      child fields
    5. skip_form_notificationsBOOLEAN

      Skip errors displayed on the Payment Highway form and redirect directly to result URL (E.g. "Ecom payments disabled") . Default false.

    HTTP Response

    Object response fields
    1. urlmandatoryURL

      The form URL where the user is redirected to. After submitting the form the user will be sent to one of the specified return URLs.

    2. valid_untilmandatoryTIMESTAMP

      Session expriration time.

    3. session_idmandatoryUUID4

      Session ID used to fetch the state and details of the form session.

    4. resultobject

      child fields

    Commit Payment

    Commit Form Payment

    curl -i \
      -H "Content-Length: 32" \
      -H "Content-Type: application/json" \
      -H "SPH-Account: test" \
      -H "SPH-Api-Version: 20191204" \
      -H "SPH-Merchant: test_merchantId" \
      -H "SPH-Request-Id: 1820d2f1-c001-408e-b842-34bfa6b2758d" \
      -H "SPH-Timestamp: 2018-10-04T10:41:15Z" \
      -H "Signature: SPH1 testKey 1918e69a5dd06fe48844bc3317c9ca257a1fb720bebe25a7da2b3272ee0ff35a" \
      --data '{"currency":"EUR","amount":2500}' \
      https://v1-hub-staging.sph-test-solinor.com/transaction/52ea5beb-343b-4516-ab70-ede2baa058c8/commit
      # Replace the transaction ID with the one retrieved from the Form API sph-transaction-id return parameter.
    
    String transactionId = "52ea5beb-343b-4516-ab70-ede2baa058c8"; // get sph-transaction-id as a GET parameter
    String amount = "2499";
    String currency = "EUR";
    CommitTransactionResponse response = paymentAPI.commitTransaction(transactionId, amount, currency);
    
    response.getResult().getCode(); // 100
    
    transaction_id = "52ea5beb-343b-4516-ab70-ede2baa058c8" # get sph-transaction-id as a GET parameter
    amount = 2499
    currency = "EUR"
    commit_transaction_response = payment_api.commit_transaction(transaction_id, amount, currency)
    
    commit_transaction_response.result.code // 100
    
    var transactionId = '52ea5beb-343b-4516-ab70-ede2baa058c8'; // get sph-transaction-id as a GET parameter
    var amount = 2499;
    var currency = 'EUR';
    var request = new paymentHighway.CommitTransactionRequest(amount, currency);
    
    paymentAPI.commitTransaction(transactionId, request)
        .then(function(response){
            var resultCode = response.result.code; // Should be 100, if OK
        });
    
    <?php
    $transactionId = "52ea5beb-343b-4516-ab70-ede2baa058c8"; // get sph-transaction-id as a GET parameter
    $amount = 2499;
    $currency = "EUR";
    
    $response = $paymentApi->commitFormTransaction($transactionId, $amount, $currency );
    
    $response->body->result->code; // 100
    

    JSON Response

    {
      "committed": true,
      "committed_amount": 2499,
      "card_token": "77ffbaca-9658-4aef-ac9e-f85da3164bdb",
      "recurring": true,
      "filing_code": "181004705200",
      "cardholder_authentication": "no",
      "card": {
        "type": "Visa",
        "partial_pan": "0024",
        "expire_year": "2023",
        "expire_month": "11",
        "cvc_required": "no",
        "bin": "415301",
        "funding": "debit",
        "country_code": "FI",
        "category": "unknown",
        "card_fingerprint": "da6b0df36efd17c0e7f6967b9e440a0c61b6bd3d96b62f14c90155a1fb883597",
        "pan_fingerprint": "e858e18daac509247f463292641237d6a74ce44e0971ba2de4a14874928a8805"
      },
      "result": {
        "code": 100,
        "message": "OK"
      }
    }
    

    In order to finalize (capture) a payment performed via Form API ("Payment", "Payment & Add Card" or "Payment with token and CVC"), the corresponding sph-transaction-id must be committed.

    The same applies for a "Charge a card" payment API request when the automatic commit is disabled for auth & capture using the "commit" parameter as "false". In this case the transaction ID must be committed as well.

    The commit amount must be equal or less than the original payment amount. One payment can only be committed once.

    Up to 7 days old transactions can be committed.

    In order to find out the result of the form payment without committing it, use the "Transaction result" request instead.

    HTTP Request

    POST /transaction/<:transaction_id>/commit

    Object request fields
    1. amountmandatoryAMOUNT

      Amount in the smallest currency unit. E.g. 99.99 € = 9999

    2. currencymandatoryCURRENCY

      ISO 4217 currency code

    HTTP Response

    Object response fields
    1. card_tokenUUID4

      Present on a successful commit. See also card.cvc_required below.

    2. cardobject

      Present on a successful commit. See also card.cvc_required below.

      child fields
    3. customerobject

      child fields
    4. committedmandatoryBOOLEAN

    5. committed_amountmandatoryAMOUNT

      Omitted if "committed" is false

    6. filing_codeAN

    7. approved_amountmandatoryAMOUNT

      Approved amount that covers only automated fuel dispenser case when supports_partial_approval is used in the request.

    8. reference_numberAN

      Reference number. In RF-format or in Finnish reference number format.

    9. resultobject

      child fields
    10. acquirerobject

      child fields
    11. acquirer_response_codeAN

      Acquirer specific response code

    12. authorizerAN

      The card issuer or scheme network which gave the authorization response (acquirer_response_code)

    Transaction result

    Used to find out whether or not an uncommitted transaction succeeded, without actually committing (capturing) it.

    For Pivo payments, check Pivo transaction result

    HTTP Request

    GET /transaction/<:transaction_id>/result

    Responses

    Responses are exactly the same as in the Commit.

    Pivo transaction result

    
    UUID transactionId = UUID.fromString("327c6f29-9b46-40b9-b85b-85e908015d92");
    PivoTransactionResultResponse response = paymentAPI.pivoTransactionResult(transactionId);
    
    
    paymentAPI.pivoTransactionResult(transactionId).then(function(res) {
        const transactionResult = res;
      });
    
    
    <?php
    $response = $paymentApi->pivoTransactionResult($transactionId);
    
    

    JSON Response for Pivo transaction

    {
      "state": "refunded",
      "current_amount": 990,
      "amount": 1000,
      "payment_type": "siirto",
      "archive_id": "20180523593064010087",
      "customer": {
        "network_address": "127.0.0.1"
      },
      "reference_number": "1805231300333",
      "result": {
        "code": 100,
        "message": "OK"
      }
    }
    

    Used to find out whether or not a Pivo transaction succeeded.

    HTTP Request

    GET /transaction/<:transaction_id>/pivo/result

    Responses

    Pivo transaction response object fields
    1. statemandatoryA

      Pivo transaction state (‘pending’, ‘paid’, ‘cancelled’, ‘rejected’ or ‘refunded’)

    2. customerobject

      child fields
    3. amountmandatoryAMOUNT

      Amount in the smallest currency unit. E.g. 99.99 € = 9999

    4. current_amountAMOUNT

      Amount after possible reversals

    5. reference_numberAN

      Reference number. In RF-format or in Finnish reference number format.

    6. archive_idAN

    7. payment_typeA

      Payment method of the Pivo payment. ‘account’: Payment order paid as Bank account transfer, ‘card’: Payment order paid as Card payment, ‘siirto’ Payment order paid as siirto payment.

    8. resultobject

      child fields

    Charge a card

    In order to do safe transactions, an execution model is used where the first call to /transaction acquires a financial transaction handle, later referred as “ID”, which ensures the transaction is executed exactly once. Afterwards it is possible to execute a debit transactions using the received ID handle. If the execution fails, the command can be repeated in order to confirm the transaction with the particular ID has been processed. After executing the command, the status of the transaction can be checked by executing a GET request to the /transaction/<:transaction_id> resource.

    Init transaction handle

    Init the transaction handle and get the ID for it.

    Init transaction handle

    curl -i \
      -H "Content-Length: 0" \
      -H "Content-Type: application/json" \
      -H "SPH-Account: test" \
      -H "SPH-Api-Version: 20191204" \
      -H "SPH-Merchant: test_merchantId" \
      -H "SPH-Request-Id: 83d6195d-b2f5-4d65-a5cd-7289dda1811c" \
      -H "SPH-Timestamp: 2018-10-04T10:19:45Z" \
      -H "Signature: SPH1 testKey 6ee85e625fa2bd1fafa6cef6a7f9fe3b7a81e62115f24ece1cff70b8338d928d" \
      --data '' \
      https://v1-hub-staging.sph-test-solinor.com/transaction
    
    InitTransactionResponse initResponse = paymentAPI.initTransaction();
    
    initResponse.getResult().getCode(); // 100
    
    init_response = payment_api.init_transaction_handle
    
    init_response.result.code // 100
    
    paymentAPI.initTransaction()
        .then(function(response){
            var resultCode = response.result.code; // 100
        });
    
    <?php
    $response = $paymentApi->initTransaction();
    
    $response->body->result->code; // 100
    

    JSON Response

    {
      "id": "52ea5beb-343b-4516-ab70-ede2baa058c8",
      "result": {
        "code": 100,
        "message": "OK"
      }
    }
    

    HTTP Request

    POST /transaction

    HTTP Response

    Object response fields

    1. idmandatoryUUID4

      The handle for the following requests.

    2. resultobject

      child fields

    Charging a card token

    After the introduction of the European PSD2 directive, the electronic payment transactions are categorised in so called customer initiated transactions (CIT) and merchant initiated transactions (MIT).

    Customer initiated transactions are scenarios, where the customer actively takes part in the payment process. This also includes token, or "one-click" purchases, where the transaction uses a previously saved payment method.

    Merchant initiated transactions are payments triggered without the customer's participation. This kind of transactions can be used for example in scenarios where the final price is not known at the time of the purchase or the customer is not present when the charge is made. A prior agreement, or "mandate" between the customer and the merchant is required.

    Charging a customer initiated transaction (CIT)

    Urls returnUrls = Urls.Builder(
        "https://example.com/success/12345",
        "https://example.com/failure/12345",
        "https://example.com/cancel/12345"
    )
        .setWebhookSuccessUrl("https://example.com/success/12345/?webhook=1")
        .setWebhookCancelUrl("https://example.com/failure/12345/?webhook=1")
        .setWebhookFailureUrl("https://example.com/webhook/failure/?webhook=1")
        .build();
    
    CustomerDetails customerDetails = CustomerDetails.Builder()
        .setShippingAddressMatchesBillingAddress(true)
        .setName("Eric Example")
        .setEmail("eric.example@example.com")
        // ...
        .build();
    
    StrongCustomerAuthentication strongCustomerAuthentication = new StrongCustomerAuthentication.Builder(returnUrls)
        .setCustomerDetails(customerDetails)
        // ...
        .build();
    
    Token cardToken = new Token("49026753-ff50-4c35-aff0-0335a26ea0ff");
    
    ChargeCitRequest request = new ChargeCitRequest.Builder(
        cardToken,
        123L,
        "EUR",
        "order-123456",
        strongCustomerAuthentication
    ).build();
    
    String requestId = request.getRequestId();
    
    UUID transactionId = paymentAPI.initTransaction().getId();
    ChargeCitResponse citResponse = paymentAPI.chargeCustomerInitiatedTransaction(transactionId, request);
    
    const token = new paymentHighway.Token('tokenId');
    const amount = 1990;
    const currency = 'EUR';
    const returnUrls = ReturnUrls.Builder(
                "https://example.com/success", // URL the user is redirected after succesful 3D-Secure authentication if strong customer authentication is required
                "https://example.com/cancel", // URL the user is redirected after cancelled 3D-Secure authentication if strong customer authentication is required
                "https://example.com/failure" // URL the user is redirected after failed 3D-Secure authentication if strong customer authentication is required
            )
            .setWebhookSuccessUrl("https://example.com/success/12345/?webhook=1")
            .setWebhookCancelUrl("https://example.com/failure/12345/?webhook=1")
            .setWebhookFailureUrl("https://example.com/webhook/failure/?webhook=1")
            .build();
    const customerDetails = CustomerDetails.Builder()
            .setShippingAddressMatchesBillingAddress(true)
            .setName('Eric Example')
            .setEmail('eric.example@example.com')
            // ...
            .build();
    const sca = StrongCustomerAuthentication.Builder(returnUrls)
            .setCustomerDetails(customerDetails)
            // Optionally other information about the customer and purchase to help in transaction risk analysis (TRA)
            .build();
    
    
    return paymentAPI.chargeCustomerInitiatedTransaction(transactionId, new ChargeCitRequest(token, amount, currency, sca));
    
    <?php
    $token = new \Solinor\PaymentHighway\Model\Token( $tokenId );
    
    $strongCustomerAuthentication = new \Solinor\PaymentHighway\Model\Sca\StrongCustomerAuthentication(
        new \Solinor\PaymentHighway\Model\Sca\ReturnUrls(
            "https://example.com/success", // URL the user is redirected after succesful 3D-Secure authentication if strong customer authentication is required
            "https://example.com/cancel", // URL the user is redirected after cancelled 3D-Secure authentication if strong customer authentication is required
            "https://example.com/failure" // URL the user is redirected after failed 3D-Secure authentication if strong customer authentication is required
        )
        // Optinally other information about the customer and purchase to help in transaction risk analysis (TRA)
    );
    
    $transaction = new \Solinor\PaymentHighway\Model\Request\CustomerInitiatedTransaction( $token, $amount, $currency, $strongCustomerAuthentication );
    
    $response = $paymentApi->chargeCustomerInitiatedTransaction( $transactionId, $transaction);
    

    When charging a token using customer initiated transaction, applicable exemptions are attempted in order to avoid the need for strong customer authentication, 3D Secure. These exemptions may include but are not limited to: low-value (under 30 EUR) or transaction risk analysis.

    Regardless, there is always a possibility the card issuer requires strong customer authentication by requesting a step-up. In this case, the response will contain "soft decline" result code 400 and an URL, where the customer needs to be redirected to, in order to perform the authentication. The merchant's URLs where the customer will be redirected back to - after completing the authentication - need to be defined in the return_urls parameter in strong_customer_authentication.

    When the customer is redirected back to the success URL, after completing the payment using strong customer authentication, the payment needs to be committed exactly as in the normal FormAPI payment flow.

    The merchant supplied "order", the request ID, or custom merchant parameters specified in the return URLs, can be used to connect the returning customer to the specific payment.

    In addition to the return urls, the strong_customer_authentication object contains many optional fields for information about the customer and the transaction. This information is used in transaction risk analysis (TRA) and may increase the likelihood of transaction being considered as low-risk, thus avoiding the need for strong authentication.

    HTTP Request

    POST /transaction/<:transaction_id>/card/charge/customer_initiated

    Object request fields
    1. amountmandatoryAMOUNT

      Amount in the smallest currency unit. E.g. 99.99 € = 9999

    2. currencymandatoryCURRENCY

      ISO 4217 currency code

    3. tokenobject

      Either `card` or `token` must be included

      child fields
    4. cardobject

      Usage of card is for PCI DSS certified parties only. Typically use token instead.

      child fields
    5. ordermandatoryORDER-ID

      Merchant defined order identifier

    6. customerobject

      child fields
    7. commitBOOLEAN

      If omitted, true is used

    8. splittingobject

      Splits the payment into sub-merchant settlement and the main merchant commission. Requires separate activation. Note: The commission will not be refunded in case of a settled payment (committed transaction after 22:00 UTC). Instead the sub-merchant's account will be used for the money transfer.

      child fields
    9. strong_customer_authenticationmandatoryobject

      Information used in transaction risk analysis (TRA) and can increase the likelihood of the transaction being considered low risk, possibly skipping the requirements of strong customer authentication. Includes return URLs object with webhooks for receiving the results.

      child fields
    10. supports_partial_approvalBOOLEAN

      Support partial approval for this transaction. Only available for Automated Fuel Dispensers.

    11. is_estimated_amountBOOLEAN

      Flag to set to `true` if the amount is estimated and will likely be changed. Should be set to `true` for Automated Fuel Dispensers.

    HTTP Response

    Object response fields
    1. resultobject

      child fields
    2. three_d_secure_urlURL

      Populated in case of soft decline result code "400" (Issuer requests 3DS step-up). The URL to redirect the cardholder to, for strong customer authentication.

    3. acquirerobject

      child fields
    4. acquirer_response_codeAN

      Acquirer specific response code

    5. authorizerAN

      The card issuer or scheme network which gave the authorization response (acquirer_response_code)

    6. approved_amountAMOUNT

      Approved amount that covers only automated fuel dispenser case when supports_partial_approval is used in the request.

    Charging a CIT for Automated Fuel Dispenser (AFD)

    The general CIT flow is partially modified for the Automated Fuel Dispenser use case.

    When making a charge request, the following fields should be set to appropriate values:

    If partial approval is supported, the approved_amount in the response must be observed for the actual amount that is available for the transaction.

    After the final amount of the transaction is known an advice message with the full amount should be sent. This will adjust the reserved amount of the transaction in real-time. The advice message must be sent within 20 minutes of creating an original charge request. Please note that amount parameter in the advice message is the final amount as opposed to amount in the revert message where amount parameter is the cancelled amount.

    After the amount was adjusted to the final amount a commit message with the final amount can be sent.

    In case the transaction is aborted a revert should be sent instead of the advice message.

    Charging a merchant initiated transaction (MIT)

    Token cardToken = new Token("49026753-ff50-4c35-aff0-0335a26ea0ff");
    
    ChargeMitRequest request = ChargeMitRequest.Builder(cardToken, 99L, "EUR", "order-123456").build();
    
    String requestId = request.getRequestId();
    
    UUID transactionId = paymentAPI.initTransaction().getId();
    ChargeMitResponse chargeMitResponse = paymentAPI.chargeMerchantInitiatedTransaction(transactionId, request);
    
    
    var token = new paymentHighway.Token('tokenId');
    var amount = 1990;
    var currency = 'EUR';
    
    return paymentAPI.chargeMerchantInitiatedTransaction(transactionId, new ChargeMitRequest(token, amount, currency));
    
    <?php
    $token = new \Solinor\PaymentHighway\Model\Token( $tokenId );
    
    $transaction = new \Solinor\PaymentHighway\Model\Request\Transaction( $token, $amount, $currency );
    
    $response = $paymentApi->chargeMerchantInitiatedTransaction( $transactionId, $transaction);
    

    This method should be used when charging the customer's card in a context, where the customer is not actively participating in the transaction.

    The MIT transactions are exempt from the strong customer authentication requirements of PSD2, thus the payment cannot receive the "soft decline" response (code 400), unlike in the case of customer initiated transactions.

    HTTP Request

    POST /transaction/<:transaction_id>/card/charge/merchant_initiated

    Object request fields
    1. amountmandatoryAMOUNT

      Amount in the smallest currency unit. E.g. 99.99 € = 9999

    2. currencymandatoryCURRENCY

      ISO 4217 currency code

    3. tokenobject

      Either `card` or `token` must be included

      child fields
    4. cardobject

      Usage of card is for PCI DSS certified parties only. Typically use token instead.

      child fields
    5. ordermandatoryORDER-ID

      Merchant defined order identifier

    6. customerobject

      child fields
    7. commitBOOLEAN

      If omitted, true is used

    8. splittingobject

      Splits the payment into sub-merchant settlement and the main merchant commission. Requires separate activation. Note: The commission will not be refunded in case of a settled payment (committed transaction after 22:00 UTC). Instead the sub-merchant's account will be used for the money transfer.

      child fields

    HTTP Response

    Object response fields
    1. resultobject

      child fields
    2. filing_codeAN

    3. approved_amountAMOUNT

      Approved amount that covers only automated fuel dispenser case when supports_partial_approval is used in the request. Omitted on failure

    4. acquirerobject

      child fields
    5. acquirer_response_codeAN

      Acquirer specific response code

    6. authorizerAN

      The card issuer or scheme network which gave the authorization response (acquirer_response_code)

    Apple Pay Debit Transaction

    How to implement Apple Pay

    1. Request a Certificate Signing Request (CSR) from support@paymenthighway.fi for Apple Pay on your site or app.
    2. Sign the CSR in your Apple Developer account and send the Apple Pay Payment Processing Certificate to us.
    3. Implement Apple Pay into your app or web site following Apple's documentation.
    4. Make an Apple Pay debit request to us to charge the card in the Payment Data received from Apple.

    Init transaction handle

    Init the transaction handle and get the ID for it.

    Init transaction handle

    curl -i \
      -H "Content-Length: 0" \
      -H "Content-Type: application/json" \
      -H "SPH-Account: test" \
      -H "SPH-Api-Version: 20191204" \
      -H "SPH-Merchant: test_merchantId" \
      -H "SPH-Request-Id: 83d6195d-b2f5-4d65-a5cd-7289dda1811c" \
      -H "SPH-Timestamp: 2018-10-04T10:19:45Z" \
      -H "Signature: SPH1 testKey 6ee85e625fa2bd1fafa6cef6a7f9fe3b7a81e62115f24ece1cff70b8338d928d" \
      --data '' \
      https://v1-hub-staging.sph-test-solinor.com/transaction
    
    InitTransactionResponse initResponse = paymentAPI.initTransaction();
    
    initResponse.getResult().getCode(); // 100
    
    init_response = payment_api.init_transaction_handle
    
    init_response.result.code // 100
    
    paymentAPI.initTransaction()
        .then(function(response){
            var resultCode = response.result.code; // 100
        });
    
    <?php
    $response = $paymentApi->initTransaction();
    
    $response->body->result->code; // 100
    

    JSON Response

    {
      "id": "52ea5beb-343b-4516-ab70-ede2baa058c8",
      "result": {
        "code": 100,
        "message": "OK"
      }
    }
    

    HTTP Request

    POST /transaction

    HTTP Response

    Object response fields

    1. idmandatoryUUID4

      The handle for the following requests.

    2. resultobject

      child fields

    Charge the card with amount

    long amount = 1990L;
    String currency = "EUR";
    
    InitTransactionResponse initResponse = paymentAPI.initTransaction();
    
    PaymentData paymentData = (new JsonParser).mapResponse(jsonFromApplePay, PaymentData.class);
    
    ApplePayTransactionRequest request = ApplePayTransactionRequest
      .Builder(paymentData, amount, currency)
      .build();
    
    TransactionResponse response = paymentAPI.debitApplePayTransaction(initResponse.getId, request);
    
    response.getResult().getCode(); // 100
    
    // Apple Pay Debit with Apple Pay Payment Token
    
    var amount = 1990;
    var currency = 'EUR';
    
    var paymentToken = JSON.parse('...');
    
    paymentAPI.initTransaction()
        .then(function (init) {
            var request = ApplePayTransactionRequest.Builder(paymentToken, amount, currency).build();
    
            return paymentAPI.debitApplePayTransaction(init.id, request);
        })
        .then(function(debit) {
            var resultCode = debit.result.code; // 100
        });
    

    Create Apple Pay debit request

    HTTP Request

    POST /transaction/<:transaction_id>/debit_applepay

    Object request fields
    1. amountmandatoryAMOUNT

      Amount in the smallest currency unit. E.g. 99.99 € = 9999

    2. currencymandatoryCURRENCY

      ISO 4217 currency code

    3. payment_datamandatoryobject

      Apple Pay Top-Level Structure

      child fields
    4. commitBOOLEAN

      If omitted, true is used

    5. customerobject

      child fields
    6. orderORDER-ID

      Merchant defined order identifier

    7. splittingobject

      Splits the payment into sub-merchant settlement and the main merchant commission. Requires separate activation. Note: The commission will not be refunded in case of a settled payment (committed transaction after 22:00 UTC). Instead the sub-merchant's account will be used for the money transfer.

      child fields

    HTTP Response

    Same response as Merchant initiated transaction (MIT)

    MobilePay app based payment flow

    Using this flow users can be moved directly to MobilePay app without using Form API and browser which will result in smoother user experience.

    It is important to check that user has MobilePay app installed before using payment flow with app.

    Using Payment Highway and MobilePay in Mobile application

    Initialize MobilePay payment with app flow.

    // Initialize MobilePay payment session
    
    long amount = 1990L;
    String currency = "EUR";
    String order = UUID.randomUUID().toString()
    
    MobilePayInitRequest request = MobilePayInitRequest.Builder(amount, currency)
       .setOrder(order)
       .setReturnUri("myapp://paid")
       .setWebhookSuccessUrl("https://backend.myapp.com/success")
       .setWebhookCancelUrl("https://backend.myapp.com/cancel")
       .setWebhookFailureUrl("https://backend.myapp.com/failure")
       .build();
    
    MobilePayInitResponse response = paymentApi.initMobilePaySession(request);
    response.getSessionToken();
    response.getUri(); // start MobilePay app with this uri
    response.getResult().getCode(); // 100
    
    const amount = 1990;
    const currency = 'EUR';
    const orderId = 'orderid';
    
    const request = MobilePayInitRequest.Builder(amount, currency)
      .setOrder(orderId)
      .setReturnUri('myapp://paid')
      .setWebhookSuccessUrl('https://myserver.com/success')
      .setWebhookCancelUrl('https://myserver.com/cancel')
      .setWebhookFailureUrl('https://myserver.com/failure')
      .build()
    
    api.initMobilePaySession(request)
      .then(function (init) {
        const token = init.session_token;
        const uri = init.uri; // start MobilePay app with this uri
        const resultCode = init.result.code; // 100
      });
    

    Json request

    {
      "amount": 1990,
      "currency": "EUR",
      "order": "order",
      "return_uri": "myapp://paid",
      "webhook_success_url": "https://backend.myapp.com/success",
      "webhook_cencel_url": "https://backend.myapp.com/cancel",
      "webhook_failure_url": "https://backend.myapp.com/failure"
    }
    

    Json response

    {
      "session_token": "0001-01-01-00.00.00.000000",
      "uri": "mobilepayonline://online?sessiontoken=0001-01-01-00.00.00.000000&version=2",
      "valid_until": "2018-09-18T10:32:59Z"
      "result": {
        "code":100,
        "message":"OK"
      }
    }
    

    HTTP Requests

    POST /app/mobilepay

    Initialize MobilePay payment flow when using MobilePay app. It is important to check that user has MobilePay app installed before using payment flow with app.

    Object request fields
    1. amountmandatoryAMOUNT

      Amount in the smallest currency unit. E.g. 99.99 € = 9999

    2. currencymandatoryCURRENCY

      ISO 4217 currency code

    3. orderORDER-ID

      Merchant defined order identifier

    4. return_urimandatoryURI

      Where MobilePay app returns. Parameter sessionToken is added to uri.

    5. webhook_success_urlmandatoryURL

      On success, server to server GET request will be made to this url.

    6. webhook_cancel_urlmandatoryURL

      On cancel, server to server GET request will be made to this url.

    7. webhook_failure_urlmandatoryURL

      On failure, server to server GET request will be made to this url.

    8. languageLANG

      Language code. Allowed values are "en", "fi", "da", "no"

    9. shop_nameANS

      Name of the shop/merchant. MobilePay app displays this under the shop logo. If omitted, the merchant name from PH is used.

    10. shop_logo_urlURL

      The logo must be 250x250 pixel in .png format and must be hosted on a HTTPS (secure) server.

    11. splittingobject

      Splits the payment into sub-merchant settlement and the main merchant commission. Requires separate activation. Note: The commission will not be refunded in case of a settled payment (committed transaction after 22:00 UTC). Instead the sub-merchant's account will be used for the money transfer.

      child fields

    About shop logo in MobilePay

    HTTP Response

    Object response fields
    1. session_tokenmandatoryANS

      MobilePay session token

    2. urimandatoryURI

      MobilePay app uri

    3. valid_untilTIMESTAMP

      Session expriration time.

    4. resultobject

      child fields

    MobilePay session status

    Get MobilePay session status

    String sessionToken = "0001-01-01-00.00.00.000000"; // in redirect from MobilePay app, or from init
    
    MobilePayStatusResponse status = paymentAPI.mobilePaySessionStatus(sessionToken);
    
    status.getStatus(); // "ok" when session is finished and transaction can be committed
    status.getTransactionId(); // available when status is "ok"
    status.getValidUntil();
    
    status.getResult().getCode(); // 100
    
    const sessionToken = "0001-01-01-00.00.00.000000"; // in redirect from MobilePay app, or from init
    
    paymentAPI.mobilePaySessionStatus(sessionToken)
      .then(function (response) {
        const status = response.status; // "ok" when session is finished and transaction can be committed
        const transaction_id = response.transaction_id; // available when status is "ok"
        const valid = response.valid_until;
    
        response.result.code; // 100
      });
    
    

    Json response

    {
      "status": "ok",
      "transaction_id": "327c6f29-9b46-40b9-b85b-85e908015d92",
      "result": {
        "code":100,
        "message":"OK"
      }
    }
    

    HTTP Request

    GET /app/mobilepay/<:mobilepay session token>

    HTTP Response

    Object response fields
    1. statusmandatoryTSTATE

      MobilePay session status

    2. valid_untilmandatoryTIMESTAMP

      Session expriration time.

    3. transaction_idUUID4

      Transaction id. Available if status is "ok"

    4. resultobject

      child fields

    Pivo app based payment flow

    Open Pivo app without external browsers, resulting in a smoother user experience.

    Please remember to first verify the user has Pivo app installed!

    Using Payment Highway and Pivo in Mobile application

    Initialize Pivo payment with app flow.

    // Initialize Pivo payment session
    
    long amount = 1990L;
    String currency = "EUR";
    String order = UUID.randomUUID().toString()
    
    PivoInitRequest request = PaymentRequestBuilder.pivoInitRequest(amount, currency)
       .setOrder(order)
       .setAppUrl("myapp://paid")
       .setWebhookSuccessUrl("https://backend.myapp.com/success")
       .setWebhookCancelUrl("https://backend.myapp.com/cancel")
       .setWebhookFailureUrl("https://backend.myapp.com/failure")
       .setDescription("3 oranges");
    
    PivoInitResponse response = paymentAPI.initPivoTransaction(request);
    response.getTransactionId();
    response.getUri(); // start Pivo app with this uri
    response.getResult().getCode(); // 100
    
    const amount = 1990;
    const currency = 'EUR';
    const orderId = 'orderid';
    
    const request = PivoInitRequest.Builder(amount, currency)
      .setOrder(orderId)
      .setDescription('3 oranges')
      .setAppUrl('myapp://paid')
      .setWebhookSuccessUrl('https://myserver.com/success')
      .setWebhookCancelUrl('https://myserver.com/cancel')
      .setWebhookFailureUrl('https://myserver.com/failure')
      .build()
    
    api.initPivoTransaction(request)
      .then(function (init) {
        const transaction_id = init.transaction_id;
        const uri = init.uri; // start Pivo app with this uri
        const resultCode = init.result.code; // 100
      });
    

    Json request

    {
      "amount": 1990,
      "currency": "EUR",
      "order": "order",
      "description": "3 oranges",
      "app_url": "myapp://paid",
      "webhook_success_url": "https://backend.myapp.com/success",
      "webhook_cencel_url": "https://backend.myapp.com/cancel",
      "webhook_failure_url": "https://backend.myapp.com/failure"
    }
    

    Json response

    {
      "transaction_id": "52ea5beb-343b-4516-ab70-ede2baa058c8",
      "uri": "pivo://api/v1/payment_button?payment_id=9942a5fa5e872a7cde823ec7b1443519506e99cd31e89ad7d63b4ea793c85843",
      "valid_until": "2018-09-18T10:32:59Z",
      "result": {
        "code":100,
        "message":"OK"
      }
    }
    

    HTTP Requests

    POST /app/pivo

    Initialize Pivo payment flow when using Pivo app. It is important to check that user has Pivo app installed before using payment flow with app.

    Object request fields
    1. amountmandatoryAMOUNT

      Amount in the smallest currency unit. E.g. 99.99 € = 9999

    2. currencymandatoryCURRENCY

      ISO 4217 currency code

    3. orderORDER-ID

      Merchant defined order identifier

    4. reference_numberAN

      Reference number. In RF-format or in Finnish reference number format.

    5. phone_numberPHONE

    6. descriptionANS

      The order description shown to the user

    7. app_urlmandatoryURL

      Where the user is returned to, after a finished Pivo payment.

    8. webhook_success_urlmandatoryURL

      On success, server to server GET request will be made to this url.

    9. webhook_cancel_urlmandatoryURL

      On cancel, server to server GET request will be made to this url.

    10. webhook_failure_urlmandatoryURL

      On failure, server to server GET request will be made to this url.

    11. languageLANG

      Language code.

    12. splittingobject

      Splits the payment into sub-merchant settlement and the main merchant commission. Requires separate activation. Note: The commission will not be refunded in case of a settled payment (committed transaction after 22:00 UTC). Instead the sub-merchant's account will be used for the money transfer.

      child fields

    HTTP Response

    Object response fields
    1. transaction_idmandatoryUUID4

      Transaction ID

    2. urimandatoryURI

      Pivo app uri

    3. valid_untilmandatoryTIMESTAMP

      Session expriration time.

    4. resultobject

      child fields

    Retrying Failed Payments

    If a payment transaction fails with RCODE 200 there are two possible retry scenarios:

    1. retrying is forbidden or
    2. retrying is allowed only a certain number of times.

    For a failed transaction you need to inspect the acquirer_response_code to know how to proceed.

    A transaction is considered a retry when after an initially failed transaction:

    The most common scenario is retrying a failed MIT transaction. Pay attention to the automatic retry logic for MITs. A retry can also easily occur with Customer Initiated Transactions using token, for example during a commute ticket purchase via an app. Even a one-time purchase in a web shop may lead to a retry if the cardholder inputs the same card details again after an initial failed payment.

    Case 1 - Retrying is forbidden

    When the acquirer_response_code is:

    Nets Bambora Concardis Amex
    111, 119, 165, 200, 207, 208, 209, 902, 908, 909 04, 07, 12, 14, 15, 41, 43, 46, 57, R0, R1, R3 04, 12, 14, 43, 57 181, 183, 187, 189, 200

    Never retry such a transaction. The cardholder needs to give a new card number to proceed.

    Case 2 - Retrying is allowed

    When the acquirer_response_code is any other than above for a specific acquirer, you may retry the transaction up to 15 times in the next 30 days.

    Order Status

    Get the transactions related to a specific order

    curl -i \
      -H "SPH-Account: test" \
      -H "SPH-Api-Version: 20191204" \
      -H "SPH-Merchant: test_merchantId" \
      -H "SPH-Request-Id: b33696d1-944c-4371-9216-4ba4a910f6c8" \
      -H "SPH-Timestamp: 2018-10-04T10:27:12Z" \
      -H "Signature: SPH1 testKey af890404b04d597f93d7c83198fe470bf007e499a64261401364eb56f5af266e" \
      --data '' \
      https://v1-hub-staging.sph-test-solinor.com/transactions/?order=API_TEST_VERSION_20191204
    
    OrderSearchResponse orderSearchResponse = paymentApi.searchOrders(order);
    
    paymentAPI.searchOrders("API_TEST_VERSION_20191204");
    
    <?php
    $response = paymentApi->searchByOrderId( $orderId );
    

    JSON response

    {
      "transactions": [
        {
          "id": "52ea5beb-343b-4516-ab70-ede2baa058c8",
          "acquirer": {
            "id": "nets",
            "name": "Nets"
          },
          "type": "debit",
          "amount": 2499,
          "current_amount": 1499,
          "currency": "EUR",
          "timestamp": "2018-10-04T10:19:46Z",
          "modified": "2018-10-04T10:31:32Z",
          "filing_code": "181004705200",
          "authorization_code": "436460",
          "token": "77ffbaca-9658-4aef-ac9e-f85da3164bdb",
          "status": {
            "state": "ok",
            "code": 4000
          },
          "card": {
            "type": "Visa",
            "partial_pan": "0024",
            "expire_year": "2023",
            "expire_month": "11",
            "cvc_required": "no",
            "bin": "415301",
            "funding": "debit",
            "country_code": "FI",
            "category": "unknown",
            "card_fingerprint": "da6b0df36efd17c0e7f6967b9e440a0c61b6bd3d96b62f14c90155a1fb883597",
            "pan_fingerprint": "e858e18daac509247f463292641237d6a74ce44e0971ba2de4a14874928a8805"
          },
          "reverts": [
            {
              "type": "cancellation",
              "status": {
                "state": "ok",
                "code": 4000
              },
              "amount": 1000,
              "timestamp": "2018-10-04T10:31:32Z",
              "modified": "2018-10-04T10:31:32Z",
              "filing_code": "181004705200"
            }
          ],
          "cardholder_authentication": "no",
          "order": "API_TEST_VERSION_20191204",
          "committed": true,
          "committed_amount": 2499,
          "recurring": true,
          "splitting": {
            "amount": 1499,
            "merchant_id": "123456"
          }
        }
      ],
      "siirto_transactions": [],
      "pivo_transactions": [
        {
          "id": "177ef24a-d3f2-4514-ad9b-492d3926bb18",
          "type": "debit",
          "amount": 100,
          "current_amount": 100,
          "currency": "EUR",
          "timestamp": "2018-06-15T10:34:31Z",
          "status": {
            "state": "ok",
            "code": 4000
          },
          "reference_number": "1806151034319",
          "customer": {
            "network_address": "93.174.192.154",
            "country_code": "FI"
          },
          "order": "API_TEST_VERSION_20191204",
          "pivo_payment_id": "37b54bcc9f78d04095214f1b8018263082bb3fcb1951520a9e1edeab94af9515",
          "payment_type": "card",
          "archive_id": "180615541764",
          "modified": "2018-06-15T10:54:56Z",
          "refunds": []
        }
      ],
      "result": {
        "code": 100,
        "message": "OK"
      }
    }
    

    Get the transaction IDs related to the order value given for the payment. This allows to get the payment transaction ID even in a case where the user's browser does not redirect back to a given URL in the calling service.

    HTTP Request

    GET /transactions/?order=<order>[&limit=<limit>][&start-date=<start-date>][&end-date=<end-date>][&start-datetime=<start-timestamp>][&end-datetime=<end-timestamp>]

    Parameter M/O Data type Description
    order M ORDER-ID Merchant defined order identifier
    limit O N (1 - 100) Limit the size of the result set. Defaults to 100.
    start-date O DATE Start date for the search. Inclusive.
    end-date O DATE End date for the search. Inclusive.
    start-datetime O TIMESTAMP Start date and time for the search. Inclusive.
    end-datetime O TIMESTAMP End date and time for the search. Inclusive.

    HTTP Response

    The response JSON contains an array of transaction statuses, where the format is the same as in the response of Transaction Status. The array is ordered by timestamp, newest first.

    Object response fields
    1. resultobject

      child fields
    2. transactionsmandatoryarray

      All transactions belonging to the order

      child fields
    3. siirto_transactionsarray

      Deprecated empty array

    4. pivo_transactionsmandatoryarray

      All Pivo transactions belonging to the order

      child fields

    Revert

    Revert a payment transaction

    curl -i \
      -H "Content-Length: 15" \
      -H "Content-Type: application/json" \
      -H "SPH-Account: test" \
      -H "SPH-Api-Version: 20191204" \
      -H "SPH-Merchant: test_merchantId" \
      -H "SPH-Request-Id: 7399702e-5ae4-4d9f-af57-e78d50937f97" \
      -H "SPH-Timestamp: 2018-10-04T10:31:31Z" \
      -H "Signature: SPH1 testKey d0e8d4cfecdf8db1180057d8a691e1d5af5b7e7d80b5acabfc920e6d0b46f388" \
      --data '{"amount":1000}' \
      https://v1-hub-staging.sph-test-solinor.com/transaction/52ea5beb-343b-4516-ab70-ede2baa058c8/revert
    
    String transactionId = "52ea5beb-343b-4516-ab70-ede2baa058c8";
    TransactionResponse response = paymentAPI.revertTransaction(transactionId);
    
    response.getResult().getCode(); // 100
    
    transaction_id = "52ea5beb-343b-4516-ab70-ede2baa058c8"
    transaction_response = payment_api.revert_transaction(transaction_id)
    transaction_response = payment_api.revert_transaction(transaction_id, 1000)
    
    transaction_response.result.code // 100
    
    var transactionId = "52ea5beb-343b-4516-ab70-ede2baa058c8";
    paymentAPI.revertTransaction(transactionId)
        .then(function(response){
            return response.result.code; // 100
        });
    
    <?php
    $transactionId = "52ea5beb-343b-4516-ab70-ede2baa058c8";
    $response = $paymentApi->revertTransaction($transactionId);
    
    $response->body->result->code; // 100
    

    JSON Response

    {
      "result": {
        "code": 100,
        "message":" OK"
      }
    }
    

    Reverts an existing debit transaction.

    For Pivo transactions, use Revert Pivo.

    HTTP Request

    POST /transaction/<:transaction_id>/revert

    Object request fields
    1. amountmandatoryAMOUNT

      Amount in the smallest currency unit. E.g. 99.99 € = 9999. Without amount the whole transaction is reverted.

    HTTP Response

    Object response fields
    1. resultobject

      child fields

    Revert Pivo

    Revert a Pivo transaction

    String transactionId = "f23a9be0-15fe-43df-98ac-92f6a5731c3b";
    String referenceNumber = "1313";
    
    TransactionResponse response = paymentAPI.revertPivoTransaction(transactionId, referenceNumber);
    
    response.getResult().getCode(); // 100
    
    const transactionId = "f23a9be0-15fe-43df-98ac-92f6a5731c3b";
    const referenceNumber = "1313";
    const pivoRevertRequest = new RevertPivoTransactionRequest(referenceNumber, pivoRevertRequest);
    
    paymentAPI.revertPivoTransaction(transactionId)
        .then(function(response){
            response.result.code; // 100
        });
    
    <?php
    $transactionId = "f23a9be0-15fe-43df-98ac-92f6a5731c3b";
    $referenceNumber = "1313";
    $amount = "10";
    
    $response = $paymentApi->revertPivoTransaction($transactionId, $referenceNumber, $amount);
    
    $response->body->result->code; // 100
    

    JSON Response

    {
      "result":
      {
        "code":100,
        "message":"OK"
      }
    }
    

    Reverts an existing Pivo transaction.

    For other transactions, use Revert.

    HTTP Request

    POST /transaction/<:transaction_id>/pivo/revert

    Object request fields
    1. reference_numberAN

      Reference number. In RF-format or in Finnish reference number format. It omitted, random reference number will be generated by PH

    2. amountmandatoryAMOUNT

      Amount in the smallest currency unit. E.g. 99.99 € = 9999. Without amount the whole transaction is reverted.

    HTTP Response

    Object response fields
    1. resultobject

      child fields

    Advice for Automated Fuel Dispensers

    Adjust amount of a payment transaction

    curl -i \
      -H "Content-Length: 15" \
      -H "Content-Type: application/json" \
      -H "SPH-Account: test" \
      -H "SPH-Api-Version: 20191204" \
      -H "SPH-Merchant: test_merchantId" \
      -H "SPH-Request-Id: 7399702e-5ae4-4d9f-af57-e78d50937f97" \
      -H "SPH-Timestamp: 2018-10-04T10:31:31Z" \
      -H "Signature: SPH1 testKey d0e8d4cfecdf8db1180057d8a691e1d5af5b7e7d80b5acabfc920e6d0b46f388" \
      --data '{"amount":1000}' \
      https://v1-hub-staging.sph-test-solinor.com/transaction/52ea5beb-343b-4516-ab70-ede2baa058c8/advice
    

    JSON Response

    {
      "result": {
        "code": 100,
        "message":" OK"
      }
    }
    

    Adjusts the amount of the initial authorization with the final amount of the transaction at the Automated Fuel Dispenser. If the user cancelled the fuelling, use Revert instead.

    The advice message should be retried at most once.

    HTTP Request

    POST /transaction/<:transaction_id>/advice

    Object advice fields
    1. amountmandatoryAMOUNT

      Amount in the smallest currency unit. E.g. 99.99 € = 9999.

    HTTP Response

    Object advice fields
    1. resultobject

      child fields

    Transaction Status

    Transaction status request

    curl -i \
      -H "SPH-Account: test" \
      -H "SPH-Api-Version: 20191204" \
      -H "SPH-Merchant: test_merchantId" \
      -H "SPH-Request-Id: 2c2ffba5-65c3-49aa-8e48-244504892710" \
      -H "SPH-Timestamp: 2018-10-04T10:23:55Z" \
      -H "Signature: SPH1 testKey 7dba83405e7a55973edc8802a60f4fb2315632982cccd48cddc064b4ed623da9" \
      --data '' \
      https://v1-hub-staging.sph-test-solinor.com/transaction/52ea5beb-343b-4516-ab70-ede2baa058c8
    
    String transactionId = "52ea5beb-343b-4516-ab70-ede2baa058c8";
    TransactionStatusResponse statusResponse = paymentAPI.transactionStatus(transactionId);
    
    statusResponse.getResult().getCode(); // 100
    
    transaction_id = "52ea5beb-343b-4516-ab70-ede2baa058c8"
    transaction_status_response = payment_api.transaction_status(transaction_id)
    
    transaction_status_response.result.code; // 100
    
    var transactionId = "52ea5beb-343b-4516-ab70-ede2baa058c8";
    paymentAPI.transactionStatus(transactionId)
        .then(function(response){
            return response.result.code; // 100
        });
    
    <?php
    $transactionId = "52ea5beb-343b-4516-ab70-ede2baa058c8";
    $status = paymentApi->statusTransaction($transactionId);
    
    $status->body->result->code; // 100
    

    JSON Response

    {
      "transaction": {
        "id": "52ea5beb-343b-4516-ab70-ede2baa058c8",
        "acquirer": {
          "id": "nets",
          "name": "Nets"
        },
        "type": "debit",
        "amount": 2499,
        "current_amount": 2499,
        "currency": "EUR",
        "timestamp": "2018-10-04T10:19:46Z",
        "modified": "2018-10-04T10:19:46Z",
        "filing_code": "181004705200",
        "authorization_code": "436460",
        "token": "77ffbaca-9658-4aef-ac9e-f85da3164bdb",
        "status": {
          "state": "ok",
          "code": 4000
        },
        "card": {
          "type": "Visa",
          "partial_pan": "0024",
          "expire_year": "2023",
          "expire_month": "11",
          "cvc_required": "no",
          "bin": "415301",
          "funding": "debit",
          "country_code": "FI",
          "category": "unknown",
          "card_fingerprint": "da6b0df36efd17c0e7f6967b9e440a0c61b6bd3d96b62f14c90155a1fb883597",
          "pan_fingerprint": "e858e18daac509247f463292641237d6a74ce44e0971ba2de4a14874928a8805"
        },
        "reverts": [],
        "cardholder_authentication": "no",
        "order": "API_TEST_VERSION_20191204",
        "committed": true,
        "committed_amount": 2499,
        "recurring": true,
        "splitting": {
          "amount": 1499,
          "merchant_id": "123456"
        }
      },
      "result": {
        "code": 100,
        "message": "OK"
      }
    }
    

    HTTP Request

    For Pivo payments, check Pivo transaction status

    GET /transaction/<:transaction_id>

    HTTP Response

    Object response fields
    1. resultobject

      child fields
    2. transactionmandatoryobject

      child fields

    Pivo Transaction Status

    Pivo Transaction status request

    String transactionId = "f23a9be0-15fe-43df-98ac-92f6a5731c3b";
    TransactionStatusResponse statusResponse = paymentAPI.pivoTransactionStatus(transactionId);
    
    statusResponse.getResult().getCode(); // 100
    
    var transactionId = "f23a9be0-15fe-43df-98ac-92f6a5731c3b";
    paymentAPI.pivoTransactionStatus(transactionId)
        .then(function(response){
            response.result.code; // 100
        });
    
    <?php
    $transactionId = "f23a9be0-15fe-43df-98ac-92f6a5731c3b";
    $status = paymentApi->statusPivoTransaction($transactionId);
    
    $status->body->result->code; // 100
    

    JSON Response for Pivo transaction

    {
      "transaction":
      {
        "id": "e1fd556f-8264-40f2-9bcf-93b5eea979db",
        "type": "debit",
        "amount": 100,
        "current_amount": 99,
        "currency": "EUR",
        "timestamp": "2018-05-04T12:59:35Z",
        "status":
        {
          "state":"reverted",
          "code":5700
        },
        "reference_number": "",
        "customer":
        {
          "network_address": "93.174.192.154",
          "country_code": "FI"
        },
        "order": "pivotus",
        "pivo_payment_id": "35b15797dac97f5233cd54e52611393a82f680bcb235a1b73ff2d8ca23937dfb",
        "phone": "+358444160589",
        "payment_type": "account",
        "archive_id": "20180504593497ZS0013",
        "modified": "2018-05-04T16:04:40Z",
        "refunds":
          [
            {
              "refund_request_id": "5fd7e9d2-7d78-488f-96c8-7ecee999b2f0",
              "amount": 1,
              "timestamp": "2018-05-04T16:04:39Z",
              "reference_number": "",
              "payment_type": "account",
              "archive_id": "20180504593497ZQ0018"
            }
          ]
      },
      "result":
      {
        "code": 100,
        "message": "OK"
       }
    }
    

    HTTP Request

    GET /transaction/pivo/<:transaction_id>

    HTTP Response

    Pivo transaction response object fields
    1. resultobject

      child fields
    2. transactionmandatoryobject

      child fields

    Tokenization

    In order to be sure that a tokenized card is valid and is able to process payment transactions the corresponding sph-tokenization-id must be used to get the actual card token.

    The card token is fetched by calling the tokenization URI with the sph-tokenization-id.

    Technically the tokenization is already done by a Form API call such as /form/view/add_card as processing an authorization requires a valid CVC given by the cardholder. If the card is valid the Tokenization response contains a card token that can be used to make transactions such as charging the card or refunding the card.

    Tokenization request

    curl -i \
      -H "SPH-Account: test" \
      -H "SPH-Api-Version: 20191204" \
      -H "SPH-Merchant: test_merchantId" \
      -H "SPH-Request-Id: d1f3e1ec-4fc3-4bda-815a-955ff53d0a5d" \
      -H "SPH-Timestamp: 2018-10-04T10:15:46Z" \
      -H "Signature: SPH1 testKey c1777efd75b06c0901c7bcbaa67ea503e66cb7b2a4f8f82516f891e89b2ee353" \
      --data '' \
      https://v1-hub-staging.sph-test-solinor.com/tokenization/1207e5d7-8d15-44d8-b1d0-00f0c434d131
    
    TokenizationResponse tokenResponse = paymentAPI.tokenize("tokenizationId");
    
    tokenResponse.getResult().getCode(); // 100
    
    token_response = payment_api.tokenize("tokenization_id")
    
    token_response.result.code // 100
    
    paymentAPI.tokenization("tokenizationId")
        .then(function(response){
            response.result.code; // 100
        })
    
    <?php
    $response = $paymentApi->tokenize( $tokenizationId );
    
    $response->body->result->code; // 100
    

    JSON Response

    {
      "card_token": "77ffbaca-9658-4aef-ac9e-f85da3164bdb",
      "recurring": false,
      "customer": {
        "network_address": "93.174.192.154",
        "country_code": "FI"
      },
      "cardholder_authentication": "attempted",
      "card": {
        "type": "Visa",
        "partial_pan": "0024",
        "expire_year": "2023",
        "expire_month": "11",
        "cvc_required": "no",
        "bin": "415301",
        "funding": "debit",
        "country_code": "FI",
        "category": "unknown",
        "card_fingerprint": "da6b0df36efd17c0e7f6967b9e440a0c61b6bd3d96b62f14c90155a1fb883597",
        "pan_fingerprint": "e858e18daac509247f463292641237d6a74ce44e0971ba2de4a14874928a8805"
      },
      "result": {
        "code": 100,
        "message": "OK"
      }
    }
    

    HTTP Request

    GET /tokenization/<sph-tokenization-id>

    HTTP Response

    Object response fields
    1. card_tokenUUID4

      Present if verification was successful

    2. cardobject

      Present if verification was successful

      child fields
    3. customerobject

      child fields
    4. cardholder_authenticationmandatoryA

      Indicates whether ThreeDS (3ds) card holder authentication was done (authenticated, attempted or no)

    5. resultobject

      child fields
    6. acquirerobject

      child fields
    7. acquirer_response_codeAN

      Acquirer specific response code

    8. authorizerAN

      The card issuer or scheme network which gave the authorization response (acquirer_response_code)

    Daily Batch Report

    Fetch a daily report of the settlements and their transactions for all of the merchants under the account.

    Batch Report request

    curl -i \
    -H "Content-Type: application/json; charset=utf-8" \
    -H "SPH-Account: test" \
    -H "SPH-Merchant: test_merchantId" \
    -H "SPH-Timestamp: 2014-09-18T10:32:59Z" \
    -H "SPH-Request-Id: f47ac10b-58cc-4372-a567-0e02b2c3d479" \
    -H "Signature: SPH1 testKey 4eab87a16e3ee7bd530d778af0cb6c680dcaa52ed1913a9c1bd8ed5a8d689e3e" \
    https://v1-hub-staging.sph-test-solinor.com/report/batch/20150323
    
    ReportResponse report = paymentAPI.fetchDailyReport("20150323");
    
    report.getResult().getCode() // 100
    
    report = payment_api.fetch_daily_report("20150323")
    
    report.result.code // 100
    
    paymentAPI.fetchDailyReport("yyyyMMdd")
        .then(function(response) {
          response.result.code; // 100
        });
    
    <?php
    $response = paymentApi->getReport("yyyyMMdd");
    
    $response->body->result->code; // 100
    

    JSON Response

    {
      "settlements": [
        {
          "id":"4b961b80-e808-487b-bc89-7cf83ffda4d7",
          "batch":"000017",
          "timestamp":"2015-03-23T22:00:09Z",
          "merchant":
          {
            "id":"test_merchantId",
            "name":"Test user"
          },
          "transaction_count":1,
          "net_amount":620,
          "currency":"EUR",
          "acquirer":
          {
            "id":"nets",
            "name":"Nets"
          },
          "transactions":[
          {
            "id":"bc42307b-1313-4d7d-9a0a-7cdd9d3d190c",
            "timestamp":"2015-03-23T10:59:54Z",
            "type":"debit",
            "partial_pan":"0024",
            "amount":620,
            "currency":"EUR",
            "filing_code":"150323000265",
            "status":
            {
              "state":"ok",
              "code":4000
            },
            "authorization_code":"317020"
          }],
          "status":
          {
            "state":"ok",
            "code":4000
          },
          "reference":"11503231000000174"
        }
      ],
      "result":
      {
        "code":100,
        "message":"OK"
      }
    }
    

    HTTP Request

    GET /report/batch/<yyyyMMdd>

    HTTP Response

    1. resultmandatoryobject

      child fields
    2. settlementsmandatoryarray

      May be empty

      child fields

    Form Session Status

    Form session status

    
    
    
    
    
    

    JSON Response

    {
      "status": {
        "code": 2000,
        "message": "started"
      }
      "transaction_id": null,
      "operation": "pay-and-tokenize"
      "created": "2022-07-14T15:00:00Z",
      "valid_until": "2022-07-14T17:59:59Z",
      "result": {
        "code":100,
        "message":"OK"
      }
    }
    
    

    Get form session current status.

    HTTP Request

    GET /form/<:session_id>/status

    HTTP Response

    Object response fields
    1. statusmandatoryobject

      Form session status.

      child fields
    2. transaction_idUUID4

      Transaction id.

    3. operationmandatoryAN

      Operation (tokenize, pay-and-tokenize, pay-single, pay-mobilepay, pay-pivo, pay-with-token-and-cvc, pay-three-d-secure-step-up).

    4. createdmandatoryTIMESTAMP

      Session creation time.

    5. valid_untilmandatoryTIMESTAMP

      Session expriration time.

    6. resultobject

      child fields

    Response and Status Codes

    RCODE Result Codes

    Please note that these codes are different from HTTP response codes

    RCODE RMSG Description, actions
    100 Description of the succesful request Request successful.
    101 Description of partial approval success Request for partial approval is successful.
    200 Reason for the failure Authorization failed, unable to create a Debit transaction or Revert failed.
    For Debit transactions, please initialize a new transaction the next day (in case there was insufficient funds) and/or contact the cardholder.
    For transaction reverts, please see the status of the transaction with GET /transaction/<id>
    209 Description of the timeout Charge/Revert failed due to acquirer or issuer timeout.
    210 Transaction already fully reverted: A full amount revert was performed on an already fully reverted transaction.
    211 Insufficient balance for the revert: A partial revert with an amount greater than the amount left was performed on the transaction.
    231 "API key is not allowed to access transaction for given account" When using API key with limited access. API key is not allowed to access transaction for given account.
    232 "API key is not allowed to access given merchant" When using API key with limited access. API key is not allowed to access given merchant.
    233 "API key is not allowed to access given card token" When using API key with limited access. API key is not allowed to access given card token.
    250 "Suspected fraud" The transaction was rejected due to suspected fraud.
    300   Transaction in progress. Given when there is already a debit transaction being processed with the ID.
    400 Soft Decline: Issuer requests step-up Customer Initiated Transaction is soft declined and the issuer requests a step-up 3D Secure transaction.
    900 Description of the error Could not process the transaction, please try again.
    901 Description of the validation error Invalid input. Detailed information is in the message field.
    902 Description and ID of the transcation Transaction not found. Error is raised if the transaction iD is not found or when the transaction ID is trying to be used for a wrong type of operation.
    910 Description of the operation type error Invalid operation type. Either a credit transaction is performed on a debit ID or vice versa.
    920 Description of the erroneous request parameters. Unmatched request parameters. Request parameters do not match the previous parameters with the current transaction ID.
    930 Description of invalid transaction state. Transaction was in invalid state for operation.
    931 Token temporarily unusable. The payment with token failed due to network token error.
    932 Token unusable. The token provided can no longer be used as the associated network token is invalid and the associated card changed.
    940 Route not found error The transaction did not match any of the merchant's acquirer routing rules and thus is not allowed.
    950 "The desired token already exists" The card is already tokenized with the existing token.
    952 "Encryption key not found"
    953 "Decryption failed"
    954 "Invalid cleartext PAN after decryption"
    990 Description of the error Permanent failure. Cannot repeat the transaction. Please initialize a new transaction.
    999 Deprecated API has been removed

    TCODE Transaction Status Codes

    TCODE TSTATE Description
    3000 "in_progress" The transaction is being authorized.
    4000 "ok" The transaction has been succesfully processed.
    4100 "ok_pending" Pending commit for the transaction.
    4200 "ok_estimated_pending" Pending commit for an estimated debit amount.
    5700 "reverted" The transaction has been successfully reverted.
    5800 "reverting" The revert is being authorized.
    6000 "declined" Payment has been declined e.g. by bank.
    6100 "cancelled" Transaction is cancelled by end user.
    7000 "failed" The transaction was failed.
    7100 "timeout" The transaction was failed due to timeout from the acquirer or issuer.
    7200 "suspected_fraud" The transaction was failed due to suspected fraud.
    7020 "soft_declined" Issuer requests 3DS step-up

    SCODE Settlement Status Codes

    SCODE SSTATE Description
    3000 "pending" Settlement has not yet been transmitted to the acquiring bank.
    4000 "ok" Settlement is processed OK.

    FSCODE Form Session Status Codes

    FCODE FSTATE Description
    3000 "in_progress" The form has been initialized but not submitted.
    4000 "ok" The form has been successfully processed.
    4100 "ok_pending" The form has been initialized but waiting for user.
    4300 "failed_recoverable" Processing of the form input has failed, but can be re-processed.
    6100 "cancelled" The form has been cancelled by the user.
    7000 "failed" Processing the form session has permanently failed.
    7030 "failed_no_route" No acquiring route was found for the submitted payment details.

    HTTP Status Code Summary

    CODE Description
    200 - OK Request successful
    401 - Unauthorized Authentication HMAC mismatch
    404 - Not Found The requested item doesn't exist
    5xx - Server Errors Something went wrong in Payment Highway

    Data Types

    Type Format Example
    A ^[a-zA-Z]+$ Hello
    N ^[0-9]+$ 1200
    ACCOUNT ^[-\w.]{1,500}$
    AMOUNT ^\d{1,12}$ 9900 (meaning 99.00 for duodecimal currencies)
    AN ^[0-9a-zA-Z]+$ sampleText001
    ANS ^[ -~]+$ ~/sample/text! <with@specials>
    BOOLEAN ^(true|false)$ true
    CURRENCY ^(EUR)$ EUR
    DATE ^\d{4}-\d{2}-\d{2}$ 2014-09-18 (year-month-day)
    IP Valid IPv4 address 127.0.0.1
    LANG ^[-\w.]{a-z}$ fi
    MERCHANT ^[-\w.]{1,500}$
    MONTH ^[0-9]{2}$ 02
    NETAMOUNT ^-?\d{1,12}$ -1590 (meaning -15.90 for duodecimal currencies)
    ORDER-ID ^[-a-zA-Z0-9_]{1,254}$ 1000123A
    PAN ^[3-6]\d{12,18}$
    RCODE ^\d{1,6}$  100
    REFERENCE  ^\d{12,20}$
    REVTYPE ^(cancellation|refund)$ cancellation
    RMSG ^[.,'-=/\w;\s]{0,1023}$
    SCODE ^\d{3,4}$ 3000
    SMSG ^[.,'-=/\w;\s]{0,1023}$
    SSTATE ^[.,'-=/\w;\s]{0,254}$
    TCODE ^\d{4}$ 4000
    TMSG ^[.,'-=/\w;\s]{0,1023}$
    TSTATE ^[.,'-=/\w;\s]{0,254}$ ok
    UUID4 ^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$ f47ac10b-58cc-4372-a567-0e02b2c3d479
    URL Valid URL with HTTPS scheme https://example.com/success?myparam=abc
    TIMESTAMP ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$ 2014-09-18T10:32:59Z
    VERSION ^\d{8}$ 20150515
    YEAR ^[0-9]{4}$ 2015
    PHONE ^+[\d]{1,14}$ +358441234567
    HEX ^[A-Fa-f0-9]+$
    FSTATE ^[.,'-=/\w;\s]{0,254}$
    FCODE ^\d{4}$ 2000

    Change log

    2022-11-30

    2022-10-20

    2022-08-19

    2022-08-15

    2022-08-11

    2022-07-15

    2021-04-12

    2020-04-27

    2020-04-20

    2020-02-24

    2019-12-11

    2019-09-26

    2019-09-13

    2019-06-14

    2018-09-27

    2018-07-25

    2018-06-08

    2018-04-26

    2018-02-26

    2017-11-27

    2017-06-27

    Masterpass with user profile

    2017-05-29

    2017-05-23

    2016-12-07

    2016-11-21

    2016-10-17

    2016-09-23

    2016-06-30

    2016-02-12

    2015-11-19

    2015-10-28

    2015-10-01

    New Result Codes

    2015-09-03

    Fraud detection

    Changes in the Payment API:

    2015-08-05

    Get transaction IDs by the "order" value

    Introduced the possibility to get the transactions related to a specific order. In cases where the user's browser does not redirect back to a given URL it is still possible to get the related transaction ID using the order value given for the payment.

    Changes in the Payment API:

    2015-06-05

    New API version: 20150605

    The CVC Form

    Introduced the new CVC Form to support a wider range of cards and business cases. Added version numbering to the Payment API to allow for incremental changes.

    Changes in the Form API:

    Changes in the Payment API: