sveaekonomi/checkout

Php integration library for Svea Checkout

1.5.0 2023-10-25 09:42 UTC

README

Index

Introduction

The checkout offers a complete solution with a variety of payment methods. The payment methods that are currently available in the checkout are invoice, payment plan, account credit, card payments and payment by bank.

The checkout supports both B2C and B2B payments, fast customer identification and caches customers behaviour.

This library provides entrypoints to integrate the checkout into your platform and to administrate checkout orders.

Test credentials

You can find credentials that can be used in the stage environment without signing an contract with Svea Bank here

The example files also contain merchant credentials which can be used in the stage environment.

1. Setup

1.1 Installing with Composer

Execute the following line in your command line interface:

composer require sveaekonomi/checkout

or add the following to your composer.json:

{
    "require": {
        "sveaekonomi/checkout": "dev-master"
    }
}

and run command composer update in your CLI

1.2 Install without composer

You can also download the library and upload it onto your server.

2. General information

2.1 Creating a Connector

You have to use a connector object as parameter when creating a CheckoutClient or a CheckoutAdminClient-object which is used to create API requests.

The connector defines what credentials should be used and which environment should be used.

Parameters for creating Connector are: checkoutMerchantId, checkoutSecret and base API url(environment).

// include the library
include 'vendor/autoload.php';

// include library without composer, include.php is in the library root
require_once 'include.php';

$checkoutMerchantId = '100001';
$checkoutSecret = 'checkoutSecret';
//set endpoint url. Eg. test or prod
$baseUrl = \Svea\Checkout\Transport\Connector::TEST_BASE_URL;

$connector = \Svea\Checkout\Transport\Connector::init($checkoutMerchantId, $checkoutSecret, $baseUrl);

2.2 CheckoutClient

The CheckoutClient class contains four methods which can be used to:

To ensure that a snippet always is displayed to the end-user, we recommend using the following flow in your platform:

Recommended flow of checkout

2.3 CheckoutAdminClient

The CheckoutAdminClient class contains methods which are used to administrate orders which have been creating using the CheckoutClient class.

Orders can only be administrated if CheckoutOrderStatus is "FINAL", any other status indicates that the order has not been finalized by the end-customer.

In order to perform an action on an order, the order needs to have an action. You'll have to get the order using "Get Order" and check which actions are available and then use a corresponding method.

For example, if you want to credit an order you first have to use Get order. Let's say that the action returned is "CanCreditAmount", then you'll have to use Credit amount to credit the order.

Some actions may not be available on certain order types, but a good integration doesn't check order type but rather which actions are available for use.

The available methods are:

3. Create order

To create a new order, you'll need to instantiate an object of \Svea\Checkout\CheckoutClient and pass a Connector as an parameter.

You can then use the method "create" in the object, pass the data below into the method. See example below.

The response will contain all order data along with a snippet which contains the iframe which needs to be rendered to the end-user.

Create order example:

// include the library
include 'vendor/autoload.php';

// without composer
require_once 'include.php';

$data = array(
        "countryCode" => "SE",
        "currency" => "SEK",
        "locale" => "sv-SE",
        "clientOrderNumber" => rand(10000,30000000),
        "merchantData" => "Test string from merchant",
        "cart" => array(
            "items" => array(
                array(
                    "articleNumber" => "1234567",
                    "name" => "Yellow rubber duck",
                    "quantity" => 200,
                    "unitPrice" => 12300,
                    "discountPercent" => 1000,
                    "vatPercent" => 2500,
                    "unit" => "st",
                    "temporaryReference" => "1",
                    "merchantData" => "Size: S"
                ),
                array(
                    "articleNumber" => "987654321",
                    "name" => "Blue rubber duck",
                    "quantity" => 500,
                    "unitPrice" => 25000,
                    "discountPercent" => 1000,
                    "vatPercent" => 2500,
                    "unit" => "pcs",
                    "temporaryReference" => "2",
                    "merchantData" => null
                )
            )
        ),
        "presetValues" => array(
            array(
                "typeName" => "emailAddress",
                "value" => "test@yourdomain.se",
                "isReadonly" => false
            ),
            array(
                "typeName" => "postalCode",
                "value" => "99999",
                "isReadonly" => false
            )
        ),
        "merchantSettings" => array(
            "termsUri" => "http://yourshop.se/terms/",
            "checkoutUri" => "http://yourshop.se/checkout/",
            "confirmationUri" => "http://yourshop.se/checkout/confirm/",
            "pushUri" => "https://yourshop.se/push.php?checkout_order_id={checkout.order.uri}",
        )
    );

