Direct Support Site

Results for

icon-search-large No search results yet
Enter your search query above

1. Introduction

To create payments, you need to link your server to our platform via one of our integration modes.
Our Python SDK library is the ideal solution to connect to our platform if you prefer to do so with your own stand-alone system using Python language.

Choosing the Python SDK, you can:

To take full advantage of this SDK, make sure you meet these requirements:

  • Python 2.7 or Python 3.5 and higher

Install the latest version of the Python SDK using PIP package manager:

  • For Python 3.5 or higher, run:
    pip install onlinepayments-sdk-python3

  • For Python 2.7, run:
    pip install onlinepayments-sdk-python2

Find more details on GitHub (Python2, Python3). Also, check out all available SDK objects and properties in our Full API Reference. Once you are all set, read the next chapters on how to prepare and use the SDK.

This guide provides a general overview on the SDK’s functionalities. To see how they precisely work for the different integration modes, see the dedicated guides explaining every step with full code samples:

Target most up-to-date API base URL

We encourage you to always target the most up-to-date API base URL when sending requests to our platform. Have a look at our dedicated guides for a full overview:

To allow you a smooth transition, previous API base URLs remain available until further notice.

2. Initialise SDK

To connect your system to our platform by using the SDK, you need to initialise it at first.

Initialising the SDK requires you to

  • Create test/live account
  • Create properties file
    ; The following keys are optional and use the given value by default.
  • Create an API Key and API Secret for the PSPID you wish to use for transaction processing
  • Initialise an instance of Client / MerchantClient using the API Key / API Secret to set up the connection to our test/live platform

    Remember to pay attention to the environment you get the key set from. API Key and API Secret are different for test and live environments.

    The full path of the API endpoint for the test/live environment is


    As our SDKs always implement the latest version of our API, you can leave out "v2" in your code as shown in the example above

    from onlinepayments.sdk.factory import Factory
    client = Factory.create_client_from_file("payments_sdk.prp",  
    merchant_client = client.merchant(merchantId)

    Where "payments_sdk.prp" is the name of a file with properties.

If you are ready to switch to the live environment, substitute the endpoint link apiEndpoint = '' for the live environment apiEndpoint = ''

The following table provides an overview of the arguments accepted by the individual instances:

  • string merchantId: Your PSPID in either our test environment/live environment. Make sure to use the correct API Key / API Secret together with the conjoining PSPID for your transactions request
  • string apiKey: The API Key you have defined in your PSPID to which you will send the transactions to
  • string apiSecret: The API Secret you have defined in your PSPID to which you will send the transactions to

    Check out our dedicated guide to learn all about API Key / API Secret

  • string apiEndpoint: It contains a link to either our test or live environment where your transaction requests are sent to

    The full path of the of API endpoint for test/live environment is


    respectively. As our SDKs always implement the latest version of our API, you can leave out "v2" in your code as shown in the example above

  • string integrator: Your (company) name or any unique identifier. We can use the value for debugging and tracking request you have sent to our platform. Therefore, we strongly suggest sending a value we can identify your requests easily in our logs

After initialisation, you can send requests to our platform via your PSPID. Learn how to do this in the next chapter. 

For transactions with no financial impact, use TEST-URL. The transactions will be sent to our test environment, thereby to your test account

For transactions with a financial impact, use the LIVE-URL. The transactions will be sent to our live environment, thereby to your live account

3. Use SDK

After the successful initialisation of the Client instance, you gain full access to our RESTful API. It enables you to:

  • Send requests for new transactions for any of our server integration modes
  • Get your transactions’ current status
  • Perform maintenance requests (i.e., captures, refunds) on existing transactions

Make sure that the payment method you would like to use is active in your test/live account. Check in the Back Office via Configuration > Payment methods 

Check out our test cases in GitHub (Python2, Python3), including full code samples, and our Full API Reference to learn what is possible.

Below you may find some of the most common actions you can perform:

Create new transactions

To create a new transaction, you can use a Client or MerchantClient instance for any of our integration modes to create a new transaction. It can be done through: 

  • Routing the request to your PSPID on our platform (for Client)
  • Creating a request for the respective integration mode

The SDK instance only keeps track of the data used to initialise it. It does not track neither active sessions nor previous requests. Your system is responsible for managing Direct sessions and payments

Sessions and payments do not impact other sessions and payments

Below you can find code samples related to particular integration modes:

Hosted Checkout Page

To use this integration mode, you need to create a CreateHostedCheckoutRequest call. It must contain at least an Order object.

""" Initialization... """

order_dict = {
    "order": {"amountOfMoney": {"currencyCode": "EUR", "amount": 123}}

hosted_checkout_client = client.merchant(merchantId).hosted_checkout()
hosted_checkout_request = CreateHostedCheckoutRequest()

hosted_checkout_response = hosted_checkout_client.create_hosted_checkout(

You can specify an optional returnUrl, which will be used to redirect your customer back to your website

This call returns a CreateHostedCheckoutResponse response. Store the hostedCheckoutId and RETURNMAC it contains, as well as any other information relevant for you. You will need these for steps described in the following chapters.

This response also contains a partialRedirectURL.

You have to concatenate the base URL "https://payment." with partialRedirectURL according to the formula

https://payment. + partialRedirectURL

and perform a redirection of your customer to this URL. Once the customer visits the Hosted Checkout Page, the payment process continues there.

The newest version of our SDK also returns the full path in redirectURL, allowing you to skip concatenate the base URL "https://payment." with partialRedirectURL. Learn more more in our  Hosted Checkout Page  guide. 

Hosted Tokenization Page

To use this integration method, you need to

from onlinepayments.sdk.domain.create_hosted_tokenization_request import CreateHostedTokenizationRequest

""" Initialization... """

request = CreateHostedTokenizationRequest()
        "variant": "template.html"
hosted_t_client = client.merchant_client().hosted_tokenization()
response = hosted_t_client.create_hosted_tokenization(request)

From response retrieve hosted_tokenizationId and partial_redirect_url:

t_id = response.hosted_tokenization_id
url = response.partial_redirect_url

Use the  partial_redirect_url for the iframe and the hosted_tokenizationId  or token_id (see infobox) to create the actual payment via Server-to-server integration mode.

You can send either the tokenID or the hostedTokenizationId in your CreatePayment request. Learn more about using either option in the dedicated chapters of our Hosted Tokenization Page guide:

token = hosted_t_client.get_hosted_tokenization(t_id)

# Dictionary with all needed data for payment request
payment_dict = {
    "order": {"amountOfMoney": {"currencyCode": "EUR", "amount": 12300}},
    "CardPaymentMethodSpecificInput": {
        "token": token,

payment_request = CreatePaymentRequest().from_dictionary(payment_dict)
payment_response = merchant_client.payments().create_payment(payment_request)


A minimum paymentResponse requires you to set at least an Order object and a payment method:

""" Initialization... """

# Dictionary with all needed data for payment request
payment_dict = {
    "order": {"amountOfMoney": {"currencyCode": "EUR", "amount": 125000}},
    "cardPaymentMethodSpecificInput": {
        "card": {
            "cvv": "123",
            "cardNumber": "5300000000000006",
            "expiryDate": "0124",
            "cardholderName": "John Doe"
        "paymentProductId": 3

payment_request = CreatePaymentRequest()
payment_response = merchant_client.payments().create_payment(payment_request)

We have dedicated guides for each of the aforementioned integration modes:

The documents contain all crucial details you need to profit from the integration modes’ full potential, including full transaction flows, code samples and other useful features

Get transaction status

Our RESTful API allows you to request a transaction’s status anytime by one of our GET calls:

A GetPayment request looks like this: 

response = merchant_client.payments().get_payment(payment_id)
string payment_id: The 10-digit unique reference of your transaction on our platform. This reference can be retrieved from the hosted_checkout_client.create_hosted_checkout()
 or merchant_client.payments().create_payment(payment_request) created in the previous section.

For more information about statuses visit the status documentation page.

Perform maintenance operation

To perform follow-up actions on existing transactions (i.e. captures or refunds), use our CapturePayment or RefundPayment API call respectively:


from onlinepayments.sdk.domain.capture_payment_request import CapturePaymentRequest

""" Initialization... """

# Here you get payment_id you can use in the further code
payment_id =
capture_request = CapturePaymentRequest()
capture_request.from_dictionary({'amount': amount, 'isFinal': True})

merchant_client.payments().capture_payment(payment_id, capture_request)


from onlinepayments.sdk.domain.refund_request import RefundRequest

 """ Initialization... """

payment_id =
refund_dict = {"amountOfMoney": {"currencyCode": "EUR", "amount": 125000}}
refund_request = RefundRequest().from_dictionary(refund_dict)

# Get RefundResponse object
response = merchant_client.payments().refund_payment(payment_id, refund_request)
string PAYMENT_ID: The 10-digit unique reference of your transaction on our platform. This reference can be retrieved from the directSdk.payments.createPayment()  or directSdk.hostedCheckout.createHostedCheckout() created in the previous section.

4. Handle exceptions

If a transaction is rejected, our platform provides detailed information with an Exception instance. The affiliated HTTP status code also help you troubleshoot the error.

You can encounter two types of exceptions: transaction exceptions and HTTP exceptions.

Transaction exceptions

This kind of exception refers to transaction requests that are technically correct but were rejected by your customer’s issuer or your acquirer. If the transaction is returned in the exception, it means that it was created in our systems but not successfully processed. 

The following code samples use implicit methods provided as an example. You are expected to provide your own implementation for these or replace them with similar logic
  • def is_not_successful(*args, **kwargs) -> bool:  
       Check if the transaction is successful 
    according to PaymentResponse properties 
    status_output.status_category and status_output.status_code. 
  • def handle_error(*args, **kwargs) -> None:  
       Process the transaction according to its status. 

Exception type /
HTTP status code
Code Sample
Rejected transactions / 
Various(see PaymentResponse object)

from onlinepayments.sdk.declined_payment_exception import DeclinedPaymentException

""" Initialization... """

    payment_response = merchant_client.payments().create_payment(payment_request)
    payment_id =
except DeclinedPaymentException as e:
    payment = e.create_payment_result.payment
    payment_id =
    payment_status = payment.status

payment_response = merchant_client.payments().get_payment(payment_id)

# Your code to check transaction status and handle errors. 
if is_not_successful(payment_response):
Rejected Refund /
Various(see PaymentResponse object)

from onlinepayments.sdk.declined_refund_exception import DeclinedRefundException

""" Initialization... """

payment_response = merchant_client.payments().create_payment(payment_request)
payment_id =

refund_id = None
    refund_request = RefundRequest().from_dictionary(refund_dict)
    refund_response = merchant_client.payments().refund_payment(payment_id, refund_request)
    refund_id =
except DeclinedRefundException as e:
    refund_result = e.refund_result

refund_response = merchant_client.payments().get_refunds(payment_id)

# Your code to check transaction status and handle errors.
if is_not_successful(refund_response, refund_id):

HTTP exceptions

This kind of exception refers to various problems caused by technical errors in the API call or payment request.

You can combine any of the following code snippets with this standard CreatePayment request:

import logging as log
from onlinepayments.sdk.api_exception import ApiException
from onlinepayments.sdk.domain.create_payment_request import CreatePaymentRequest

""" Initialization... """

payment_dict = {
    "order": {"amountOfMoney": {"currencyCode": "EUR", "amount": 125000}},
    "cardPaymentMethodSpecificInput": {
        "card": {
            "cvv": "123",
            "cardNumber": "5300000000000006",
            "expiryDate": "0124",
            "cardholderName": "John Doe"
        "paymentProductId": 3

payment_requests = CreatePaymentRequest()
    payment_response = merchant_clients.payments().create_payment(payment_request)
except ApiException as e:
   # Refer to the list below to see how 
   # specific implementations of ApiException can be handled.

Exception type / 
HTTP status code
Code Sample
except ValidationException as e:
log.error("Input validation error:")
for error in e.errors:
if error.property_name is not None:
log.error(f"{error.code}: {error.message}")
log.error(f"{error.property_name}: {error.code}: {error.message}")
AuthorizationException / 
except AuthorizationException as e:
log.error("Authorization error:")
for error in e.errors:
log.error(f"{error.code}: {error.message}")
except IdempotenceException as e:
log.error("Idempotence error:")
for error in e.errors:
log.error(f"{error.code}: {error.message}")}}
except ReferenceException as e:
log.error("Incorrect object reference:")
for error in e.errors:
log.error(f"{error.code}: {error.message}") }}
except ApiException as e:
direct_er = [error for error in e.errors if error.http_status_code in [500, 502, 503]]
if direct_er:
log.error("Error occurred at Direct or a downstream partner/acquirer:")
for error in direct_er:
log.error(f"{error.code}: {error.message}")}}
ApiException /
Any other codes
except ApiException as e:
log.error("Platform error: ")
for error in e.errors:
log.error(f"{error.code}: {error.message}")}}
CommunicationException /
300 codes without a body or non-JSON response
except CommunicationException as e:
log.error(f"Communication exception: {e}")}}

HTTP status codes 

All our exceptions are linked to one or more HTTP status codes, indicating the root cause for many possible errors.

Status code Description Exception type

Our platform processed your request correctly



Our platform processed your request correctly and created a new resource. We return the URI of this resource in the Location header of the response



No content
Our platform processed your request correctly


CreatePaymentResult key is in the response

Payment Rejected
Either our platform or one of our downstream partners/acquirers rejected your request


PayoutResult is present in the response

Payout Rejected
Your request was rejected either by the Direct platform or one of our downstream partners/acquirers


RefundResult key is in the response

Refund Rejected
Either our platform or one of our downstream partners/acquirers rejected your request



Bad Request
Your request contains errors, thus our platform cannot process it



Not Authorised
You are trying to do something that is not allowed or that you are not authorised to do



Not Found
The object you were trying to access could not be found on the server



Your idempotent request resulted in a conflict because of either: 

  • The first request has not finished yet
  • Your request resulted in a conflict. Either you submitted a duplicate request, or you are trying to create something with a duplicate key



The object that you are trying to reach has been removed.



Internal Server Error
An error occurred on our platform


502 Bad Gateway
Our platform was unable to process a message from a downstream partner/acquirer
503 Service Unavailable
The service that you are trying to reach is temporarily unavailable. Please try again later
Other Unexpected error
An unexpected error has occurred

5. Use additional features

The SDK has a lot more to offer. Have a look at the following features, as they will help you build the perfect solution.

Get available payment methods

Before you initiate the actual payment process, you send a GetPaymentProducts request to our platform. The response contains a list of available payment methods in your PSPID. Depending on your customers’ preferences, you can offer a selection on our Hosted Checkout Page or on your own webshop environment using subsequent CreatePayment requests.

from onlinepayments.sdk.merchant.products.get_payment_product_params import GetPaymentProductParams

""" Initialization... """

product_params = GetPaymentProductParams()
product_params.country_code = "FR"
product_params.currency_code = "EUR"

response = merchant_client.products().get_payment_products(product_params)

Response is an instance of GetPaymentsProductsResponse with a list of available payment products.

Send idempotent requests

One of the main REST API features is its ability to detect and prevent sending requests (i.e. payment requests) accidentally twice. The SDK makes it very easy for you to ensure that you send only unique – idempotent – requests to our platform.

Use the additional argument  context and set its property named idempotence_key to a CreatePayment request. The SDK will send an X-GCS-Idempotence-Key header with the idempotence key as its value.

If you send requests this way to our platform, we will check the following

  • If you send subsequent request with the same idempotence key, the response contains an X-GCS-Idempotence-Request-Timestamp header. The SDK will set the idempotence_request_timestamp property of the CallContext argument
  • If the first request is not finished yet, the RESTful Server API returns a 409 status code. Then the SDK throws an IdempotenceException with the original idempotence key and the idempotence request timestamp

from onlinepayments.sdk.call_context import CallContext
from onlinepayments.sdk.idempotence_exception import IdempotenceException

""" Initialization... """

context = CallContext(idempotence_key="your_key_for_payment")

payment_client = client.merchant_client.payments()
    payment_response = payment_client.create_payment(payment_request, context)
except IdempotenceException as e:
    # a request with the same idempotence_key is still in progress, try again after a short pause
    # e.idempotence_request_timestamp contains the value of the
    # X-GCS-Idempotence-Request-Timestamp header"Idempotent request: {e.idempotence_request_timestamp}")
    idempotence_timestamp = context.idempotence_request_timestamp
    # idempotence_request_timestamp contains the value of the
    # X-GCS-Idempotence-Request-Timestamp header
    # if idempotence_timestamp is not empty, this was not the first request
If an idempotence key is sent for a call that does not support idempotence, the RESTful Server API will ignore the key and treat the request as a first request.

Use logging

The SDK supports logging of requests, responses, and exceptions of the API communication. These can be helpful for troubleshooting or tracing individual steps in the payment flow.

To use this logging feature, you should implement the CommunicatorLogger class. The Python SDK offers an interface based on the print method (SysOutCommunicatorLogger).

Have a look at a code sample presenting the case of adding a logger:

from onlinepayments.sdk.log.sys_out_communicator_logger import SysOutCommunicatorLogger

""" Initialization... """

log_interface = SysOutCommunicatorLogger()
# Do some calls ...

The SDK obfuscates sensitive data in the logger

Connection pooling

You can manage your network resources by limiting the number of possible connections the SDK creates and maintains. The Client instances created as discussed in the Initialise SDK chapter will have their own connection pool. The Client instances created with the same Communicator object share a connection pool.

If you use multiple Client instances to share a single connection pool, make sure to follow these steps:

  1. Create a shared Communicator . You can use the Factory class 
  2. Create Client instances with that Communicator

from onlinepayments.sdk.factory import Factory
# Create shared communicator.
communicator = Factory.create_communicator_from_file(
    "payments_sdk.prp", apiKey, apiSecret
# Create one or more clients using the shared communicator.
client = Factory.create_client_from_communicator(communicator)

Customise communication

A Client uses a Communicator to communicate with our platform. Communicator implementations transform a request object to a HTTP request and a HTTP response to a response object. If needed, you can extend this class. To instantiate a Client that uses your own implementation of Communicator, you can use the following code snippet:

from onlinepayments.sdk.factory import Factory
communicator = YourCommunicator()
client = Factory.create_client_from_communicator(communicator)

However, for most customisations, you do not have to extend Communicator. The functionality of the Communicator is built on the following classes: Authenticator, Connection, Marshaller and MetaDataProvider, the implementation of which can easily be extended or replaced.

Marshaller is used to marshal and unmarshal request and response objects to and from JSON. We do not recommend changing this module. The other modules needed to communicate with the Direct platform are the following:

  • Connection for one or more HTTP connections to our server
  • Authenticator to sign your requests
  • MetaDataProvider constructing the header with your server’s meta data

For your convenience, the Factory.create_communicator_from_configuration and Factory.create_communicator_from_file methods can take optional arguments to set the Connection, Authenticator, Marshaller or MetaDataProvider modules. For example, the following code snippet allows you to use your own Communicator implementation:

connection = YourConnection()
communicator = Factory.create_communicator_from_file(configuration_file_name,
     api_key_id = "api_key_id",
secret_api_key = "secret_api_key",
connection = connection) client = Factory.create_client_from_communicator(communicator)


The part of the SDK that handles the webhooks support is called the webhooks helper. It transparently handles both validation of signatures against the event bodies sent by the webhooks system (including finding the secret key for key IDs - not to be confused with the API Key and API Secret), and unmarshalling of these bodies to objects. This allows you to focus on the essentials, without going through all the additional information and extracting the desired ones by yourself. To learn more about webhooks, read our dedicated guide. 

Provide secret keys

Configure the "WebhooksKey" / "WebhooksKeySecret" and your server webhooks endpoints in the Merchant Portal:

key_id = "webhooks_key"
secret_key = "webhooks_key_secret"

Use InMemorySecretKeyStore to store a secret key for a key ID:

from onlinepayments.sdk.webhooks.in_memory_secret_key_store import InMemorySecretKeyStore

key_store = InMemorySecretKeyStore()
key_store.store_secret_key(key_id, secret_key)

You can add or remove keys using the following functions:

  • The key ID to return the secret key for
  • A callback function that either takes an error as its first argument, or the secret key for the given key ID as its second argument (in which case the first argument must be null)

The SDK provides one implementation for this function: webhooks.inMemorySecretKeyStore.getSecretKey. This will retrieve secret keys from an in-memory key store.

You can add or remove keys using the following functions:

  • key_store.get_secret_key(key_id) to get the stored secret key for a key ID
  • key_store.remove_secret_key(key_id) to remove the stored secret key for a key ID
  • key_store.clear() to remove all stored secret keys

If you require more advanced storage, i.e. for a database or file system, we recommend writing your own implementation.

Initialise webhooks helper

Include and initialise the webhooks helper as follows:

from onlinepayments.sdk.webhooks.web_hooks import Webhooks
helper = Webhooks.create_helper(key_store)

Use webhook helper

You can call a webhook helper to unmarshal incoming events which allows you to process data in your application. It takes the following arguments:

  • The body as  bytes. This should be the raw body as received from the webhooks system
  • A list with objects containing the request headers as received from the webhooks system. Each header object should have name and value properties

webhook_event = helper.unmarshal(body, headers)
# Process an exception
# Process event