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
| Term | Definition |
|---|---|
| Organization | The organization using Pushpay to provide a payment solution. An organization has one or more merchant listings. |
| Merchant listing | A 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 Field | Custom 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. |
| Fund | The fund a payment is associated with. Funds have a label and value, similar to drop-down reference fields. |
| Public API | The API made available to third-party integrations. Documented at docs.pushpay.io/giving-v1/reference. |
| Community Member | The 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 ID | The "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. |
| Settlement | Also 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_idandclient_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
- Code Flow: docs.pushpay.io/giving-v1/docs/code-flow
- Client Flow: docs.pushpay.io/giving-v1/docs/client-flow
Both flows require the following scopes to synchronize payments:
read
merchant:view_payments
merchant:view_recurring_payments
list_my_merchants2. 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
keyandname— 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:
updatedFromupdatedTo
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"
...
}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
- Code Flow: docs.pushpay.io/giving-v1/docs/code-flow
- Client Flow: docs.pushpay.io/giving-v1/docs/client-flow
Both flows require the following scopes to synchronize payments:
read
merchant:view_payments
merchant:view_recurring_payments
list_my_merchants2. 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
Fetch the settlements updated since your code last checked.
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"
}
}
}Settlements have an
isReconciledflag, 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
You cannot explicitly order the payments in a settlement — the API returns them in ascending
createdOnorder (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.
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:
-
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.
-
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.
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
Updated 25 days ago