$checkoutClient = new \Svea\Checkout\CheckoutClient($connector);

$response = $checkoutClient->create($data);

See full example

4. Get Order

To fetch an existing order, you'll need to instantiate an object of \Svea\Checkout\CheckoutClient and pass a Connector as an parameter.

You can then use the method "get" in the object, pass the data below into the method. See example below.

The response contains the order information and the along with the GUI which can be used to render the iframe once again.

// include the library
include 'vendor/autoload.php';

// without composer
require_once 'include.php';

$data = array(
        'orderId' => 51721
    );

$checkoutClient = new \Svea\Checkout\CheckoutClient($connector);

$response = $checkoutClient->get($data);

See full example

5. Update Order

To update an existing order, you'll need to instantiate an object of \Svea\Checkout\CheckoutClient and pass a Connector as an parameter.

The method returns the order information and the updated Gui needed to display the iframe for Svea Checkout. The previously displayed iframe should be replaced by the iframe in the response received when updating the order unless using the Javascript API.

Updating an order is only possible while the CheckoutOrderStatus is "Created", see CheckoutOrderStatus.

This method can be combined with the Javascript API, if the iframe is disabled using the JS API and the order is updated while the it's disabled the iframe will be updated once it's enabled again. This removes the requirement of replacing the iframe once the order is updated.

// include the library
include 'vendor/autoload.php';

// without composer
require_once 'include.php';

...

$checkoutClient = new \Svea\Checkout\CheckoutClient($connector);

$data = array(
        "orderId" => 251147,
        "merchantData" => "test",
        "cart" => array(
            "items" => array(
                array(
                    "articleNumber" => "123456",
                    "name" => "Yellow rubber duck",
                    "quantity" => 200,
                    "unitPrice" => 66600,
                    "discountPercent" => 1000,
                    "vatPercent" => 2500,
                    "temporaryReference" => "230",
                    "merchantData" => "Size: M"
                ),
                array(
                    "articleNumber" => "658475",
                    "name" => "Shipping Fee Updated",
                    "quantity" => 100,
                    "unitPrice" => 4900,
                    "vatPercent" => 2500,
                    "temporaryReference" => "231",
                    "merchantData" => null
                )
            )
        )
    );

$response = $checkoutClient->update($data);

See full example

6. Create recurring order

In order to create a recurring order the feature must be enable on your merchant. Contact Svea if you'd like to enable this feature.

To create a recurring order, you'll need to instantiate an object of \Svea\Checkout\CheckoutClient and pass a Connector as an parameter. In the data you'll have to specify the recurringToken which is returned when the order is finalized.

This uses the checkoutApi and will create a new order that you later can see in PaymentAdmin.

Example:

// include the library
include 'vendor/autoload.php';

// without composer
require_once 'include.php';

...

$checkoutClient = new \Svea\Checkout\CheckoutClient($connector);

$data = array(
    "token" => "12345678-90ab-cdef-1234-567890abcdef",
    "currency" => "SEK",
    "clientOrderNumber" => 12356,
    "merchantSettings" => array(
        "checkoutUri" => "http://yourshop.se/checkout/",
        "pushUri" => "https://yourshop.se/push.php?checkout_order_id={checkout.order.uri}",
    ),
    "cart" => array(
        "items" => array(
            array(
                "articleNumber" => "123456",
                "name" => "Yellow rubber duck",
                "quantity" => 200,
                "unitPrice" => 66600,
                "discountPercent" => 1000,
                "vatPercent" => 2500,
                "temporaryReference" => "230",
                "merchantData" => "Size: M"
            ),
        )
    )
);

$response = $checkoutClient->create($data);

7. Get recurring order

In order to get a recurring order you need to pass the token used to create the order as well as the orderId. Please note that this is only for orders previously created with the create recurring order method. The original order can be fetched using the get order method.

Example:

// include the library
include 'vendor/autoload.php';

// without composer
require_once 'include.php';

$data = array(
    'orderId' => 123456
    'token' => '12345678-90ab-cdef-1234-567890abcdef'
);

$checkoutClient = new \Svea\Checkout\CheckoutClient($connector);

$response = $checkoutClient->get($data);

8. Response

The response contains information about the order such as Cart, Status, PaymentType and much more.

Sample response

