API Reference
Complete reference for the Orita Provider Resolution API. All endpoints are prefixed with https://orita.online. Requests and responses use JSON with UTF-8 encoding.
Authentication
All API requests must include an Authorization header with a Bearer token.
Authorization: Bearer orita_live_...Platform API keys begin with orita_live_ and are created in your dashboard settings.
Test keys begin with orita_test_ and have identical capabilities, but do not send real email notifications or trigger live webhooks.
Keep your API keys secret. Never expose them in client-side code or public repositories. Rotate keys immediately if they are compromised.
Resolution API
/api/v1/resolutionsFind the best available provider slots that match the given constraints. Returns a ranked list of options valid for 5 minutes (300 seconds). Insurance and license region are stored on the provider profile and filterable via GET /professionals, but are not hard constraints in the resolution engine.
TTL: Resolution options expire after 5 minutes. Hold: 2 minutes default, 10 minutes maximum.
Authentication
Authorization: Bearer orita_...Headers
| Header | Value | Required |
|---|---|---|
| Authorization | Bearer orita_... | required |
| Idempotency-Key | <unique-string> | required |
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| serviceId | string | required | Event type ID to match against. |
| constraints.languageCodes | { anyOf: string[] } | optional | ISO 639-1 codes. Provider must match any listed. |
| constraints.modalityCodes | { anyOf: string[] } | optional | Accepted modalities (e.g. ["virtual", "in-person"]). |
| constraints.acceptsNewClients | boolean | optional | Filter to providers accepting new clients. |
| constraints.specialties | { anyOf: string[] } | optional | Provider specialty filter. |
| constraints.profession | string | optional | Provider profession filter. |
| preferences.dayParts | string[] | optional | Time-of-day parts for ranking (e.g. ["morning", "afternoon"]). |
| preferences.earliestAvailable | boolean | optional | Rank earliest available slots first. |
| dateRange.from | string (YYYY-MM-DD) | required | Start of the search window. |
| dateRange.to | string (YYYY-MM-DD) | required | End of the search window. Max 14-day span. |
Request Body
{
"serviceId": "svc_01...",
"constraints": {
"languageCodes": { "anyOf": ["es", "en"] },
"modalityCodes": { "anyOf": ["virtual"] },
"acceptsNewClients": true,
"specialties": { "anyOf": ["therapy", "CBT"] },
"profession": "therapist"
},
"preferences": {
"dayParts": ["afternoon"],
"earliestAvailable": false
},
"dateRange": {
"from": "2026-08-04",
"to": "2026-08-08"
}
}Response 200
{
"resolutionId": "res_01JZBK9m...",
"status": "resolved",
"options": [
{
"optionId": "opt_01JZBK...",
"rank": 1,
"provider": {
"id": "prov_01...",
"name": "Dr. Ana GarcĂa",
"username": "dr-ana-garcia"
},
"service": {
"id": "svc_01...",
"title": "Initial Consultation",
"duration": 50
},
"slot": {
"id": "c2l0ZXx...",
"date": "2026-08-05",
"time": "15:00",
"label": "Tue Aug 5 at 3:00 PM"
},
"modality": "virtual",
"reason": "Matched all hard constraints. Language: Spanish. Afternoon preference matched. Earliest eligible option.",
"reasonCodes": [
"LANGUAGE_MATCH",
"MODALITY_MATCH",
"PREFERENCE_MATCH",
"EARLIEST_ELIGIBLE"
]
}
],
"totalProviders": 20,
"evaluatedSlots": 143,
"expiresAt": "2026-08-04T14:35:00Z"
}Possible Errors
/api/v1/resolutions/:idRetrieve the current state of a resolution, including all ranked options and expiry.
Authentication
Authorization: Bearer orita_...Response 200
{
"resolutionId": "res_01JZBK9m...",
"status": "resolved",
"options": [ ... ],
"totalProviders": 20,
"evaluatedSlots": 143,
"expiresAt": "2026-08-04T14:35:00Z"
}Possible Errors
/api/v1/resolutions/:id/options/:optionId/holdLock a specific option from a resolution while the user confirms. Default TTL is 2 minutes (120 s); maximum is 10 minutes (600 s). Only one hold may be active per resolution at a time.
Authentication
Authorization: Bearer orita_...Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| ttlSeconds | number | optional | Hold duration in seconds. Default 120, max 600. |
Request Body
{
"ttlSeconds": 120
}Response 200
{
"holdId": "hold_01JZBK...",
"status": "active",
"expiresAt": "2026-08-04T14:47:00Z"
}Possible Errors
/api/v1/resolutions/:id/confirmConfirm an option from a resolution and create a booking. A prior hold is optional but recommended to prevent race conditions. Returns the final booking record.
Authentication
Authorization: Bearer orita_...Headers
| Header | Value | Required |
|---|---|---|
| Authorization | Bearer orita_... | required |
| Idempotency-Key | <unique-string> | required |
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| optionId | string | required | The option ID from the resolution to confirm. |
| customer.name | string | required | Customer full name. |
| customer.email | string | required | Customer email address. |
| customer.lastname | string | optional | Customer last name (optional). |
| metadata | object | optional | Arbitrary key-value data to attach to the booking. |
Request Body
{
"optionId": "opt_01JZBK...",
"customer": {
"name": "Juan",
"email": "juan@example.com",
"lastname": "RodrĂguez"
},
"metadata": {
"source": "widget",
"campaignId": "summer-2026"
}
}Response 200
{
"bookingId": "bk_01JZBK...",
"status": "confirmed",
"provider": {
"id": "prov_01...",
"name": "Dr. Ana GarcĂa"
},
"service": {
"title": "Initial Consultation",
"duration": 50
},
"start": "2026-08-05T15:00:00Z",
"end": "2026-08-05T15:50:00Z",
"confirmationUrl": "https://orita.online/b/bk_01JZBK..."
}Possible Errors
Provider Graph
/api/v1/professionalsCreate a new professional profile in your provider graph. Requires a platform-level API key.
Authentication
Authorization: Bearer orita_... (platform key)Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | required | Full display name. |
| string | required | Provider email address. | |
| profession | string | required | e.g. 'therapist', 'dentist'. |
| specialty | string[] | optional | List of specialty tags. |
| languages | string[] | optional | ISO 639-1 language codes. |
| modality | "virtual" | "in-person" | "both" | optional | Session modality. |
| location | string | optional | Human-readable location. |
| timezone | string | required | IANA timezone (e.g. 'Europe/Madrid'). |
| insurance | string[] | optional | Accepted insurance plans. |
| bio | string | optional | Short professional bio. |
Request Body
{
"name": "Dr. Ana GarcĂa",
"email": "ana@example.com",
"profession": "therapist",
"specialty": ["therapy", "CBT"],
"languages": ["es", "en"],
"modality": "virtual",
"location": "Madrid, Spain",
"timezone": "Europe/Madrid",
"insurance": ["sanitas", "adeslas"],
"bio": "Licensed therapist specializing in anxiety and depression."
}Response 200
{
"id": "prov_01...",
"username": "dr-ana-garcia",
"name": "Dr. Ana GarcĂa",
"email": "ana@example.com",
"bookingUrl": "https://orita.online/dr-ana-garcia",
"status": "active"
}Possible Errors
/api/v1/professionalsList professionals in your provider graph. Supports filtering by specialty, language, profession, location, and modality.
Authentication
Authorization: Bearer orita_...Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| specialty | string | optional | Filter by specialty tag. |
| language | string | optional | ISO 639-1 code. |
| profession | string | optional | Filter by profession. |
| location | string | optional | Filter by location string. |
| modality | "virtual" | "in-person" | "both" | optional | Filter by modality. |
Response 200
{
"professionals": [
{
"id": "prov_01...",
"name": "Dr. Ana GarcĂa",
"username": "dr-ana-garcia",
"profession": "therapist",
"specialty": ["therapy", "CBT"],
"modality": "virtual"
}
],
"total": 20
}Possible Errors
/api/v1/event-typesCreate a service or session type for a provider. Defines the booking unit used during resolution.
Authentication
Authorization: Bearer orita_...Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| providerId | string | required | The provider this event type belongs to. |
| title | string | required | Display name of the event type. |
| duration | number | required | Duration in minutes. |
| price | number | optional | Price in smallest currency unit. |
| currency | string | optional | ISO 4217 currency code (e.g. 'EUR'). |
| modality | "virtual" | "in-person" | "both" | optional | Session modality override. |
Request Body
{
"providerId": "prov_01...",
"title": "Initial Consultation",
"duration": 50,
"price": 80,
"currency": "EUR",
"modality": "virtual"
}Response 200
{
"id": "svc_01...",
"providerId": "prov_01...",
"title": "Initial Consultation",
"duration": 50,
"price": 80,
"currency": "EUR",
"modality": "virtual",
"slug": "initial-consultation"
}Possible Errors
/api/v1/availabilityDefine a recurring availability schedule for a provider. The schedule is used by the resolution engine to find bookable slots.
Authentication
Authorization: Bearer orita_...Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| providerId | string | required | Provider to assign this schedule to. |
| title | string | optional | Human-readable label for this schedule. |
| timezone | string | required | IANA timezone for all times in this schedule. |
| days | object | required | Per-day config: { enabled: boolean, slots: [{ start, end }] } |
Request Body
{
"providerId": "prov_01...",
"title": "Default",
"timezone": "Europe/Madrid",
"days": {
"monday": {
"enabled": true,
"slots": [{ "start": "09:00", "end": "17:00" }]
},
"tuesday": {
"enabled": true,
"slots": [{ "start": "09:00", "end": "17:00" }]
},
"wednesday": { "enabled": false, "slots": [] },
"thursday": {
"enabled": true,
"slots": [{ "start": "10:00", "end": "18:00" }]
},
"friday": {
"enabled": true,
"slots": [{ "start": "09:00", "end": "14:00" }]
},
"saturday": { "enabled": false, "slots": [] },
"sunday": { "enabled": false, "slots": [] }
}
}Response 200
{
"id": "avail_01...",
"providerId": "prov_01...",
"title": "Default",
"timezone": "Europe/Madrid",
"status": "active"
}Possible Errors
Booking Lifecycle
/api/v1/bookingsCreate a booking directly when the provider and slot are already known, bypassing resolution.
The booking is created with status âpendingâ. The client receives a confirmation email with a link. Status transitions to âConfirmadaâ after the client clicks the link. Listen for the booking.confirmed webhook event to detect this transition.
Authentication
Authorization: Bearer orita_...Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| providerId | string | required | Provider to book with. |
| serviceId | string | required | Event type / service. |
| slotId | string | required | Slot ID from availability. |
| attendee | object | required | { name, email, timezone } |
| notes | string | optional | Optional notes from the attendee. |
Request Body
{
"providerId": "prov_01...",
"serviceId": "svc_01...",
"slotId": "c2l0ZXx...",
"attendee": {
"name": "Juan RodrĂguez",
"email": "juan@example.com",
"timezone": "America/New_York"
},
"notes": "First session"
}Response 200
{
"data": {
"id": "bk_01JZBK...",
"status": "pending",
"title": "Therapy Session",
"date": "2026-08-05T15:00:00.000Z",
"end_time": "2026-08-05T16:00:00.000Z",
"tokenToConfirm": "ecc4deb7aa22e7e85b...",
"resolutionId": "res_7812"
}
}Possible Errors
/api/v1/bookingsList all bookings. Paginated. Optionally filter by status.
Authentication
Authorization: Bearer orita_...Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| page | number | optional | Page number (default 1). |
| limit | number | optional | Results per page (default 20). |
| status | "confirmed" | "cancelled" | "completed" | "rescheduled" | optional | Filter by booking status. |
Response 200
{
"bookings": [
{
"bookingId": "bk_01JZBK...",
"status": "confirmed",
"provider": { "name": "Dr. Ana GarcĂa" },
"start": "2026-08-05T15:00:00Z",
"end": "2026-08-05T15:50:00Z"
}
],
"total": 42,
"page": 1,
"limit": 20
}Possible Errors
/api/v1/bookings/:idRetrieve full details of a single booking by ID.
Authentication
Authorization: Bearer orita_...Response 200
{
"bookingId": "bk_01JZBK...",
"status": "confirmed",
"provider": {
"id": "prov_01...",
"name": "Dr. Ana GarcĂa",
"username": "dr-ana-garcia"
},
"service": {
"title": "Initial Consultation",
"duration": 50
},
"attendee": {
"name": "Juan RodrĂguez",
"email": "juan@example.com"
},
"start": "2026-08-05T15:00:00Z",
"end": "2026-08-05T15:50:00Z",
"confirmationUrl": "https://orita.online/b/bk_01JZBK..."
}Possible Errors
/api/v1/bookings/:id/rescheduleMove an existing booking to a new date and time. Cancels the original booking and creates a new one with the same provider, event type, and client.
Production requires separate date (YYYY-MM-DD) and time (HH:MM) fields â not a single ISO datetime. The new booking starts in âpendingâ status until confirmed by the client.
Authentication
Authorization: Bearer orita_...Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| date | string | required | New date in YYYY-MM-DD format (e.g. "2026-08-06"). |
| time | string | required | New time in HH:MM format in the providerâs timezone (e.g. "15:00"). |
| notes | string | optional | Optional notes to attach to the rescheduled booking. |
Request Body
{
"date": "2026-08-06",
"time": "15:00",
"notes": "Client requested afternoon slot"
}Response 200
{
"data": {
"id": "bk_01JZBK...",
"status": "pending",
"title": "Therapy Session",
"date": "2026-08-06T19:00:00.000Z",
"end_time": "2026-08-06T20:00:00.000Z"
}
}Possible Errors
/api/v1/bookings/:id/cancelCancel an existing booking. Triggers a booking.cancelled webhook event.
Authentication
Authorization: Bearer orita_...Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| reason | string | optional | Optional cancellation reason. |
Request Body
{
"reason": "Patient no longer needs appointment"
}Response 200
{
"bookingId": "bk_01JZBK...",
"status": "cancelled",
"cancelledAt": "2026-08-04T09:00:00Z"
}Possible Errors
Direct Scheduling
/api/v1/slotsRetrieve available time slots for a specific provider and event type on a given date. Use this endpoint when you already know which provider and service you want to book, bypassing the resolution engine.
Authentication
Authorization: Bearer orita_...Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| providerId | string | required | Provider ID to fetch slots for. |
| eventTypeId | string | required | Event type (service) ID. |
| date | string (YYYY-MM-DD) | required | Date to fetch available slots for. |
Response 200
{
"slots": [
{
"id": "c2l0ZXx...",
"date": "2026-08-05",
"time": "09:00",
"label": "Tue Aug 5 at 9:00 AM",
"available": true
},
{
"id": "c2l0ZXy...",
"date": "2026-08-05",
"time": "10:00",
"label": "Tue Aug 5 at 10:00 AM",
"available": true
}
],
"total": 8
}Possible Errors
Operations
/api/v1/webhooksRetrieve your current webhook configuration.
Authentication
Authorization: Bearer orita_...Response 200
{
"url": "https://yourapp.com/webhooks/orita",
"events": ["booking.created", "booking.cancelled"],
"active": true,
"createdAt": "2026-01-01T00:00:00Z"
}Possible Errors
/api/v1/webhooksUpdate your webhook URL and the list of events to receive.
Authentication
Authorization: Bearer orita_...Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| url | string | required | HTTPS endpoint that will receive webhook POSTs. |
| events | string[] | required | List of event names to subscribe to. |
Request Body
{
"url": "https://yourapp.com/webhooks/orita",
"events": [
"booking.created",
"booking.cancelled",
"booking.rescheduled",
"resolution.resolved"
]
}Response 200
{
"url": "https://yourapp.com/webhooks/orita",
"events": ["booking.created", "booking.cancelled", "booking.rescheduled", "resolution.resolved"],
"active": true
}Possible Errors
/api/v1/webhooksSend a test event to your configured webhook URL to verify delivery.
Authentication
Authorization: Bearer orita_...Request Body
// No body required â sends a test ping eventResponse 200
{
"delivered": true,
"statusCode": 200,
"latencyMs": 142
}Possible Errors
/api/v1/webhooks/deliveriesList recent webhook delivery attempts with HTTP status codes and latency.
Authentication
Authorization: Bearer orita_...Response 200
{
"deliveries": [
{
"id": "del_01...",
"event": "booking.created",
"statusCode": 200,
"latencyMs": 132,
"timestamp": "2026-08-05T15:01:00Z",
"success": true
},
{
"id": "del_02...",
"event": "booking.cancelled",
"statusCode": 503,
"latencyMs": 5000,
"timestamp": "2026-08-04T10:00:00Z",
"success": false
}
],
"total": 48
}Possible Errors
/api/v1/webhooks/deliveries/:id/replayReplay a specific webhook delivery attempt. Useful for recovering from failures without waiting for the automatic retry schedule. Requires the Launch plan or higher.
Authentication
Authorization: Bearer orita_... (Launch plan or higher)Request Body
// No body required â pass the delivery ID in the URL pathResponse 200
{
"delivered": true,
"statusCode": 200,
"latencyMs": 118,
"replayedAt": "2026-08-05T16:00:00Z"
}Possible Errors
/api/v1/analyticsRetrieve resolution and booking metrics for your account.
Authentication
Authorization: Bearer orita_...Response 200
{
"resolutions": {
"total": 1240,
"resolved": 1185,
"zeroResults": 55,
"avgEvaluatedSlots": 121
},
"bookings": {
"total": 980,
"confirmed": 930,
"cancelled": 40,
"rescheduled": 10
},
"conversionRate": 0.79,
"period": "last_30_days"
}Possible Errors
Webhook Events
Orita POSTs a signed JSON payload to your configured webhook URL whenever one of the following events occurs.
| Event | Description |
|---|---|
| booking.created | A new booking was confirmed. |
| booking.cancelled | A booking was cancelled. |
| booking.rescheduled | A booking was moved to a new slot. |
| booking.completed | A booking time has passed and it is marked completed. |
| resolution.resolved | A resolution found at least one matching option. |
| resolution.zero_results | A resolution returned no matching options. |
| option.held | An option within a resolution was held. |
| professional.updated | A professional profile was modified. |
Payload Shape
{
"type": "booking.created",
"timestamp": "2026-08-05T15:00:00Z",
"data": { ... }
}Signature Verification
Every webhook request includes an X-Orita-Signature header. Its value is sha256=<hex>, where the hex string is an HMAC-SHA256 of the raw request body signed with your webhook secret.
// Node.js verification example
import crypto from "crypto";
function verifySignature(rawBody: string, signature: string, secret: string) {
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}Webhook delivery is retried up to 5 times with exponential backoff when your endpoint returns a non-2xx status. Check GET /api/v1/webhooks/deliveries for delivery history.
Error Codes
All errors return a JSON body with an error object. Check the code and message fields for machine-readable and human-readable details.
{
"error": {
"code": "INVALID_DATE_RANGE",
"message": "dateRange.to must be after dateRange.from and within 14 days.",
"status": 400
}
}| Status | Name | Meaning |
|---|---|---|
| 400 | Bad Request | Missing or invalid request parameters. Check the errors array in the response body. |
| 401 | Unauthorized | API key is missing, malformed, or revoked. |
| 404 | Not Found | The requested resource does not exist. |
| 409 | Conflict | State conflict â e.g. slot already taken, idempotency key reused. |
| 410 | Gone | The resource existed but has expired (e.g. a resolution past its expiry). |
| 422 | Unprocessable Entity | Request is syntactically valid but semantically incorrect. |
| 429 | Too Many Requests | Rate limit exceeded. Retry after the Retry-After header value (seconds). |
| 500 | Internal Server Error | Unexpected server error. Contact support if this persists. |
