Python SDK
Introduction
To understand how to use this SDK, it is best to read the following documentation:
API Reference
This SDK wraps the Server API and (amongst other things) exposes the responses of the webservice calls as JavaScript objects. Understanding the Acquiring API will help you understand these SDK objects as well.
The explanation of all the various
features
we offer.
This current document will help you understand the global flow when interacting with the Worldline platform using the Python SDK.
Introduction
To understand how to use this SDK, it is best to read the following documentation:
API Reference
This SDK wraps the Server API and (amongst other things) exposes the responses of the webservice calls as JavaScript objects. Understanding the Acquiring API will help you understand these SDK objects as well.The explanation of all the various features we offer.
This current document will help you understand the global flow when interacting with the Worldline platform using the Python SDK.
The Python SDK helps you to communicate with the Acquiring API . More specifically, it offers a fluent Python API that provides access to all the functionality of the RESTful API. Below, we discuss the following topics in detail.
Initialization of the SDK
Exceptions
Logging
Advanced use: Connection pooling
Advanced use: Customization of the communication
Notes
The source code of the SDK is available on Github . There you can find installation instructions.
The API documentation of the latest version of the SDK is available here . For a specific major version, replace latest with the actual version in format <major>.x .
Initialization of the Python SDK
All Python code snippets presented in the API Reference assume you have initialized the Python SDK before using them in your Development Environment. This section details the initialization of the Python SDK.
Initializing is simple, and requires only one key task: use our Factory class to create an instance of Client , which contains the actual methods to communicate with the Server API.
The Factory needs the following input information to provide you with an initialized Client
A String to the configuration file with your connection configuration.
The oauth2_token_uri , oauth2_client_id and oauth2_client_secret .The property file should contain the following keys:
[AcquiringSDK]
acquiring.api.integrator=<your company name>
acquiring.api.endpoint.host=api.preprod.acquiring.worldline-solutions.com
acquiring.api.authorizationType=OAuth2
acquiring.api.oauth2.tokenUri=https://auth-test-eu-west-1.aws.bambora.com/connect/token
acquiring.api.connectTimeout=5 # use -1 for no timeout
acquiring.api.socketTimeout=300 # use -1 for no timeout
acquiring.api.maxConnections=10 # to support 10 concurrent connections
We recommend to keep the timeout values at these values. See API endpoints for the possible hosts and token URIs.
If a proxy should be used, the property file should additionally contain the following key(s) under the [AcquiringSDK] section:
acquiring.api.proxy.uri=<URL to the proxy host including leading http:// or https://>
# omit the following two lines if no proxy authentication is required
acquiring.api.proxy.username=<username for the proxy>
acquiring.api.proxy.password=<password for the proxy>
You can create an instance of Client using the Factory with this code snippet:
client = Factory.create_client_from_file(configuration_file_name, "oauth2_client_id", "oauth2_client_secret")
This Client instance offers connection pooling and can be reused for multiple concurrent API calls. Once it is no longer used, it should be closed.
Client defines __enter__ and __exit__ methods, which allows it to be used in with statements.
Connection management
Connection pooling is configured with the max_connections setting in CommunicatorConfiguration or in the configuration file. Its value determines how many connections to the Server API are kept alive for re-use in a connection pool. If there are more requests in progress than this maximum number of connections, then a new connection will be temporarily opened.
Exceptions
All calls can raise one of the following runtime exceptions:
A ValidationException if the request was not correct and couldn't be processed (HTTP status code 400)
An AuthorizationException if the request was not allowed (HTTP status code 403)
An IdempotenceException if an idempotent request caused a conflict (HTTP status code 409)
A ReferenceException if an object was attempted to be referenced that doesn't exist or has been removed, or there was a conflict (HTTP status code 404, 409 or 410)
A PlatformException if something went wrong on the Worldline platform. The Worldline platform was unable to process a message from a downstream partner/acquirer, or the service that you're trying to reach is temporary unavailable (HTTP status code 500, 502 or 503)
An ApiException if the RESTful Server API returned any other error
A payment attempt can now be handled as follows:
try:
response = client.v1().acquirer(acquirer_id).merchants(merchant_id).payments().process_payment(request)
except ValidationException as e:
sys.stderr.write("Input validation error: " + e.detail)
except AuthorizationException as e:
sys.stderr.write("Authorization error: " + e.detail)
except ReferenceException as e:
sys.stderr.write("Incorrect object reference: " + e.detail)
except PlatformException as e:
sys.stderr.write("Error occurred at Worldline or a downstream partner/acquirer: " + e.detail)
except ApiException as e:
sys.stderr.write("Worldline error: " + e.status_code + ", " + e.detail)
Exception overview
The following table is a summary that shows when each of these exceptions will be raised:
HTTP status code |
Meaning |
Description |
Exception Type |
---|---|---|---|
200 |
Successful |
Your request was processed correctly |
N/A |
201 |
Created |
Your request was processed correctly and a new resource was created.
|
N/A |
204 |
No Content |
Your request was processed correctly |
N/A |
400 |
Bad Request |
Your request is not correct and can't be processed. Please correct the mistake and try again. |
ValidationException |
403 |
Not Authorized |
You're trying to do something that is not allowed or that you're not authorized to do. |
AuthorizationException |
404 |
Not Found |
The object you were trying to access could not be found on the server. |
ReferenceException |
409 |
Conflict |
Your idempotent request resulted in a conflict. The first request has not finished yet. |
IdempotenceException |
409 |
Conflict |
Your request resulted in a conflict. Either you submitted a duplicate request or you're trying to create something with a duplicate key. |
ReferenceException |
500 |
Internal Server Error |
Something went wrong on the Worldline platform. |
PlatformException |
502 |
Bad Gateway |
The Worldline platform was unable to process a message from a downstream partner/acquirer. |
PlatformException |
503 |
Service Unavailable |
The service that you're trying to reach is temporary unavailable.
|
PlatformException |
other |
Unexpected error |
An unexpected error has occurred |
ApiException |
HTTP status code 401 responses are automatically handled by the SDK and will not result in an exception if your OAuth2 credentials are valid. The SDK will automatically try to renew the access token if it gets such a response.
Logging
The Python SDK supports logging of requests, responses and exceptions of the API communication.
In order to start using the logging feature, an implementation of the CommunicatorLogger interface should be provided. The SDK provides two example implementations for logging to sys.stdout ( SysOutCommunicatorLogger ) and logging to a logger ( PythonCommunicatorLogger ).
Logging can be enabled by calling the enable_logging method on a Client object, and providing the logger as an argument. The logger can subsequently be disabled by calling the disable_logging method.
When logged messages contain sensitive data, this data is obfuscated.
The following code exemplifies the use of adding a logger:
client = Factory.create_client_from_file(configuration_file_name, "oauth2_client_id", "oauth2_client_secret")
logger = PythonCommunicatorLogger(logging.get_logger(...), 800)
client.enable_logging(logger)
# ... Do some calls
client.disable_logging()
Advanced use: Connection pooling
A Client created using the Factory class from a properties file or CommunicatorConfiguration object will use its own connection pool. If multiple clients should share a single connection pool, the Factory class should be used to first create a shared Communicator , then to create Client instances that use that Communicator :
communicator = Factory.create_communicator(configuration_file_name, "oauth2_client_id", "oauth2_client_secret")
client = Factory.create_client_from_communicator(communicator)
Instead of closing these Client instances, you should instead close the Communicator when it is no longer needed. This will close all Client instances that use the Communicator .
If instead, one of the Client instances is closed, the Communicator will be closed as well. As a result, all other Client instances that use the Communicator will also be closed. Attempting to use a closed Client or Communicator will result in an error.
Just like Client , Communicator defines __enter__ and __exit__ methods, and can therefore also be used in with statements.
Connection management
Just like Client , Communicator also has method close_expired_connections that can be used to evict expired HTTP connections. You can call this method on the Communicator instead of on any of the Client instances. The effect will be the same.
Advanced use: Customization of the communication
A Client uses a Communicator to communicate with the RESTful Server API. A Communicator contains all the logic to transform a request object to an HTTP request and an 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:
communicator = YourCommunicator()
client = Factory.create_client_from_communicator(communicator)
However, for most customizations you do not have to extend Communicator . The functionality of the Communicator is built on the following:
The RESTful Server API endpoint URI.
A Connection , which represents one or more HTTP connections to the Worldline server.
An Authenticator , which is used to sign your requests.
A MetadataProvider , which constructs the header with metadata of your server that is sent in requests for BI and fraud prevention purposes.
A Marshaller , which is used to marshal and unmarshal request and response objects to and from JSON.
For your convenience, the Factory.create_communicator_from_configuration , Factory.create_communicator_from_file , Factory.create_client_from_configuration and Factory.create_client_from_file methods can take optional arguments to set the Connection , Authenticator , MetadataProvider or Marshaller components. For example, the following code snippet:
connection = YourConnection()
client = Factory.create_client_from_file(configuration_file_name, "oauth2_client_id", "oauth2_client_secret",
connection = connection)
Connection management
Calling close_expired_connections on a Client or a Communicator object only works if the Connection extends PooledConnection , otherwise these methods do nothing. If you write a custom Connection that uses a pool of HTTP connections, extend PooledConnection instead.
Logging
To facilitate implementing logging in a custom Connection , the SDK provides utility classes RequestLogMessage and ResponseLogMessage . These can be used to easily construct request and response messages. For instance:
# In the below code, logger is the CommunicatorLogger set using enable_logging.
# Note that it may be None if enable_logging is not called.
request_id = uuid.uuid4()
request_log_message = RequestLogMessage(request_id, method, uri)
# add request headers to request_log_message
# if present, set the request body on request_log_message
logger.log(request_log_message.get_message())
start_time = time.time() * 1000
# send the request
end_time = time.time() * 1000
duration = end_time - start_time
status_code = ...
# note: duration is optional
response_log_message = ResponseLogMessage(request_id, status_code, duration)
# add response headers to response_log_message
# if present, set the response body on response_log_message
logger.log(response_log_message.get_message())
Notes
Renaming of properties
The Python SDK uses Python naming conventions. As a result, properties have been turned into so-called Snake case . For example, cardNumber is called card_number .