Array
(
    [MerchantSettings] => Array
        (
            [CheckoutValidationCallBackUri] => 
            [PushUri] => https://yourdomain.se/push.php?svea_order_id={checkout.order.uri}
            [TermsUri] => http://yourdomain.se/terms
            [CheckoutUri] => http://yourdomain.se/checkout/
            [ConfirmationUri] => http://yourdomain.se/checkout/confirm
            [ActivePartPaymentCampaigns] => Array
                (
                )

            [PromotedPartPaymentCampaign] => 0
        )

    [Cart] => Array
        (
            [Items] => Array
                (
                    [0] => Array
                        (
                            [ArticleNumber] => 1234567
                            [Name] => Yellow rubber duck
                            [Quantity] => 200
                            [UnitPrice] => 66600
                            [DiscountPercent] => 1000
                            [VatPercent] => 2500
                            [Unit] => 
                            [TemporaryReference] => 
                            [RowNumber] => 1
                            [MerchantData] => Size: M
                        )

                    [1] => Array
                        (
                            [ArticleNumber] => 987654321
                            [Name] => Blue rubber duck
                            [Quantity] => 500
                            [UnitPrice] => 25000
                            [DiscountPercent] => 1000
                            [VatPercent] => 2500
                            [Unit] => pcs
                            [TemporaryReference] => 
                            [RowNumber] => 2
                            [MerchantData] => 
                        )
                        
                    [2] => Array
                        (
                            [ArticleNumber] => 6eaceaec-fffc-41ad-8095-c21de609bcfd
                            [Name] => InvoiceFee
                            [Quantity] => 100
                            [UnitPrice] => 2900
                            [DiscountPercent] => 0
                            [VatPercent] => 2500
                            [Unit] => st
                            [TemporaryReference] => 
                            [RowNumber] => 3
                            [MerchantData] => 
                        )
                )
        )
        
    [Customer] => Array
        (
            [Id] => 626
            [NationalId] => 194605092222
            [CountryCode] => SE
            [IsCompany] => 
        )

    [ShippingAddress] => Array
        (
            [FullName] => Persson, Tess T
            [FirstName] => Tess T
            [LastName] => Persson
            [StreetAddress] => Testgatan 1
            [CoAddress] => c/o Eriksson, Erik
            [PostalCode] => 99999
            [City] => Stan
            [CountryCode] => SE
            [IsGeneric] => 
            [AddressLines] => Array
                (
                )

        )

    [BillingAddress] => Array
        (
            [FullName] => Persson, Tess T
            [FirstName] => Tess T
            [LastName] => Persson
            [StreetAddress] => Testgatan 1
            [CoAddress] => c/o Eriksson, Erik
            [PostalCode] => 99999
            [City] => Stan
            [CountryCode] => SE
            [IsGeneric] => 
            [AddressLines] => Array
                (
                )

        )


    [Gui] => Array
            (
                [Layout] => desktop
                [Snippet] => <iframe src=\"\"></iframe>
            )
    [Locale] => sv-SE
    [Currency] => SEK
    [CountryCode] => SE
    [PresetValues] => 
    [ClientOrderNumber] => 8828014
    [OrderId] => 251147
    [EmailAddress] => test@yourdomain.se
    [PhoneNumber] => 12312313
    [PaymentType] => INVOICE
    [Status] => Final
    [CustomerReference] => 
    [SveaWillBuyOrder] => 1
    [IdentityFlags] => 
    [MerchantData] => test
    [Recurring] => 1
    [RecurringToken] => 12345678-90ab-cdef-1234-567890abcdef (Only available when the order is FINAL)
)

The checkout GUI contains the Snippet and the Layout. The Snippet contains the Html and JavaScript that you implement on your page where you want to display the iframe for Svea checkout. The Layout is a String defining the orientation of the customers screen.

echo $response['Gui']['Snippet']

9. Additional requests

9.1 GetAvailablePartPaymentCampaigns

GetAvailablePartPaymentCampaigns can be used to fetch the details of all the campaigns that are available on the merchant

The information can be used to for example display information about how much it will cost to pay for a certain product or products on the actual product page.

See example

Example Request:

$checkoutMerchantId = 100002;
$checkoutSecret = "3862e010913d7c44f104ddb4b2881f810b50d5385244571c3327802e241140cc692522c04aa21c942793c8a69a8e55ca7b6131d9ac2a2ae2f4f7c52634fe30d2";
$baseUrl = \Svea\Checkout\Transport\Connector::TEST_BASE_URL;

$conn = \Svea\Checkout\Transport\Connector::init($checkoutMerchantId, $checkoutSecret, $baseUrl);
$checkoutClient = new \Svea\Checkout\CheckoutClient($conn);

