NAV Navbar
  • Track a Resource
  • Track a Resource

    The Form3 API offers a variety of ways to track resources within the system, for example to keep track of the status of a submission.

    Besides the regular fetch and list operations via http GET, you can:

    This guide will introduce both methods and provide ready-to-go code examples in Python.

    Prerequisites

    Before getting started, make sure you have the following things ready to follow along:

    The code example is written in Python using the requests package to access the Form3 API. Each code snippet is a standalone Python program, but make sure to paste the required data for each program at the top. The snippets are tested with Python 3.5, but most likely will also work with other Python versions.

    Track the Payment using Subscriptions

    Using the Notification API, you can subscribe to events such as created or updated for a type of resource. Whenever the event occurs on a type of resource you have subscribed for, a notification is sent to a callback location.

    The Form3 API supports Amazon SQS and webhook URLs as callback locations.

    Create a Subscription using Webhooks

    In order to subscribe to an event via webhook, you need to provide the API with a callback URL. This needs to be a public URL that the API can call and notify you whenever the event has occured.

    Create a Public URL

    The easiest way to set up a public URL for testing is to use a free service like Beeceptor or PostBin, which allow you to inspect any calls made to the URL.

    Create the Subscription Resource

    To subscribe to an event, create a subscription resource. Note the following key attributes:

    In the example below, we create a subscription to the updated event of Payment Submission resources by setting record_type to payment_admission. Note that we're using the webhook callback mechanism by choosing callback_transport to be http. Make sure to add a callback URL in the callback_url parameter.

    Create a webhook subscription

    import requests, uuid
    
    ### Replace these variables with your own data! ###
    client_id = 'YOUR CLIENT ID HERE'
    client_secret = 'YOUR CLIENT SECRET HERE'
    organisation_id = 'YOUR ORGANISATION ID HERE'
    callback_url = 'YOUR CALLBACK URL HERE'
    
    base_url = 'https://api.test.form3.tech/v1'
    
    # Generate IDs
    subscription_id = uuid.uuid4()
    print("Subscription ID: %s" % subscription_id)
    
    # Obtain authentication token
    print("Obtaining bearer token...")
    auth_payload = "grant_type=client_credentials"
    auth_url = '%s/oauth2/token' % base_url
    auth_headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    auth_request = requests.auth.HTTPBasicAuth(client_id, client_secret)
    
    auth = requests.request('post', auth_url, data=auth_payload, auth=auth_request, headers=auth_headers)
    auth_token = auth.json().get('access_token')
    
    # Create subscription resource
    subscription_url = "%s/notification/subscriptions" % base_url
    subscription_payload = """
    {
        "data": {
            "type": "subscriptions",
            "id": "%s",
            "organisation_id": "%s",
            "attributes": {
                "callback_uri": "%s",
                "callback_transport": "http",
                "event_type": "updated",
                "record_type": "payment_submissions"
            }
        }
    }
    """ % (subscription_id, organisation_id, callback_url)
    
    subscription_headers = {
        'authorization': "bearer %s" % auth_token,
        'accept': "application/json",
        'content-type': "application/json",
        'cache-control': "no-cache",
        }
    
    subscription = requests.request("POST", subscription_url, data=subscription_payload, headers=subscription_headers)
    print(subscription.text)
    

    Verify notifications

    The notifications service requires client mutual authentication to ensure all notifications are only sent by Form3 to your webhook. See this section of the API documentation to learn how to verify the Form3 client certificate.

    To test the webhook, Create a payment and send it (see this tutorial to learn how). Once you create the submission resource, check your public URL for incoming calls. If everything worked, a call will have arrived containing "status": "delivery_confirmed".

    Delivery errors

    Subscriptions do not expire, but they can be deactivated if the delivery of a notification fails repeatedly. If this happens, you can reactivate the subscription. See this section of the API documentation to learn more.

    Track changes to a Resource using Audits

    Another way to track resources is using audits. Each time something happens in the system and a resource changes its state, an audit entry is created to document it.

    We'll use an outgoing payment as an example. The best resource to track in this case is the submission resource that was created to submit the payment:

    GET /audit/entries/payment_submissions/{submission_id}

    The response contains a number of AuditEntry elements. Each entry contains an after_data section with a status attribute. This attribute denotes the status of the resource after the event that the AuditEntry element describes.

    A typical successful payment goes through the following stages:

    In case the processing of the payment resource fails at some point in the system, the status update trail would contain an error message and terminate with the status delivery_failed.

    Query the audit trail

    import requests
    from pprint import pprint
    
    ### Replace these variables with your own data! ###
    client_id = 'YOUR CLIENT ID HERE'
    client_secret = 'YOUR CLIENT SECRET HERE'
    auth_token = 'A VALID BEARER TOKEN HERE'
    submission_id = 'A VALID SUBMISSION ID HERE'
    
    base_url = 'https://api.test.form3.tech/v1'
    
    # Obtain authentication token
    print("Obtaining bearer token...")
    auth_payload = "grant_type=client_credentials"
    auth_url = '%s/oauth2/token' % base_url
    auth_headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    auth_request = requests.auth.HTTPBasicAuth(client_id, client_secret)
    
    auth = requests.request('post', auth_url, data=auth_payload, auth=auth_request, headers=auth_headers)
    auth_token = auth.json().get('access_token')
    
    # Query the audit trail
    audit_url = "%s/audit/entries/payment_submissions/%s" % (base_url, submission_id)
    
    audit_headers = {
        'authorization': "bearer %s" % auth_token,
        'cache-control': "no-cache"
        }
    
    audit = requests.request("GET", audit_url, headers=audit_headers)
    pprint(audit.json())