{"info":{"name":"Orita Provider Resolution API v2","_postman_id":"orita-provider-resolution-v1","description":"Provider Resolution API v2 — resolve, hold, confirm. Import this collection and set {{baseUrl}} to https://orita.online","schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json","version":{"major":1,"minor":0,"patch":0}},"variable":[{"key":"baseUrl","value":"https://orita.online","type":"string"},{"key":"apiKey","value":"orita_your_key_here","type":"string"},{"key":"resolutionId","value":"","type":"string"},{"key":"optionId","value":"","type":"string"},{"key":"bookingId","value":"","type":"string"},{"key":"professionalId","value":"","type":"string"}],"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{apiKey}}","type":"string"}]},"item":[{"name":"0. Connection","item":[{"name":"Test connection","event":[{"listen":"test","script":{"exec":["pm.test('Connected', () => pm.response.to.have.status(200));","const data = pm.response.json();","const count = (data.professionals || data.data || []).length;","pm.test('Returns professionals', () => pm.expect(count).to.be.gte(0));","console.log('✓ Connected. Professionals visible:', count);"],"type":"text/javascript"}}],"request":{"method":"GET","url":"{{baseUrl}}/api/v2/providers?limit=1","description":"Verify your API key is valid. Returns 200 with your professional list."}}]},{"name":"1. Provider Graph","item":[{"name":"Seed sample providers","event":[{"listen":"test","script":{"exec":["pm.test('Provider created', () => pm.response.to.have.status(201));","const id = pm.response.json().id;","if (id) pm.collectionVariables.set('professionalId', id);","console.log('Created provider:', id);"],"type":"text/javascript"}}],"request":{"method":"POST","url":"{{baseUrl}}/api/v2/providers","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"seed_dr_garcia_{{$timestamp}}"}],"body":{"mode":"raw","raw":"{\n  \"name\": \"Dr. Ana García\",\n  \"email\": \"ana.garcia@orita-sample.test\",\n  \"languageCodes\": [\"es\", \"en\"],\n  \"modalityCodes\": [\"virtual\"],\n  \"specialtyIds\": [\"anxiety\", \"cbt\"],\n  \"acceptsNewClients\": true,\n  \"timezone\": \"America/New_York\"\n}"},"description":"Create a sample professional. The provider receives a confirmation email and sets up availability through their dashboard.\n\n**Note:** `name` and `email` are required. The professional is a real account."}},{"name":"List professionals","event":[{"listen":"test","script":{"exec":["pm.test('Returns 200', () => pm.response.to.have.status(200));","const d = pm.response.json();","const list = d.professionals || d.data || [];","pm.test('Has professionals', () => pm.expect(list.length).to.be.gte(0));","console.log('Professionals in network:', list.length);"],"type":"text/javascript"}}],"request":{"method":"GET","url":{"raw":"{{baseUrl}}/api/v2/providers","query":[{"key":"language","value":"es","disabled":true,"description":"Filter by language code"},{"key":"modality","value":"virtual","disabled":true,"description":"Filter by modality"},{"key":"specialty","value":"anxiety","disabled":true,"description":"Filter by specialty"}]},"description":"List all professionals in your provider network. Supports filtering by language, modality, and specialty."}}]},{"name":"2. Provider Resolution (unknown provider)","description":"Use when you know the customer need but not which provider should handle it.\n\nFlow: resolveScheduling → holdOption (optional) → confirmResolution\n\n⚠️ Creating a resolution does NOT create a booking.","item":[{"name":"Create resolution","event":[{"listen":"test","script":{"exec":["pm.test('Status 200', () => pm.response.to.have.status(200));","const d = pm.response.json();","pm.test('Has resolutionId', () => pm.expect(d.resolutionId).to.exist);","pm.collectionVariables.set('resolutionId', d.resolutionId);","const opts = d.options || [];","if (opts.length > 0) {","  pm.collectionVariables.set('optionId', opts[0].optionId);","  console.log('Top option:', opts[0].provider?.displayName, '- Score:', opts[0].score);","}","console.log('Resolution:', d.resolutionId, '| Status:', d.status);","console.log('Summary:', JSON.stringify(d.summary));","if (d.exclusions) console.log('Exclusions:', JSON.stringify(d.exclusions));"],"type":"text/javascript"}}],"request":{"method":"POST","url":"{{baseUrl}}/api/v2/resolutions","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"resolution_postman_{{$timestamp}}"}],"body":{"mode":"raw","raw":"{\n  \"serviceId\": \"svc_therapy\",\n  \"dateRange\": {\n    \"from\": \"{{$isoTimestamp}}\",\n    \"to\": \"2026-08-30\",\n    \"timezone\": \"America/New_York\"\n  },\n  \"constraints\": {\n    \"languageCodes\": { \"anyOf\": [\"es\"] },\n    \"modalityCodes\": { \"anyOf\": [\"virtual\"] },\n    \"acceptsNewClients\": true\n  },\n  \"preferences\": {\n    \"dayParts\": [\"afternoon\"],\n    \"earliestAvailable\": true\n  },\n  \"limit\": 5\n}"},"description":"Search your provider network and return ranked, explained provider-time options.\n\n**Hard constraints** (fail closed if no match):\n- `languageCodes` — provider must speak the language\n- `modalityCodes` — provider must support the modality\n- `acceptsNewClients` — provider must be accepting\n\n**Preferences** (affect ranking only, never exclude):\n- `dayParts` — preferred time of day\n- `earliestAvailable` — prefer sooner slots\n\n**Returns:** `resolutionId`, `options[]` with scores and reasons, `exclusions` map, `expiresAt` (5 min TTL)"}},{"name":"Get resolution","event":[{"listen":"test","script":{"exec":["pm.test('Status 200', () => pm.response.to.have.status(200));","const d = pm.response.json();","console.log('Status:', d.status, '| Expires:', d.expiresAt);","console.log('Options:', (d.options||[]).length);"],"type":"text/javascript"}}],"request":{"method":"GET","url":"{{baseUrl}}/api/v2/resolutions/{{resolutionId}}","description":"Retrieve a stored resolution with all ranked options, exclusion reasons, and expiration status."}},{"name":"Hold option (2 min)","event":[{"listen":"test","script":{"exec":["pm.test('Status 200', () => pm.response.to.have.status(200));","const d = pm.response.json();","console.log('Hold:', d.holdId, '| Expires:', d.expiresAt);","pm.test('Hold is active', () => pm.expect(d.status).to.equal('active'));"],"type":"text/javascript"}}],"request":{"method":"POST","url":"{{baseUrl}}/api/v2/resolutions/{{resolutionId}}/options/{{optionId}}/hold","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"ttlSeconds\": 120\n}"},"description":"Temporarily reserve an option while the customer reviews it.\n\n- Default TTL: 120 seconds (2 min)\n- Maximum TTL: 600 seconds (10 min)\n- Returns: `holdId`, `status: \"active\"`, `expiresAt`\n- Does NOT create a booking"}},{"name":"Confirm resolution → booking","event":[{"listen":"test","script":{"exec":["pm.test('Status 201', () => pm.response.to.have.status(201));","const d = pm.response.json();","const booking = d.data || d;","pm.collectionVariables.set('bookingId', booking.id || '');","pm.test('Booking created', () => pm.expect(booking.id).to.exist);","console.log('Booking:', booking.id, '| Status:', booking.status);"],"type":"text/javascript"}}],"request":{"method":"POST","url":"{{baseUrl}}/api/v2/resolutions/{{resolutionId}}/confirm","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"confirm_postman_{{$timestamp}}"}],"body":{"mode":"raw","raw":"{\n  \"optionId\": \"{{optionId}}\",\n  \"customer\": {\n    \"name\": \"James Park\",\n    \"email\": \"james@example.com\"\n  }\n}"},"description":"Confirm the selected option and create the booking.\n\n⚠️ **Call only after the customer has approved:**\n- Provider name\n- Service\n- Date and time\n- Timezone\n- Cancellation policy\n\n**Requires:** `Idempotency-Key` header (safe to retry)\n\n**Returns:** booking with `status: \"pending\"` — the client receives an email to confirm."}},{"name":"Zero-result example","event":[{"listen":"test","script":{"exec":["const d = pm.response.json();","console.log('Status:', d.status);","console.log('Zero results — exclusions:', JSON.stringify(d.exclusions));"],"type":"text/javascript"}}],"request":{"method":"POST","url":"{{baseUrl}}/api/v2/resolutions","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"zero_result_{{$timestamp}}"}],"body":{"mode":"raw","raw":"{\n  \"serviceId\": \"svc_therapy\",\n  \"dateRange\": {\n    \"from\": \"2026-08-01\",\n    \"to\": \"2026-08-02\"\n  },\n  \"constraints\": {\n    \"languageCodes\": { \"anyOf\": [\"zh\"] },\n    \"modalityCodes\": { \"anyOf\": [\"in_person\"] },\n    \"acceptsNewClients\": true\n  },\n  \"limit\": 3\n}"},"description":"Intentionally over-constrained request to demonstrate zero-result handling.\n\nThe response includes `status: \"zero_results\"` and an `exclusions` map explaining why each provider was excluded."}}]},{"name":"3. Direct Booking (known provider)","description":"Use when you already know which provider should handle the request.\n\nFlow: GET /slots → POST /bookings","item":[{"name":"Get available slots","event":[{"listen":"test","script":{"exec":["pm.test('Status 200', () => pm.response.to.have.status(200));","const d = pm.response.json();","const slots = d.slots || d.data || [];","console.log('Available slots:', slots.length);"],"type":"text/javascript"}}],"request":{"method":"GET","url":{"raw":"{{baseUrl}}/api/v2/slots?providerId={{professionalId}}&date=2026-08-05","query":[{"key":"providerId","value":"{{professionalId}}"},{"key":"date","value":"2026-08-05"},{"key":"timezone","value":"America/New_York","disabled":true}]},"description":"Fetch available time slots for a known provider. Calendar conflicts are removed automatically."}},{"name":"Get booking","request":{"method":"GET","url":"{{baseUrl}}/api/v2/bookings/{{bookingId}}","description":"Retrieve full booking details by ID."}},{"name":"Reschedule booking","request":{"method":"POST","url":"{{baseUrl}}/api/v2/bookings/{{bookingId}}/reschedule","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"date\": \"2026-08-07\",\n  \"time\": \"15:00\"\n}"},"description":"Reschedule a booking to a new date and time.\n\n**Body:** `{ date: \"YYYY-MM-DD\", time: \"HH:MM\" }` (separate fields in provider timezone)\n\nCreates a new booking and cancels the original. Returns new booking with `status: \"pending\"`."}},{"name":"Cancel booking","request":{"method":"POST","url":"{{baseUrl}}/api/v2/bookings/{{bookingId}}/cancel","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"reason\": \"Customer requested cancellation\"\n}"},"description":"Cancel a booking. Triggers `booking.cancelled` webhook event."}}]},{"name":"4. Webhooks","item":[{"name":"Get webhook config","request":{"method":"GET","url":"{{baseUrl}}/api/v2/webhooks","description":"Read your current webhook URL and event subscriptions."}},{"name":"Send test webhook","event":[{"listen":"test","script":{"exec":["pm.test('Fired', () => pm.response.to.have.status(200));","const d = pm.response.json();","pm.test('Success', () => pm.expect(d.success).to.be.true);","console.log('Sent to:', d.sentTo);"],"type":"text/javascript"}}],"request":{"method":"POST","url":"{{baseUrl}}/api/v2/webhooks","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\n  \"url\": \"https://webhook.site/your-endpoint\",\n  \"events\": [\"booking.confirmed\"]\n}"},"description":"Send a synthetic test webhook to your endpoint.\n\nThe request is signed with `X-Orita-Signature: sha256=<hmac>`. Verify using HMAC-SHA256 with your webhook secret."}},{"name":"Get delivery logs","request":{"method":"GET","url":"{{baseUrl}}/api/v2/webhooks/deliveries","description":"Inspect webhook delivery attempts, status codes, latency, and response excerpts."}}]},{"name":"5. Analytics","item":[{"name":"Get analytics","request":{"method":"GET","url":{"raw":"{{baseUrl}}/api/v2/analytics?days=30","query":[{"key":"days","value":"30"}]},"description":"Resolution and booking performance metrics for the last N days."}},{"name":"Get usage","request":{"method":"GET","url":"{{baseUrl}}/api/v2/usage","description":"Monthly API usage and plan limits."}}]}]}