OneSpan Sign Developer: Callback Event Notification – Python

Duo Liang,

Python is one of the most popular general-purpose programming languages for web applications, software development, and desktop GUI domains. 

As a part of the Callback Event Notification blog series, in today’s blog, we will setup a Python web application to serve as a callback listener and respond to OneSpan Sign event notifications. Without further delay, let’s get started!

Callback Event Notification in Action

Before beginning a Python project, be sure you complete the following:

  • Register for Event Notifications: Before the OneSpan Sign system can notify you of an event, you must turn on notifications. Follow this feature guide to learn how to register. In our example, we will simply register from the web portal.
  • Install Python: Python is a cross-platform, interpreted, object-oriented programming language that is perfectly suited for a web application. The sample code used in this blog is based on Python 3.7.
  • Download Ngrok.

The Code

Download the complete source code. Feel free to copy the necessary files directly to your existing project.

The main entrance of the project is the file, where we start the server and listen to port 4449 for connections.

app = Flask(__name__)
if __name__ == '__main__':
    # Run the app server on localhost:4449'localhost', 4449)

We will expose an API route to handle callback requests sent from OneSpan Sign. See the code below to process the event notification.

@app.route('/callback', methods=['POST'])
def callback():
return json.dumps({'success':True}), 200, {'ContentType':'application/json'} 

Once a transaction get completed, OneSpan Sign will make a POST request to the registered URL with the following example JSON payload: 

  "@class": "com.silanis.esl.packages.event.ESLProcessEvent",
  "sessionUser": "0787be84-f095-44c7-ba00-787093df86fc",
  "packageId": "KHiRfOXgKK0gpVWwwpFOSNy6o34=",
  "message": null,
  "documentId": null

The corresponding code to unpack this request looks like this:

    callbackKey = request.headers.get('Authorization')
    callbackPayload = json.loads(
    print('callback key: '+ callbackKey)
    print('callback body: '+ json.dumps(callbackPayload))

    eventName = {
        'PACKAGE_COMPLETE' : packageComplete,
        'PACKAGE_ARCHIVE' : packageArchive,
        'PACKAGE_DECLINE' : packageDecline,

As our main business logic, we will simply download the signed documents if the event name equals “PACKAGE_COMPLETE”, based on the data passed by the callback request:

def packageComplete(callbackPayload):   
    if not os.path.exists(filePath):

    filename = packageId + '.zip' 
    file_path = os.path.join(filePath, filename)
    headers = { 'Authorization' : 'Basic ' + apiKey}
    r = requests.get(apiUrl + '/packages/' + packageId + '/documents/zip', headers, stream=True)
    if r.ok:
        print("saving to", os.path.abspath(file_path))
        with open(file_path, 'wb') as f:
            for chunk in r.iter_content(chunk_size=1024 * 8):
                if chunk:
        print("Download failed: status code {}\n{}".format(r.status_code, r.text))


Perform a Test

Go ahead and run your local server with XAMPP. Then, open a command prompt and change the directory to the location where you saved your ngrok executable. Enter the following command:

ngrok http [port] -host-header="localhost:[port]"

Next, login to your OneSpan Sign account, browse to the Admin page, and modify the domain of your callback URL. 

Finally, create, send, and complete a test package. You should be able to view the signed documents as a zipped file in the location of your choice. The moment OneSpan Sign sends a callback notification to your listener, you’ll see the message below at your output console. 


If you have any questions regarding this blog or anything else concerning integrating OneSpan Sign into your application, visit the Developer Community Forums. Your feedback matters to us!

Browse the Full Blog series:

Duo Liang is a Technical Evangelist and Partner Integrations Developer at OneSpan where he creates and maintains integration guides and code shares, helps customers and partners integrate OneSpan products into their applications, and builds integrations within third party platforms.