Payments Synchronization Guidance

Synchronizing Payments using the Pushpay API

Overview

As payments are made in Pushpay, the information about those payments is made available via the Pushpay public API - a common need is to query for recent payments and then record them in a 3rd party system. This document serves as a guide to our API users who are looking to build a new integration using the API.

Glossary

  • Organization - the organization using Pushpay to provide a payment solution - they will have 1 or more merchant listings.
  • Merchant listing - a merchant listing is a single giving page or listing in the mobile app.  Payments are always linked to a single listing.  Sometimes this is just referred to as "Merchant" or "Listing".
  • Reference Field - Reference fields are custom fields belonging to each listing - payments made for a listing can include these reference fields.  
    • There are 3 types of custom field - Text box, Number field and Drop down list (single select).  A merchant may only have one drop down field.
    • A drop down reference field has both a label and a value - the value can be used to represent the internal value for a Fund in a 3rd party system if necessary.
    • Fields are always owned by the listing - a single field can not be shared across multiple listings.
  • Fund - the fund a payment is associated with. Funds have a label and value similar to drop down reference fields.
  • Public API - the API we make available to 3rd party integrations - it's documented here: https://pushpay.io/docs/operations
  • Community Member - When a payment is made to a merchant listing there is an associated community member linked to that payment.  Community members have a name, email address and a type (Pending or Registered) and an Export Key (Your ID).
  • Your ID - The your ID is the "External system" identifier for a community member - many churches would call this an "envelope number" or "person id" or "community member id" etc. depending on the Church management system they are making use of.   At current we have 2 common names in use for this field - in the UI and file exports we call this "Your ID", in the public API we call this "ExportKey".
  • Settlement - The terms "Settlement", "Deposit" and "Batch/Settlement Batch" are all interchangeable here and represent a batch of transactions in Pushpay (credit card or ACH) which will be paid into the merchants bank account as one or more deposits. Settlements are used to aid in reconciliation of deposits to payments, so the deposited amount can split across the chart of accounts based on the Fund the payment was attributed to.

Authentication

  • Authentication requires using OAuth2 (Client Flow or Code Flow) - as documented in our API docs - https://pushpay.io/docs/security
  • If you are building a B2B Integration, you will be required to use Code Flow
    • Client ID and Client Secret in your integrations should be configurable, as should the URL for the API.
      • Pushpay will issue different credentials for sandbox and production.
      • The sandbox environment's API has a different URL to production.
    • Access token lifetime is 1 hour - refresh token lifetime is unlimited.  The refresh token must be stored in a secure manner.
  • If you are a singular entity building a bespoke integration that will not server more than one organization, you can use Client Flow for Authorization

Rate Limiting

For guidance on how to handle rate limiting please see here.

Process - Payment Import

