Endpoints
GET
/api/partner/v1/catalogPublished services and allowed locations. Use bounded limit/cursor paging.
catalog.readGET
/api/partner/v1/catalog/specialistsPublished specialists narrowed by supported service/location filters.
catalog.readGET
/api/partner/v1/availabilityBounded free slots after current lead, schedule and capacity rules.
availability.readPOST
/api/partner/v1/bookingsGuest booking with contact consent, external_reference and Idempotency-Key.
booking.createGET
/api/partner/v1/bookings/{pbr_reference}Application-owned booking projection and current management version.
booking.managePOST
/api/partner/v1/bookings/{pbr_reference}/actions/{cancel|reschedule}Versioned idempotent lifecycle change under current booking rules.
booking.manageAuthorization, envelopes and request tracing
http
GET /api/partner/v1/catalog?locale=en&limit=2 HTTP/1.1
Authorization: Bearer fnx_test_example_key_not_a_real_credential
Accept-Language: en
Origin: https://partner.example
HTTP/1.1 200 OK
Cache-Control: private, no-store
Referrer-Policy: no-referrer
X-Request-Id: <request_id>
X-RateLimit-Limit: <limit>
X-RateLimit-Remaining: <remaining>
X-RateLimit-Reset: <unix_seconds>
{
"data": { "services": [], "next_cursor": null },
"meta": { "request_id": "<request_id>", "version": "v1" }
}Scope and credential policy
| Scope | Routes | Boundary |
|---|---|---|
| catalog.read | Catalog and specialists | Only current published data allowed by the credential location policy. |
| availability.read | Availability | Only bounded available slots under current booking, capacity and lead-time rules. |
| booking.create | Create booking | Explicit customer consent, external_reference and Idempotency-Key are required. |
| booking.manage | Booking read and actions | Only an application-owned pbr_ reference; actions also require expected_version. |
| webhooks.manage | Owner Control Center | Webhook configuration is managed in the protected owner workspace, not by a public API route. |
Create booking
http
POST /api/partner/v1/bookings HTTP/1.1
Authorization: Bearer fnx_test_example_key_not_a_real_credential
Idempotency-Key: 7b1d9ed1-7f34-4ddf-9e01-example
Content-Type: application/json
{
"service_id": "<published_service_id>",
"location_id": "<optional_allowed_location_id>",
"date": "2026-09-21",
"start_time": "10:00",
"external_reference": "partner-order-1042",
"customer": {
"name": "Test customer",
"phone": "+15550001111",
"consent_to_contact": true
}
}Current booking shape
- Partner API v1 creates one service per booking. The documented service_id field is singular; sending an invented service_ids or composition_mode field is rejected.
- Composite sequential or parallel service booking is available through the signed Feny widget and first-party booking flow, where the canonical booking engine validates combinations, staff capacity and current business rules.
- Do not expose a Partner API credential in browser code. Use the public widget id and version for browser embeds, and keep Partner API calls on a trusted server.
Pagination and bounded reads
http
GET /api/partner/v1/catalog?locale=en&limit=25&cursor=<next_cursor> HTTP/1.1
Authorization: Bearer fnx_test_example_key_not_a_real_credential
{
"data": {
"services": ["..."],
"next_cursor": "<opaque_cursor_or_null>"
},
"meta": { "request_id": "<request_id>", "version": "v1" }
}Pagination rules
- Catalog and specialist reads accept limit from 1 to 50 (default 25). Availability accepts limit from 1 to 96 (default 48).
- Pass next_cursor exactly as returned. It is opaque and must not be decoded, constructed, shared across unrelated queries or used after changing filters.
- Availability next_cursor represents the last returned slot start time for that exact availability query. A null next_cursor means there is no next page.
- Availability is a current read, not a reservation. Re-read and let the create-booking request perform the final server-side capacity check.
Idempotent booking actions
http
POST /api/partner/v1/bookings/<pbr_reference>/actions/cancel HTTP/1.1
Authorization: Bearer fnx_test_example_key_not_a_real_credential
Idempotency-Key: 11111111-2222-4333-8444-example
Content-Type: application/json
{ "expected_version": 3 }Idempotency and version policy
- Use one 16-128 character Idempotency-Key for one logical write. Repeat the exact request after an uncertain result to obtain the safe replay; use a new key for a new operation.
- Never reuse an idempotency key with changed input. The API returns 409 idempotency_key_reused rather than guessing which request is authoritative.
- Retrieve a managed booking before cancel or reschedule, then send its latest management version as expected_version. A stale version can return a 409 booking_version_conflict.
- Do not encode customer data, credentials or other sensitive values in Idempotency-Key or external_reference.
Errors and retries
| Condition | Response | Partner action |
|---|---|---|
| Invalid or expired key | 401 invalid_api_key | Rotate or select the correct environment; do not retry with another tenant selector. |
| Missing scope or credential restriction | 403 insufficient_scope / credential_restricted | Change the application policy in the owner Control Center. |
| Invalid request or unavailable booking | 400 invalid_request / 409 booking_unavailable | Correct the input or retrieve current availability; keep the original idempotency key only for the same logical write. |
| Missing record | 404 not_found | Do not infer tenant state or retry with a different tenant selector. |
| Quota response | 429 rate_limited | Respect Retry-After and rate-limit headers. Retry only after the stated window with bounded backoff. |
| Temporary service response | 503 service_unavailable | Use bounded exponential backoff with jitter; preserve the same idempotency key only for the same write. |
| Reused idempotency key with changed input | 409 idempotency_key_reused | Create a new logical operation and key; never mutate a replay request. |
Feny