$data = array(
    'IsCompany' => false
);
$response = $checkoutClient->getAvailablePartPaymentCampaigns($data);
echo "<pre>" . print_r($response, true) . "</pre>";

Executing the code above will return an array with 8.11 CampaignCodeInfo

Example response:

Array
(
    [0] => Array
        (
            [CampaignCode] => 213060
            [ContractLengthInMonths] => 3
            [Description] => Köp nu betala om 3 månader (räntefritt)
            [FromAmount] => 1000
            [InitialFee] => 100
            [InterestRatePercent] => 0
            [MonthlyAnnuityFactor] => 1
            [NotificationFee] => 29
            [NumberOfInterestFreeMonths] => 3
            [NumberOfPaymentFreeMonths] => 3
            [PaymentPlanType] => 2
            [ToAmount] => 50000
        )

    [1] => Array
        (
                    [CampaignCode] => 410012
                    [ContractLengthInMonths] => 12
                    [Description] => Dela upp betalningen på 12 månader
                    [FromAmount] => 100
                    [InitialFee] => 0
                    [InterestRatePercent] => 19.9
                    [MonthlyAnnuityFactor] => 0.092586652785396
                    [NotificationFee] => 29
                    [NumberOfInterestFreeMonths] => 0
                    [NumberOfPaymentFreeMonths] => 0
                    [PaymentPlanType] => 0
                    [ToAmount] => 30000
        )
)

The information should be stored in a database for fast access instead of sending requests on demand.

Calculation formulas

Calculating price per month:

(InitialFee + (ceil(ProductPrice * MonthlyAnnuityFactor) + NotificationFee) * ContractLengthInMonths) / ContractLengthInMonths

Using the second campaign with a product price of 1500kr in the example above will result in: (0 + (ceil(1500 * 0.092586652785396) + 29 ) * 12) / 12 = (0 + (139 + 29) * 12 ) / 12 = 168kr

Calculating total amount to pay:

InitialFee + (ProductPrice * MonthlyAnnuityFactor + NotificationFee) * ContractLengthInMonths

Using the second campaign with a product price of 150kr in the example above will result in: 0 + (150 * 0.092586652785396 + 29 ) * 12 = 514.655975 round upwards to closest whole number -> 515kr

!!! NOTE !!!

If you are a finnish merchant you have to display ALL the values described here to be compliant with finnish laws.

10. Data structures

10.1 MerchantSettings

10.2 Items

10.3 OrderRow

10.4 PresetValue

List of presetvalue typenames

10.5 Gui

10.6 Customer

10.7 Address

10.8 CheckoutOrderStatus

The order can only be considered “ready to send to customer” when the CheckoutOrderStatus is Final. No other status can guarantee payment.

10.9 Locale

10.10 PaymentType

Directbanks:

10.11 CampaignCodeInfo

10.12 IdentityFlags

10.13 CheckoutValidationCallbackResponse

If a CheckoutValidationCallbackUri is set on an order when it's created, Svea will send a HTTP GET request to the specified URI when a customer clicks on "Confirm Order".

The response should have HTTP status 200, indicating a successful request. The response should contain the required parameters below. Encode the response in JSON before responding.

11. HttpStatusCodes

If the returned ResultCode is not present in the above tables please contact Svea Ekonomi for further information.

12. Order administration

See full examples

Errors

If any action is unsuccessful or there is any other error, library will throw exception

Possible Exceptions \Svea\Checkout\Exception\SveaInputValidationException - If any of the input fields is invalid or missing.

\Svea\Checkout\Exception\SveaApiException - If there is some problem with API connection or some error occurred with data validation on the API side.

\Svea\Checkout\Exception\SveaConnectorException - will be returned if some of fields merchantId, sharedSecret or baseUrl is missing.

\Exception - For any other error

12.1 Get order

This method is used to get the entire order with all its relevant information. Including its deliveries, rows, credits and addresses.

Parameters

Response

12.2 Get task

A task will explain the status of a previously performed operation. When finished it will point towards the new resource with the Location.

Parameters

Response

12.3 Deliver order

Creates a delivery on a checkout order. Assuming the order got the CanDeliverOrder action.

The deliver call should contain a list of all order row ids that should be delivered. If a complete delivery of all rows should be made the list should either contain all order row ids or be empty. However if a subset of all active order rows are specified a partial delivery will be made. Partial delivery can only be made if the order has the CanDeliverOrderPartially action and each OrderRow must have action CanDeliverRow.

Response