A step-by-step process of how payment synchronization generally works.

  1. Authentication

    Code Flow: https://pushpay.io/docs/security#oauth_code_flow

    Client Flow: https://pushpay.io/docs/security#oauthclientcredentials_flow

    In both cases the following scopes will be needed to synchronize payments:

    • read
    • merchant:view_payments
    • merchant:view_recurring_payments
    • list_my_merchants
  2. Retrieve the list of in-scope organizations
    https://pushpay.io/docs/operations/organizations#get_v1organizations_in-scope
    GET /v1/organizations/in-scope

    • Return the list of organizations your code can retrieve payments for.
  3. Retrieve the list of merchant listing for each organization you have access to
    https://pushpay.io/docs/operations/organizations#get_v1organizationorganizationKeymerchantlistings
    GET /v1/organization/{organizationKey}/merchantlistings

    • Return the list of merchant listings for the specified organization.
    • For each merchant listing you will be able to:

      • Find the "key" of the merchant listing, used to identify the listing the payment was made against. Store the key and name in your DB for reference
      • If you plan to use Pre-configured Giving links ensure you also store the "handle"

        {
        "page": 0,
        "pageSize": 25,
        "total": 1,
        "totalPages": 1,
        "items": [
            {
            "homeCountry": "NZ",
            "visibility": "Visible",
            "status": "Active",
            "version": 50,
            "key": "MTIzOkRUclhHb1Jtc24tX3NKMGxjZzJ3cUJqb1ZlTQ",
            "handle": "widgetinc",
            "name": "Widgets Inc",
            "address": "123 Summer Grove",
            "location": {
                "latitude": -36.8567852,
                "longitude": 174.7583516
        },
        
  4. Retrieve payements at an organization level
    Doing this requires less calls as you get all payments for all merchant listings (as opposed to making a call per listing)
    https://pushpay.io/docs/operations/payments#get_v1organizationorganizationKeypayments
    GET /v1/organization/{organizationKey}/payments

    We recommend using the following query parameters:

    • updatedFrom
    • updatedTo

    Select a frequency for your calls e.g. every hour on the hour. In addition ensure you have an overlap to catch all the payments. E.g. at 2pm you make a call for the previous hour + 10 minutes:

    • updatedFrom=2020-01-01T12:50:00Z
    • updatedTo=2020-01-01T14:00:00Z

    https://api.pushpay.com/v1/organization/MTpZc2M4M3hOM05KMmdxOHpDQklvYkxqQWpfY2M/payments?updatedFrom=2020-01-01T12:50:00Z&updatedTo=2020-01-01T14:00:00Z

    You can then poll our API every hour pushing the window forward by one hour each time. Ensure you always have that 10 minute overlap.

  5. Donor Identification
    https://pushpay.io/docs/operations/payments#get_v1organizationorganizationKeypayments

    In the payment, find the payer representation - which will have a key - this is the "pushpay account key":

    "payer": {
                    "key": "MDoxWWpVN2dpTjNzeDdfMTdCcXk1bnZjOUJ5Qzg",
                    "emailAddress": "joe.bloggs@test.com",
                    "mobileNumber": "+15555555555",
                    "fullName": "Joe Bloggs"
                    ...
                  },
    
    Note! Depending on your integration's goals, you may also want to synchronize recurring payments - the API is documented here: https://pushpay.io/docs/operations/payments#get__v1_organization_organizationKey_recurringpayments. For a financial system integration we also make the settlements for a merchant available via the API: https://pushpay.io/docs/operations#settlements

Process - Settlement Batch Import

A step-by-step process of how a settlement batch import generally works.

  1. Authentication
    Code Flow: https://pushpay.io/docs/security#oauth_code_flow

    Client Flow: https://pushpay.io/docs/security#oauthclientcredentials_flow

    In both cases the following scopes will be needed to synchronize payments:

    • read
    • merchant:view_payments
    • merchant:view_recurring_payments
    • list_my_merchants
  2. Retrieve the list of in-scope organizations https://pushpay.io/docs/operations/organizations#get_v1organizations_in-scope GET /v1/organizations/in-scope

    • Return the list of organizations your code can retrieve payments for.
  3. Retrieve the list of merchant listing for each organization you have access to
    https://pushpay.io/docs/operations/organizations#get_v1organizationorganizationKeymerchantlistings
    GET /v1/organization/{organizationKey}/merchantlistings

    • Return the list of merchant listings for the specified organization.
  4. Fetch recent settlements
    https://pushpay.io/docs/operations/settlements#get__v1_merchant_merchantKey_settlements

    Fetch the settlements updated since last time your code checked.

    Note! There is no merchant Key in the URL - this is because a single settlement can be for payments made to multiple listings, depending on how the individual merchant listings are configured e.g. if they remit funds into the same bank account or not.

    GET /v1/settlements?updatedFrom=2015-12-11T00:00:00Z&page=0

    The results are paged so you will need to keep fetching pages of settlements until you've read them all.

    GET /v1/settlements?updatedFrom=2015-12-11T00:00:00Z&page=1
    GET /v1/settlements?updatedFrom=2015-12-11T00:00:00Z&page=2

    Each page of settlements details returned will include some links in the response for the next page, if there is one - using these links can simplify the process of paging in our API.

        "_links": {
                "self": {
                "href": "https://api.pushpay.com/v1/merchant/MTpZc2M4M3hOM05KMmdxOHpDQklvYkxqQWpfY2M/settlements?updatedFrom=2015-12-11T00:00:00Z&page=1"
                },
                "next": {
                "href": "https://api.pushpay.com/v1/merchant/MTpZc2M4M3hOM05KMmdxOHpDQklvYkxqQWpfY2M/settlements?updatedFrom=2015-12-11T00:00:00Z&page=2"
                    }
                }
    

    As an alternative, if it makes sense you can loop through individual merchant listings, retrieving the settlements per merchant listing (this is similar the payment import process described earlier in this document).

  5. Loop through the in-scope merchants.
    https://pushpay.io/docs/operations/settlements#get__v1_merchant_merchantKey_settlements

    For each merchant you can retrieve the list of batches updated since the last time synchronization was performed (in UTC)

    GET /v1/merchant/{merchantKey}/settlements?updatedFrom=2015-12-11T00:00:00Z&page=0

    The results are paged so you will need to keep fetching pages of settlements until you've read them all.

    GET /v1/merchant/{merchantKey}/settlements?updatedFrom=2015-12-11T00:00:00Z&page=1
    GET /v1/merchant/{merchantKey}/settlements?updatedFrom=2015-12-11T00:00:00Z&page=2

  6. Fetch the payments for a settlement.

    In the details of each settlement is a link to the payments within a settlement ("settlementpayments") - fetching this will retrieve a paged list of payments.

        {
                "key": "MDpkQUFOQ1FzdE1BLVZfVWZFdEZkQ3dvb3YyTDg",
                "name": "Settlement #1",
                "totalAmount": {
                "amount": "202.00",
                "currency": "USD"
                },
                "type": "ACH",
                "totalPayments": 2,
                "estimatedDepositDate": "2016-01-03T07:00:00Z",
                "isReconciled": true,
                "_links": {
                "self": {
                    "href": "https://api.pushpay.com/v1/settlement/MDpkQUFOQ1FzdE1BLVZfVWZFdEZkQ3dvb3YyTDg"
                },
                "settlementpayments": {
                    "href": "https://api.pushpay.com/v1/settlement/MDpkQUFOQ1FzdE1BLVZfVWZFdEZkQ3dvb3YyTDg/payments"
                }
                }
        }
    
    Note! There is an "isReconciled" flag on settlements, but currently this can only be set via the UI, not via the API.

    The payments are paged - you will need to retrieve all pages of payments to be able to see the entire list of payments.

    GET /v1/settlement/{settlementKey}/payments?page=0
    GET /v1/settlement/{settlementKey}/payments?page=1
    GET /v1/settlement/{settlementKey}/payments?page=2

    Note! You can not explicitly order the payments in a settlement, the API will retrieve them in createdOn ascending order (order in which the payments were made).

Webhooks

If your integration needs to synchronize payments constantly, rather then in batches, you can do so by configuring a webhook (either via the Merchant Admin portal, or by using the webhooks API) https://pushpay.io/docs/operations#post__v1_merchant_merchantKey_webhooks. Once the webhook is configured, every time a payment is created or updated, a POST request will be sent to the URI you configured in the webhook. The body of the events are JSON:

{
    "subscription": "http://api.pushpay.com/v1/webhook/token",
    "events": [
    {
        "date": "2015-01-02T03:04:05Z",
        "eventType": "payment_created",
        "entityType": "Payment",
        "links": {
        "merchant": "http://api.pushpay.com/v1/merchant/MTIzOkRUclhHb1Jtc24tX3NKMGxjZzJ3cUJqb1ZlTQ",
        "payment: "/v1/merchant/MTIzOkRUclhHb1Jtc24tX3NKMGxjZzJ3cUJqb1ZlTQ/payment/q235azs3KMGxjZzJ3cUJqb1349s0909"
        }
    }
    ]
}

No sensitive information is included in the webhook event - it will only contain links to the affected items which can be retrieved to find more details.

Warning! Webhook delivery is never guaranteed - and Pushpay currently will not retry sending a webhook event if its delivery fails. As such we always recommend using a combination of webhooks and a periodic check so your integration can eventually recover if it missed a webhook message.

Compensation

A common problem for systems synchronizing payments is how to deal with bank payments which may take up to 7 days to process. Within Pushpay these payments will be immediately visible, and have a status of "Processing". At the point they succeed (or return) the status will then change to "Success" or "Failed".  This could take up to 7 days to happen. In some systems you may already have the concept of a "Processing" payment, in which case the 2 systems will align well. Otherwise, there are 2 options: * Not displaying the payment until it's status has changed to Success. However, this can lead to a lot of user confusion. * Show the payment immediately, but then "handle" the uncommon case of the payment failing, rather then succeeding. We refer to this as compensation - as soon as the payment has a status of processing, treat it as a successful payment in your system. If it later fails, either void the payment in your system- OR - create a second "compensating" payment that has all the same details but a negative amount (so it negates the original payment).  By doing so you provide an experience which is much less confusing to merchant administrators.

Info! If fetching recently updated payments (ORDER by updatedOn ASC/DESC), you will find that this not only includes new payments, but also payments which have changed status - including processing payments which have transitioned from "Processing" to "Success" or "Failed". You may find a payment in a status of "Processing" is updated several times without having it's status change, this is because in Pushpay we are updating the payment as it tracks through the stages of processing in the ACH network.

Sandbox Access

Development is always done against the sandbox environment - Pushpay does not issue production API credentials until it has seen evidence of an integration working against the sandbox environment. Sandbox access can be requested (as well as general support for the API) by sending an email to api@pushpay.com To configure sandbox access we need to know:

  • The name of your organization, or the merchant you are developing the integration for.
  • At least one email address that can be invited as a merchant administrator for the merchant in our sandbox environment.
  • The purpose of your integration (so we can determine what scopes should be allowable for your client).