A versioned partner API for clinics: scoped access, safe retries that never double-book, signed notifications, and ready-made documentation in Postman.
Overview
What this is and why it matters, in plain English.
A versioned partner API for clinics: scoped access, safe retries that never double-book, signed notifications, and ready-made documentation in Postman.
One documented, secure API so outside systems can book appointments and get updates without custom builds.
The situation
What was going on before, and why it needed fixing.
Every new clinic integration was a private endpoint and a Slack thread. Partners could not book or read a schedule without a custom build.
Each new clinic integration was a private endpoint and a Slack thread. Partners could not book or read a schedule without a custom build.
What it needed to do
The outcomes the project had to deliver.
- A public, versioned contract partners can build against.
- Safe booking under retries.
- Webhooks partners can trust.
What I did
My part of the work and who I worked with.
I designed and published /v2: OAuth scopes, the error catalog, rate limits, idempotent booking, webhook signing and rotation, and the Postman collection.
How it works
The main building blocks, from the screen people use to the data underneath.
Published /v2 with scoped OAuth, a written error catalog, rate limits, and a Postman collection that matches the live contract.
- 01
Laravel /v2 routes
Scoped OAuth middleware and partner rate limits on every route.
- 02
Booking with idempotency
A replayed booking request returns the original appointment.
- 03
Webhooks
Signed deliveries that fail closed on signature mismatch, with secret rotation.
- 04
Postman collection
Matches the live contract and serves as partner documentation.
Key choices and trade-offs
Every build involves trade-offs. These are the important ones and what each one cost.
| Decision | Trade-off |
|---|---|
| Ship v2 alongside v1. | Two versions to run for a while, but existing clients keep working. |
| Fail closed on bad signatures. | Misconfigured partners see failures quickly, which is safer than silently accepting. |
Under the hood
Implementation details for technical readers, with a code sample.
- A stable v2 contract.
- Booking replay returns one appointment.
- A Postman collection as partner docs.
Route::prefix('v2')->middleware(['auth:api', 'throttle:partner'])->group(function () {
Route::post('appointments', [AppointmentController::class, 'store'])
->middleware('scope:appointments:write');
Route::get('patients/{patient}/schedule', [ScheduleController::class, 'show'])
->middleware('scope:schedule:read');
});Problems solved
What got in the way, and how each problem was fixed.
- 01
v1 clients still called old paths. v2 had to ship without breaking them.
v1 paths stay routed to their original handlers while v2 lives under its own prefix.
- 02
A replayed booking request had to return the original appointment, not a second one.
Idempotency keys map a replayed request to the appointment it already created.
- 03
Webhook secrets rotated without dropping in-flight deliveries.
Overlapping secret windows during rotation, so in-flight deliveries still verify.
Security, speed and growth
How data is protected, and how the system stays fast as usage grows.
Security
OAuth scopes per capability, rate limiting per partner, and signed webhooks that fail closed.
Speed & growth
Rate limits protect the platform from any single partner, and idempotency removes duplicate work from retries.
Quality and releases
How changes were tested and shipped safely.
Contract tests per version, replay tests for booking, and signature tests across secret rotation.
Tech stack
The tools and technologies used, for recruiters and technical reviewers.
Results
Measured outcomes recorded for this project.
| Metric | Result |
|---|---|
| Contract | v2 stable |
| Booking replay | 1 appointment |
| Partner docs | Postman collection |
Questions
Plain answers first, then the detail a technical reviewer would ask about.
Common questions
- Why does a clinic need a partner API?
- So other companies can book appointments and receive updates through one documented connection, instead of a custom build for each partner.
- What if a partner sends the same booking twice?
- The second request returns the original booking, so nothing is ever double-booked.
For your tech lead
- What happens if a partner retries a booking?
- The same idempotency key returns the original appointment.
- Did v1 clients break?
- No. v1 paths stayed in place while v2 launched.
Key takeaways
- •One documented, secure API so outside systems can book appointments and get updates without custom builds.
- •Built with Laravel, OAuth, REST, MySQL, Postman, Webhooks.