12.3.1 Row Delivery Options

12.4 Deliver order with lower amount

Creates a delivery on a checkout order with a lower amount than the total, canceling the remaining amount. Assuming the order got CanDeliverOrder and CanCancelAmount action.

The deliver with lower amount call should be used when the delivery is complete but should not capture the full amount. All order rows will be seen as delivered.

Response

12.5 Cancel Order

Cancel an order before it has been delivered. Assuming the order has the action CanCancelOrder.

Response

If the order is successfully cancelled, Response is empty.

12.6 Cancel order amount

By specifying a higher amount than the current order cancelled amount then the order cancelled amount will increase, assuming the order has the action CanCancelOrderAmount. The delta between the new CancelledAmount and the former CancelledAmount will be cancelled.

The new CancelledAmount cannot be equal to or lower than the current CancelledAmount or more than OrderAmount on the order.

Response

If order amount is successfully cancelled, Response is empty.

12.7 Cancel order row

Changes the status of an order row to Cancelled, assuming the order has the action CanCancelOrderRow and the OrderRow has the action CanCancelRow.

Response

If order row is successfully cancelled, Response is empty.

12.8 Credit order rows

Creates a new credit on the specified delivery with specified order rows. Assuming the delivery has action CanCreditOrderRows and the specified order rows also has action CanCreditRow

Response

On the returned URL can be checked status of the task.

12.8.1 Row Crediting Options

12.9 Credit new order row

By specifying a new credit row, a new credit row will be created on the delivery, assuming the delivery has action CanCreditNewRow.

Response

On the returned URL can be checked status of the task.

12.10 Credit order rows with fee

Creates a new credit on the specified delivery with specified order rows. Assuming the delivery has action CanCreditOrderRows and the specified order rows also has action CanCreditRow. Adds the ability to add a fee to the credit.

Response

On the returned URL can be checked status of the task.

12.11 Credit amount

By specifying a credited amount larger than the current credited amount. A credit is being made on the specified delivery. The credited amount cannot be lower than the current credited amount or larger than the delivered amount.

This method requires CanCreditAmount on the delivery.

Response

If order amount is successfully credited, Response is empty.

12.12 Add order row

This method is used to add order rows to an order, assuming the order has the action CanAddOrderRow. If the new order amount will exceed the current order amount, a credit check will be performed.

Response

On the returned URL (HeaderLocation) can be checked status of the task.

12.13 Update order row

This method is used to update an order row, assuming the order has action "CanUpdateOrderRow" and the order row has the action CanUpdateRow. The method will update all fields set in the payload, if a field is not set the row will keep the current value. If the new order amount will exceed the current order amount, a credit check will be performed.

Response

If order row is successfully updated, Response is empty.

12.14 Replace order rows

This method is used to update an order row, assuming the order has action "CanUpdateOrderRow". This method will delete all the present rows and replace with the ones set in the payload. If the new order amount will exceed the current order amount, a credit check will be performed.

Response

If order row is successfully updated, Response is empty.

12.15 Data objects

12.15.1 Order

12.15.2 Delivery

12.15.3 Credit

12.15.4 Task

12.15.5 Order Row

12.15.6 Address

12.15.7 Order Status

12.15.8 Order actions

12.15.9 Delivery actions

12.15.10 Order Row actions

13. Javascript API

(Please note that the API is still considered a work in progress and might see significant changes.)

API entry point

window.scoApi is the root object for the API and contains all the operations available.

Listening for API readiness

The checkout raises an event when ready, which can be used to safely access the API.

Example:

document.addEventListener("checkoutReady", function() {
    window.scoApi... // Your code here
});

Available operations

observeEvent(propertyString, handlerFunction) => function

Observes the client data for changes, calling the supplied function when a change is detected.

Returns a function that can be called to stop observing the specified property.

The following properties are currently supported:

"identity.isCompany"
"identity.email"
"identity.phoneNumber"
"identity.companyName"
"identity.firstName"
"identity.lastName"
"identity.streetAddress"
"identity.coAddress"
"identity.postalCode"
"identity.city"
"identity.addressLines"

Example:

// Observe the city property
var unsubscribe = window.scoApi.observeEvent("identity.city", function (data) { 
    console.log("City changed to %s.", data.value); 
});

// Stop observing
unsubscribe();

setCheckoutEnabled(value) => void

Pass a false-ish value to disable the checkout. While disabled, the merchant can safely perform updates to the cart. When finished, call setCheckoutEnabled(true) to re-enable the checkout and make it reflect the changes made.