Payments Synchronization

Guide to synchronizing payments and settlement batches using the Pushpay API.

Payments Synchronization Guidance

Overview

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


Glossary

TermDefinition
OrganizationThe organization using Pushpay to provide a payment solution. An organization has one or more merchant listings.
Merchant listingA single giving page or listing in the mobile app. Payments are always linked to a single listing. Sometimes referred to simply as "Merchant" or "Listing."
Reference FieldCustom fields belonging to each listing; payments made for a listing can include these fields. There are three types: Text box, Number field, and Drop down list (single-select — a merchant may only have one drop-down field). A drop-down field has both a label and a value; the value can represent the internal ID for a Fund in a third-party system. Fields are owned by the listing and cannot be shared across multiple listings.
FundThe fund a payment is associated with. Funds have a label and value, similar to drop-down reference fields.
Public APIThe API made available to third-party integrations. Documented at docs.pushpay.io/giving-v1/reference.
Community MemberThe individual linked to a payment made to a merchant listing. Community members have a name, email address, a type (Pending or Registered), and an Export Key ("Your ID").
Your IDThe "external system" identifier for a community member — often called an "envelope number," "person ID," or "community member ID" depending on the church management system in use. In the UI and file exports this is called "Your ID"; in the public API it's called ExportKey.
SettlementAlso called "Deposit" or "Batch/Settlement Batch" — a batch of transactions (credit card or ACH) paid into the merchant's bank account as one or more deposits. Settlements aid reconciliation of deposits to payments, splitting the deposited amount across the chart of accounts based on the Fund each payment was attributed to.

Authentication

Authentication uses OAuth2 (Client Flow or Code Flow), as documented in our API security docs.

  • If you're building a B2B integration, you must use Code Flow.
  • client_id and client_secret, as well as the API URL, should be configurable in your integration.
  • Pushpay issues separate credentials for sandbox and production.
  • The sandbox environment uses a different API URL than production.
  • Access tokens last 1 hour; refresh tokens have unlimited lifetime and must be stored securely.
  • If you're a single entity building a bespoke integration that won't serve more than one organization, you can use Client Flow instead.

Rate Limiting

For guidance on handling rate limiting, see the Rate Limiting Guidance.


Process: Payment Import

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

1. Authenticate

Both flows require the following scopes to synchronize payments:

read
merchant:view_payments
merchant:view_recurring_payments
list_my_merchants

2. Retrieve the list of in-scope organizations

GET /v1/organizations/in-scope

Returns the list of organizations your code can retrieve payments for.

3. Retrieve the merchant listings for each organization

GET /v1/organization/{organizationKey}/merchantlistings

Returns the list of merchant listings for the specified organization. For each listing:

  • Store the key and name — the key identifies the listing a payment was made against.
  • If you plan to use pre-configured Giving links, 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 payments at the organization level

Fetching payments at the organization level requires fewer calls, since you get all payments across all merchant listings at once, rather than making one call per listing.

GET /v1/organization/{organizationKey}/payments

We recommend using the following query parameters:

  • updatedFrom
  • updatedTo

Choose a polling frequency (e.g., every hour, on the hour), and build in an overlap window to avoid missing payments. For example, at 2:00 PM, request the previous hour plus 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

Continue polling the API every hour, moving the window forward by one hour each time — always keeping the 10-minute overlap.

5. Identify the donor

GET /v1/organization/{organizationKey}/payments

In the payment response, find the payer object — its key is the "Pushpay account key":

"payer": {
  "key": "MDoxWWpVN2dpTjNzeDdfMTdCcXk1bnZjOUJ5Qzg",
  "emailAddress": "[email protected]",
  "mobileNumber": "+15555555555",
  "fullName": "Joe Bloggs"
  ...
}
info

Depending on your integration's goals, you may also want to synchronize recurring payments — see getorganizationrecurring. For financial system integrations, merchant settlements are also available via the API: getmerchantsettlements.


Process: Settlement Batch Import

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

1. Authenticate

Both flows require the following scopes to synchronize payments:

read
merchant:view_payments
merchant:view_recurring_payments
list_my_merchants

2. Retrieve the list of in-scope organizations

GET /v1/organizations/in-scope

Returns the list of organizations your code can retrieve payments for.

3. Retrieve the merchant listings for each organization

GET /v1/organization/{organizationKey}/merchantlistings

Returns the list of merchant listings for the specified organization.

4. Fetch recent settlements

GET /v1/settlements

Fetch the settlements updated since your code last checked.

info

There is no merchant key in this URL — a single settlement can cover payments made to multiple listings, depending on whether those listings are configured to remit funds into the same bank account.

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

Results are paged, so keep fetching pages until you've retrieved 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 settlement results includes _links for the next page, if one exists — using these links can simplify paging through the 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"
  }
}

Alternative approach: if it makes more sense for your integration, you can instead loop through individual merchant listings and retrieve settlements per listing (similar to the payment import process described earlier).

GET /v1/merchant/{merchantKey}/settlements

For each merchant, retrieve the batches updated since the last synchronization (in UTC):

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

Results are paged, so keep fetching pages until you've retrieved 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

5. Fetch the payments for a settlement

Each settlement's details include a settlementpayments link to the payments within that settlement — fetching it returns 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"
    }
  }
}
info

Settlements have an isReconciled flag, but currently this can only be set via the UI, not the API.

Payments are also paged — retrieve all pages to see the full list:

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

You cannot explicitly order the payments in a settlement — the API returns them in ascending createdOn order (the order in which payments were made).


Webhooks

If your integration needs to synchronize payments continuously, rather than in batches, configure a webhook — either via the Merchant Admin portal, or using the webhooks API. Once configured, every time a payment is created or updated, a POST request is sent to your configured URI. The event body is 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/MTIzOkRUclhHb1Jtc24tX3NKMGxjZzJ3cUJqb1349s0909"
      }
    }
  ]
}

No sensitive information is included in webhook events — only links to the affected items, which can be retrieved for more detail.

exclamation-triangle

Webhook delivery is never guaranteed, and Pushpay currently does not retry failed webhook deliveries. We recommend combining webhooks with a periodic polling check, so your integration can recover if it ever misses a webhook message.


Compensation

A common challenge when synchronizing payments is handling bank payments, which can take up to 7 days to process. In Pushpay, these payments are immediately visible with a status of "Processing." Once the payment succeeds or is returned, the status changes to "Success" or "Failed" — a transition that can take up to 7 days.

If your system already has a concept of a "Processing" payment, the two systems will align well. Otherwise, you have two options:

  1. Wait to display the payment until its status changes to "Success." This can lead to user confusion, since the payment won't appear right away.

  2. Show the payment immediately, and handle the less common case of failure after the fact — a pattern we call compensation. As soon as a payment reaches "Processing," treat it as successful in your system. If it later fails, either:

    • Void the payment in your system, or
    • Create a second "compensating" payment with the same details but a negative amount (offsetting the original).

    This approach provides a much less confusing experience for merchant administrators.

info

When fetching recently updated payments (ordered by updatedOn, ascending or descending), you'll see not only new payments but also payments that changed status — including ones that transitioned from "Processing" to "Success" or "Failed." A payment may show as "Processing" across several updates without changing status, since Pushpay updates the record as it moves through each stage of ACH network processing.


Sandbox Access

Development should always be done against the sandbox environment — Pushpay does not issue production API credentials until it has seen evidence of an integration working in sandbox. Request sandbox access (or general API support) by emailing [email protected]. To configure sandbox access, we'll need to know:

  • The name of your organization, or the merchant you're 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 allowed for your client

Did this page help you?