The Planning Center API is genuinely good: REST, JSON:API, documented product by product. Building a warehouse on it is still a real project, because each product is a separate API with its own id space, and the cross-product joins are yours to make.
Key points
- Planning Center’s API reference covers Calendar, Check-Ins, Giving, Groups, People, Publishing, Registrations and Services, each as its own API, with its own versions and resources.
- Auth is either a Personal Access Token for your own organization or OAuth 2.0 with per-product scopes for multi-church apps.
- The documented rate limit is 100 requests per 20 seconds per authenticated user, and 75 per 20 seconds once your offset climbs past 30,000.
- The expensive part of a sync is not reading the API; it is identity across products, incremental updates, deletions, and who maintains it in two years.
- In our experience a first useful pull takes days, and a warehouse you would trust for board reporting takes a quarter.
I spent several years as head of data analytics at a 30,000-member church, and the Planning Center API was the first thing I reached for. Let me be fair to it up front: well-designed, consistent, stable, and included with your account rather than sold back as an integration tier. What follows is the part nobody writes down. That is what the build turns into after the first successful request.
What does the Planning Center API give you?
A REST API that conforms to the JSON:API 1.0 spec, documented product by product.
Coverage. The API reference index covers the eight products: Calendar, Check-Ins, Giving, Groups, People, Publishing, Registrations and Services. Alongside them sit Webhooks and two account-level APIs (api and current) that describe your organization and its OAuth applications rather than any ministry data. Check the reference rather than the developers overview page, which still describes the API as covering six products. Registrations got its public API in June 2025. Coverage is not uniform: some products are read-only, and write support varies.
Authentication. Two doors, documented here. A Personal Access Token is a client id and secret passed with HTTP Basic auth, and it inherits the permissions of the person who created it. That matters more than it sounds like, and I will come back to it. OAuth 2.0 is the route for an application used by more than one organization, with per-product scopes; since March 2023, only Organization Administrators can create OAuth applications.
Querying. The JSON:API overview documents where[attribute]=value filters, comparison operators (gt, gte, lt, lte) for dates, and include for side-loading up to two levels deep. That date operator is the hinge your whole incremental sync hangs on.
Rate limits. Documented as 100 requests per 20 seconds per authenticated user, falling to 75 for requests with an offset above 30,000. Every response carries X-PCO-API-Request-Rate-Limit, -Rate-Period and -Rate-Count headers; going over returns a 429 with Retry-After. Planning Center asks that you never hard-code the values, because they adjust dynamically. Read the headers.
Webhooks. Available, HMAC-signed, retried up to 16 times over roughly 5.4 days, and scoped to what the subscribing user can see.
That is a good API by any standard. Nothing below is a complaint about it.
What does building your own Planning Center sync involve?
Six things, roughly in the order they surprise you.
One API per product
Planning Center is a suite of separate products, and the API mirrors that faithfully. Eight APIs, eight versioning schemes, eight sets of resources. Giving’s current documented version is 2019-10-18, while Check-Ins is on a 2025 one. Your extraction layer is really eight extraction layers, each with its own filters and its own quirks about what can be side-loaded.
Separate id spaces
This is the one that bites. Each product exposes its own Person resource with its own primary key. The Giving reference describes its Person as “a Planning Center Person record that has been added to Giving,” but the documentation nowhere promises that id is interchangeable with the People id, and you should not build as though it is.
What you do get, in places, is an explicit bridge: the Check-Ins API exposes an account_center_person_id for querying check-ins by related person. Use those where they exist and resolve identity deliberately everywhere else. What you must not do is fall back to matching on email or name. Churches have shared family addresses, two Chris Andersons, and a person who married and changed both. That is how you end up with a giving report that quietly double-counts a household.
Incremental sync
The first full pull is the easy one. It is slow, but it is a loop.
The second night is where the design work is. You want where[updated_at][gt]=<last successful run> per resource per product, a durably stored watermark, and a rule for what happens when a run fails halfway. Not every resource gives you the filter. Giving’s Person documents only where[first_name] and where[last_name], so donors need a full sweep while donations get a watermark. And a partially advanced watermark loses records forever, with nothing in your data to tell you it happened. Back-dating the watermark by an overlap window and making writes idempotent is the cheap insurance.
Deletions and history
updated_at filters find changes. They do not find deletions. A refunded donation, a check-in deleted by an admin, a person merged into another person. None of those arrive as an update on the record you hold. You need reconciliation passes that compare id sets, and you need to decide early whether your warehouse keeps history or mirrors current state. Year-over-year questions need the former, and retrofitting history onto a mirror is a rebuild, not a change.
Permissions
A Personal Access Token carries the permissions of whoever created it. Giving is the trap: if that person is not a Giving Administrator, the giving endpoints return only what they can see, possibly very little, and your pipeline records a clean success. Assert record counts against a number a human can verify in the UI, or you will present a giving trend built on one campus.
The parts that are not the API
Retries with jitter that respect Retry-After. Backfills that do not trip the offset-30,000 penalty. Schema drift when Planning Center ships a new version. Alerting when last night’s sync did not finish. Documentation for the next person.
Which joins are worth the trouble?
Once the sync is real, the payoff is the questions no single-product report can reach, the reports Planning Center can’t run. These are the joins I would build first, in order:
| Join | The question it answers | Why it is worth it |
|---|---|---|
| Giving × Check-Ins | Which households still give but stopped attending | Separates financial hardship from quiet exit |
| Services × Check-Ins | Which volunteers came off the rota before they left | Usually the earliest signal in your data |
| Groups × everything | Whether group members attend, give and serve more | Measures what groups ministry actually produces |
| Registrations × Check-Ins | How many event families ever came on a Sunday | Tells you if events connect to the church |
| People × time | Who is still here 6 and 12 months after joining | Retention, not just arrivals |
Every one needs a reliable person key spanning two products. That single key is the whole engineering problem, and it is why “just pull the API” underestimates the work badly. Everything downstream is straightforward once identity is solved and worthless until it is: dashboards, a Sheets export, a giving trend.
How long does this take?
No statistics here, only what we have seen building this repeatedly.
A single-product pull is an afternoon: People into a table, paginated, authenticated. That first success is encouraging, and it is also why these projects get approved.
Two or three products with a nightly incremental run, a stored watermark and basic retries: two to three weeks of an engineer’s part-time attention.
All eight modelled into typed tables with a resolved person key, deletion reconciliation, history and alerting: in our experience, a quarter of someone’s real time. Not calendar time, but the time they actually have after the ministry requests.
Then maintenance, which nobody budgets. A few days a quarter for version changes, new fields, and the night the sync fails silently. Plus a succession problem, because church data pipelines are usually built by one person, and that person eventually moves.
Should you build this or buy it?
Build when your requirements are genuinely unusual, your engineering capacity is not borrowed from someone’s evenings, and you can name the person who owns this in 2029.
| Build on the API | Use a synced warehouse | |
|---|---|---|
| Time to first cross-product query | Weeks to a quarter | Overnight |
| Person key across products | You resolve it | Already resolved |
| Incremental sync, deletes, retries | Yours to own | Handled |
| Rate limits | You babysit them | Not your problem |
| Schema changes | You track versions | Absorbed upstream |
| Ongoing cost | Engineer time, indefinitely | Subscription |
| Unusual requirements | Anything you can code | What the model exposes |
Buying is not obviously right either. If your questions live inside one product, Planning Center’s own reports answer them and a warehouse is overhead. That trade-off is laid out on how we compare to Planning Center itself, and if a spreadsheet is honestly enough, we’ve written that down too.
Where Parable fits
This is the section where I am selling something, so read it that way.
Parable connects over OAuth, reads all eight Planning Center products, and syncs nightly into a modelled warehouse. That is the work described above, done once and maintained by us. The for data teams page has the detail, but the shape matters here: everything lands in one planning_center schema, tables are named <product>_<entity> (giving_donations, groups_memberships, checkins_check_ins), and *_relationships tables carry a relationship_id identifying the same person across every product.
That last part is the id-space problem, solved. It turns the join into ordinary SQL:
SELECT COUNT(DISTINCT gdr.relationship_id)
FROM planning_center.giving_donations gd
JOIN planning_center.giving_donations_relationships gdr ON gd.donation_id = gdr.donation_id
JOIN planning_center.groups_memberships_relationships gmr ON gdr.relationship_id = gmr.relationship_id
WHERE gdr.relationship_type = 'Person';
Two honest caveats. The sync is nightly, so this is a reporting warehouse rather than an operational read replica. A query answers as of last night. And the first run pulls full history rather than a rolling window, which makes year-over-year work immediately but takes a few hours for a large church.
Point Power BI, Tableau, Looker Studio, Metabase or Sheets at it. Direct database access is on the Scale plan and above; pricing is public. Meanwhile the rest of your staff ask in plain English against the same data, through the reporting layer this warehouse sits underneath.
So the decision is narrow. Planning Center stays your system of record either way; you are only choosing who owns the sync. Build it if the ownership is real. Buy it if the pipeline would be one more thing you maintain at 10pm. Either way, insist on what the joins can tell you rather than eight products that each report beautifully on themselves.

