{"openapi":"3.1.0","info":{"title":"Tolk2Go Public Booking API","version":"1.2.0","description":"Discover and book professional interpreters without partner onboarding. Catalogue and availability endpoints are public. Booking management accepts a short-lived login token or a durable, revocable account-scoped agent access key. REST and MCP support resumable polling; outbound webhooks are not part of this contract."},"servers":[{"url":"https://api.tolk2go.com/api/v1"}],"paths":{"/languages":{"get":{"operationId":"listLanguages","summary":"List available interpreting languages (use IDs to filter /language-pairs)","parameters":[],"responses":{"200":{"description":"List of languages","content":{"application/json":{"schema":{"type":"object","properties":{"languages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"code":{"type":"string"},"flag":{"type":"string"}}}}}}}}}}}},"/language-pairs":{"get":{"operationId":"listLanguagePairs","summary":"List available language pair combinations","parameters":[{"name":"language_id","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by language ID"},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"nl"},"description":"Locale for names"}],"responses":{"200":{"description":"List of language pairs"}}}},"/situations":{"get":{"operationId":"listSituations","summary":"List situation types (medical, legal, etc.) with descriptions","parameters":[{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"nl"},"description":"Locale for names and descriptions"}],"responses":{"200":{"description":"List of situations"}}}},"/situations/{situation_id}/details":{"get":{"operationId":"getSituationDetails","summary":"List quick-select sub-options within a situation (not exhaustive)","parameters":[{"name":"situation_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"nl"}}],"responses":{"200":{"description":"List of situation details"}}}},"/availability":{"get":{"operationId":"searchAvailability","summary":"Search available interpreters with pricing","parameters":[{"name":"language_pair_id","in":"query","required":true,"schema":{"type":"string"},"description":"ID from /language-pairs"},{"name":"situation_id","in":"query","required":true,"schema":{"type":"string"},"description":"ID from /situations"},{"name":"start","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"ISO-8601 UTC"},{"name":"end","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"ISO-8601 UTC"},{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["phone","address"]}},{"name":"lat","in":"query","required":false,"schema":{"type":"number"},"description":"Required when type=address"},{"name":"lng","in":"query","required":false,"schema":{"type":"number"},"description":"Required when type=address"},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["price_asc","rating_desc"],"default":"price_asc"}}],"responses":{"200":{"description":"List of available interpreters with pricing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailabilityResult"}}}},"400":{"description":"Required search input missing"},"404":{"description":"Language pair or situation not found"}}}},"/register":{"post":{"operationId":"registerUser","summary":"Create a new user account (agent provides password)","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"},"first_name":{"type":"string","default":"Agent"},"last_name":{"type":"string","default":"Agent"},"company_name":{"type":"string"},"vat_number":{"type":"string"}}}}}},"responses":{"201":{"description":"Account created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationResult"}}}},"409":{"description":"Email already registered"},"429":{"description":"Registration limit reached"}}}},"/login":{"post":{"operationId":"loginUser","summary":"Login and receive a 5-minute Bearer token","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}}}}},"responses":{"200":{"description":"Token returned","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"expires_in":{"type":"integer","example":300}}}}}},"401":{"description":"Invalid credentials"},"429":{"description":"Too many attempts"}}}},"/agent-access-keys":{"get":{"operationId":"account_listAgentAccessKeys","summary":"List agent access key metadata; plaintext keys are never returned","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Key metadata"},"403":{"description":"A short-lived account login token is required"}}},"post":{"operationId":"account_issueAgentAccessKey","summary":"Issue a durable account-scoped key; plaintext is disclosed once","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":80},"expires_in_days":{"type":"integer","minimum":7,"maximum":365,"default":90}}}}}},"responses":{"201":{"description":"Key issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAccessKeyIssued"}}}},"403":{"description":"A short-lived account login token is required"},"429":{"description":"Issuance rate limit reached"}}}},"/agent-access-keys/{key_id}/rotate":{"post":{"operationId":"account_rotateAgentAccessKey","summary":"Issue a replacement and immediately revoke the current key","security":[{"bearerAuth":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Replacement key issued"},"404":{"description":"Active key not found"}}}},"/agent-access-keys/{key_id}":{"delete":{"operationId":"account_revokeAgentAccessKey","summary":"Revoke an agent access key","security":[{"bearerAuth":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Key revoked"},"404":{"description":"Active key not found"}}}},"/bookings":{"get":{"operationId":"interpreting_listBookings","summary":"List this account’s bookings and discover changes incrementally","security":[{"bearerAuth":[]}],"parameters":[{"name":"updated_since","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Owner-scoped bookings with a change cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingList"}}}},"401":{"description":"Credential missing, invalid, expired or revoked"}}},"post":{"operationId":"createBooking","summary":"Create a booking request — interpreters will be contacted for availability","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["language_pair_id","situation_id","start","end","type","preferred_interpreter_ids"],"properties":{"language_pair_id":{"type":"string"},"situation_id":{"type":"string"},"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["phone","address"]},"phone_type":{"type":"string","enum":["phone","video"]},"bookingTimezone":{"type":"string","example":"Europe/Amsterdam","description":"IANA timezone required for remote bookings; clients should send the booking device timezone"},"location":{"type":"object","required":["lat","lng","address"],"properties":{"lat":{"type":"number"},"lng":{"type":"number"},"address":{"type":"string"}}},"description":{"type":"string"},"client_reference":{"type":"string"},"preferred_interpreter_ids":{"type":"array","items":{"type":"string"},"description":"Interpreter IDs from GET /availability"}},"allOf":[{"if":{"properties":{"type":{"const":"phone"}},"required":["type"]},"then":{"required":["bookingTimezone"]}}]}}}},"responses":{"201":{"description":"Booking request created; poll the response endpoint until an interpreter is available","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingCreated"}}}},"400":{"description":"Invalid request"},"403":{"description":"New user limit - complete first booking before creating more"},"404":{"description":"Language pair, situation or interpreter not found"},"422":{"description":"Invalid address location"}}}},"/bookings/{booking_id}":{"get":{"operationId":"getBookingStatus","summary":"Poll booking, payment and change-request status","security":[{"bearerAuth":[]}],"parameters":[{"name":"booking_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Authoritative booking state with payment next action and polling links","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Booking"}}}},"401":{"description":"Bearer token missing, invalid or expired"},"404":{"description":"Booking not found or not owned by this account"}}},"patch":{"operationId":"requestBookingChange","summary":"Submit a supported customer change through the existing approval flow","description":"The assigned interpreter must approve the change. Send at least one supported field, then poll this booking for progress.","security":[{"bearerAuth":[]}],"parameters":[{"name":"booking_id","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingChange"}}}},"responses":{"202":{"description":"Change request submitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeRequestAccepted"}}}},"400":{"description":"No supported change supplied"},"401":{"description":"Bearer token missing, invalid or expired"},"404":{"description":"Booking or requested catalogue item not found, not owned, or not changeable"},"409":{"description":"Change rejected by booking policy or another request is pending"}}},"delete":{"operationId":"cancelBooking","summary":"Cancel a booking","security":[{"bearerAuth":[]}],"parameters":[{"name":"booking_id","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Booking cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancellationResult"}}}},"401":{"description":"Bearer token missing, invalid or expired"},"404":{"description":"Booking not found or not owned by this account"}}}},"/bookings/{booking_id}/responses":{"get":{"operationId":"getBookingResponses","summary":"Poll which interpreters responded as available","security":[{"bearerAuth":[]}],"parameters":[{"name":"booking_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Current interpreter responses; an empty array means poll again","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingResponses"}}}},"401":{"description":"Bearer token missing, invalid or expired"},"404":{"description":"Booking not found or not owned by this account"}}}},"/bookings/{booking_id}/book":{"post":{"operationId":"bookInterpreter","summary":"Book a specific interpreter who responded as available","security":[{"bearerAuth":[]}],"parameters":[{"name":"booking_id","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["interpreter_id"],"properties":{"interpreter_id":{"type":"string"}}}}}},"responses":{"200":{"description":"Interpreter selected. If payment is required, payment.payment_url is the secure customer action; otherwise follow next_action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InterpreterSelectionResult"}}}},"400":{"description":"Interpreter ID missing or booking failed"},"401":{"description":"Bearer token missing, invalid or expired"},"404":{"description":"Booking not found, not owned, or no longer searching"}}}}},"components":{"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":200},"description":"Required for writes authenticated with an agent access key. Reusing it with identical input safely replays the original response."}},"schemas":{"RegistrationResult":{"type":"object","required":["user_id","email","created"],"properties":{"user_id":{"type":"string"},"email":{"type":"string","format":"email"},"created":{"type":"boolean","const":true}}},"AgentAccessKeyIssued":{"type":"object","required":["key_id","key","name","status","expires_at","plaintext_disclosed_once"],"properties":{"key_id":{"type":"string"},"key":{"type":"string","writeOnly":true},"name":{"type":"string"},"status":{"type":"string","const":"active"},"expires_at":{"type":"string","format":"date-time"},"plaintext_disclosed_once":{"type":"boolean","const":true}}},"BookingList":{"type":"object","required":["service_kind","bookings","change_cursor"],"properties":{"service_kind":{"type":"string","const":"interpreting"},"bookings":{"type":"array","items":{"$ref":"#/components/schemas/Booking"}},"change_cursor":{"type":["string","null"]}}},"AvailabilityResult":{"type":"object","required":["language_pair","interpreters"],"properties":{"language_pair":{"type":"string"},"interpreters":{"type":"array","items":{"type":"object","required":["id","first_name","rating","review_count","price_excl_tax","tax","currency"],"properties":{"id":{"type":"string"},"first_name":{"type":"string"},"rating":{"type":"number"},"review_count":{"type":"integer"},"price_excl_tax":{"type":"string"},"tax":{"type":"string"},"currency":{"type":"string","const":"EUR"}}}}}},"BookingCreated":{"type":"object","required":["booking_id","status","created_at"],"properties":{"booking_id":{"type":"string"},"status":{"type":"string","const":"searching"},"created_at":{"type":"string","format":"date-time"}}},"Payment":{"type":"object","required":["required","status","amount","currency","deposit_percentage","next_action"],"properties":{"required":{"type":"boolean"},"status":{"type":"string","enum":["not_required","pending","paid"]},"amount":{"type":"number"},"currency":{"type":"string","const":"EUR"},"deposit_percentage":{"type":"number"},"payment_url":{"type":["string","null"],"format":"uri"},"next_action":{"type":"string","enum":["none","open_payment_url","poll_booking"]}}},"Booking":{"type":"object","required":["booking_id","service_kind","status","start","end","timezone","payment","change_request","next_actions","polling","created_at","updated_at"],"properties":{"booking_id":{"type":"string"},"service_kind":{"type":"string","const":"interpreting"},"status":{"type":"string","enum":["searching","booked_pending_payment","confirmed","reported","completed","disputed","cancelled","processing"]},"language_pair":{"type":"string"},"type":{"type":"string","enum":["phone","address"]},"phone_type":{"type":["string","null"]},"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"timezone":{"type":"string"},"taskTimezone":{"type":"string"},"client_reference":{"type":"string"},"interpreter":{"type":["object","null"]},"payment":{"$ref":"#/components/schemas/Payment"},"change_request":{"type":"object","properties":{"status":{"type":"string","enum":["none","pending"]}}},"next_actions":{"type":"array","items":{"type":"string"}},"polling":{"type":"object","properties":{"status_url":{"type":"string"},"responses_url":{"type":"string"},"recommended_after_seconds":{"type":"integer"}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"BookingChange":{"type":"object","minProperties":1,"properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"bookingTimezone":{"type":"string"},"type":{"type":"string","enum":["phone","address"]},"phone_type":{"type":"string"},"location":{"type":"object","required":["lat","lng","address"],"properties":{"lat":{"type":"number"},"lng":{"type":"number"},"address":{"type":"string"}}},"description":{"type":"string"},"situation_id":{"type":"string"},"language_pair_id":{"type":"string"}}},"BookingResponses":{"type":"object","required":["booking_id","status","responses"],"properties":{"booking_id":{"type":"string"},"status":{"type":"string"},"responses":{"type":"array","items":{"type":"object","required":["interpreter_id","first_name","available","financial_details"],"properties":{"interpreter_id":{"type":"string"},"first_name":{"type":"string"},"available":{"type":"boolean","const":true},"financial_details":{"type":"object","properties":{"hourly_rate":{"type":"string"},"distance_km":{"type":"number"},"distance_charge":{"type":"string"},"total":{"type":"string"},"currency":{"type":"string","const":"EUR"}}},"responded_at":{"type":["string","null"],"format":"date-time"}}}}}},"InterpreterSelectionResult":{"type":"object","required":["booking_id","status","interpreter","payment","next_action"],"properties":{"booking_id":{"type":"string"},"status":{"type":"string"},"interpreter":{"type":"object","properties":{"name":{"type":"string"}}},"payment":{"$ref":"#/components/schemas/Payment"},"next_action":{"type":"string","enum":["open_payment_url","poll_booking"]}}},"ChangeRequestAccepted":{"type":"object","required":["booking_id","status","change_request","next_action"],"properties":{"booking_id":{"type":"string"},"status":{"type":"string"},"change_request":{"type":"object","properties":{"status":{"type":"string","const":"pending"}}},"next_action":{"type":"string","const":"poll_booking"}}},"CancellationResult":{"type":"object","required":["booking_id","status"],"properties":{"booking_id":{"type":"string"},"status":{"type":"string","const":"cancelled"}}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A JWT from /login (valid for 5 minutes) or a durable t2g_agent_ account key. Key management itself requires the JWT."}}}}