[{"data":1,"prerenderedAt":799},["ShallowReactive",2],{"developers:\u002Fdevelopers\u002Freference-bookings":3},{"doc":4,"lang":207,"nav":219,"alternatePath":320,"policy":321,"specVersion":365,"reference":366,"layout":214,"toc":786,"prev":793,"next":794,"operations":795,"overview":209,"heroExample":209},{"id":5,"title":6,"apiTag":7,"body":8,"description":204,"draft":205,"extension":206,"lang":207,"meta":208,"navTitle":209,"navigation":210,"order":211,"path":212,"rawbody":213,"section":214,"seo":215,"stem":216,"translationKey":217,"version":209,"__hash__":218},"developers_en\u002Fdevelopers\u002Freference-bookings.md","Bookings and services","bookings",{"type":9,"value":10,"toc":198},"minimark",[11,16,30,56,113,150,173],[12,13,15],"h2",{"id":14},"overview","Overview",[17,18,19,20,24,25,29],"p",{},"A ",[21,22,23],"strong",{},"booking"," is an appointment on the team's calendar. Its ",[26,27,28],"code",{},"kind"," says where it came from:",[31,32,33,44,50],"ul",{},[34,35,36,39,40,43],"li",{},[26,37,38],{},"service_booking",": booked for a bookable service, by the AI, a customer or someone on the team. ",[26,41,42],{},"service"," names the service.",[34,45,46,49],{},[26,47,48],{},"calendar_event",": an event from the team's connected calendar.",[34,51,52,55],{},[26,53,54],{},"external_import",": synced from an external booking system, or read from a booking portal's email.",[17,57,58,61,62,65,66,65,69,65,72,65,75,65,78,81,82,85,86,89,90,65,93,81,96,99,100,61,103,65,106,81,109,112],{},[26,59,60],{},"status"," is ",[26,63,64],{},"scheduled",", ",[26,67,68],{},"rescheduled",[26,70,71],{},"cancelled",[26,73,74],{},"postponed",[26,76,77],{},"attended",[26,79,80],{},"no_show"," or ",[26,83,84],{},"team_no_show",". Only people record attendance. ",[26,87,88],{},"source"," says who booked it: ",[26,91,92],{},"ai",[26,94,95],{},"customer",[26,97,98],{},"operator",". ",[26,101,102],{},"meeting_type",[26,104,105],{},"online",[26,107,108],{},"in_person",[26,110,111],{},"phone",". Payments are not exported.",[17,114,115,116,119,120,123,124,126,127,129,130,132,133,136,137,140,141,143,144,149],{},"A reschedule shows up in one of two ways. The same booking is updated when someone on the team moves it in Totem, when the AI moves a booking held in an external booking system such as Koibox, when that system reports a move, or when a booking portal's email does: ",[26,117,118],{},"starts_at"," and ",[26,121,122],{},"ends_at"," hold the new time, and the previous time is not exported. Its ",[26,125,60],{}," becomes ",[26,128,68],{},", although a move that an external booking system reports can leave the status unchanged. When the AI reschedules any other booking, it creates a new one: the old booking ends as ",[26,131,71],{},", with ",[26,134,135],{},"rescheduled_to"," pointing to the new one, and the new one points back with ",[26,138,139],{},"rescheduled_from",". For a few seconds after that kind of reschedule, the old booking can still read ",[26,142,64],{},". A change made directly in Google Calendar or Outlook may not reach the Totem booking. A booking rescheduled before Totem started recording these links may lack either link, as ",[145,146,148],"a",{"href":147},"\u002Fdevelopers\u002Fcoverage","Data coverage"," explains.",[17,151,19,152,155,156,162,163,165,166,81,169,172],{},[21,153,154],{},"bookable service"," is something customers can book with the team, such as a first consultation. ",[145,157,159],{"href":158},"\u002Fdevelopers\u002Freference-bookings#booking_services.list",[26,160,161],{},"GET \u002Fv1\u002Fbooking_services"," returns every service of the team, each with its ",[26,164,102],{},", in one response that takes no ",[26,167,168],{},"limit",[26,170,171],{},"cursor",". Services are not in the changes feed: read the list when you start syncing a team, when a booking names a service you do not know, and at least once a day. A deleted service drops out of the list while its bookings keep naming its id: do not re-read the list for an id it did not resolve last time, and if you show service names on older bookings, keep the name from an earlier read. Disabled services stay listed, with nothing that marks them as disabled.",[17,174,175,176,119,182,188,189,192,193,197],{},"Use ",[145,177,179],{"href":178},"\u002Fdevelopers\u002Freference-bookings#bookings.list",[26,180,181],{},"GET \u002Fv1\u002Fbookings",[145,183,185],{"href":184},"\u002Fdevelopers\u002Freference-bookings#bookings.get",[26,186,187],{},"GET \u002Fv1\u002Fbookings\u002F{id}"," to look bookings up; ",[26,190,191],{},"GET \u002Fv1\u002Fbookings?lead="," lists one lead's bookings. To keep a copy, follow the changes feed: ",[145,194,196],{"href":195},"\u002Fdevelopers\u002Fsync","Keep a copy in sync"," explains it.",{"title":199,"searchDepth":200,"depth":200,"links":201},"",3,[202],{"id":14,"depth":203,"text":15},2,"List and fetch a team's bookings, and list the services its customers can book.",false,"md","en",{},null,true,"80","\u002Fdevelopers\u002Freference-bookings","---\ntitle: Bookings and services\ndescription: List and fetch a team's bookings, and list the services its customers can book.\nsection: reference\norder: 80\ntranslationKey: reference-bookings\nlang: en\ndraft: false\napiTag: bookings\n---\n\n## Overview\n\nA **booking** is an appointment on the team's calendar. Its `kind` says where it came from:\n\n- `service_booking`: booked for a bookable service, by the AI, a customer or someone on the team. `service` names the service.\n- `calendar_event`: an event from the team's connected calendar.\n- `external_import`: synced from an external booking system, or read from a booking portal's email.\n\n`status` is `scheduled`, `rescheduled`, `cancelled`, `postponed`, `attended`, `no_show` or `team_no_show`. Only people record attendance. `source` says who booked it: `ai`, `customer` or `operator`. `meeting_type` is `online`, `in_person` or `phone`. Payments are not exported.\n\nA reschedule shows up in one of two ways. The same booking is updated when someone on the team moves it in Totem, when the AI moves a booking held in an external booking system such as Koibox, when that system reports a move, or when a booking portal's email does: `starts_at` and `ends_at` hold the new time, and the previous time is not exported. Its `status` becomes `rescheduled`, although a move that an external booking system reports can leave the status unchanged. When the AI reschedules any other booking, it creates a new one: the old booking ends as `cancelled`, with `rescheduled_to` pointing to the new one, and the new one points back with `rescheduled_from`. For a few seconds after that kind of reschedule, the old booking can still read `scheduled`. A change made directly in Google Calendar or Outlook may not reach the Totem booking. A booking rescheduled before Totem started recording these links may lack either link, as [Data coverage](\u002Fdevelopers\u002Fcoverage) explains.\n\nA **bookable service** is something customers can book with the team, such as a first consultation. [`GET \u002Fv1\u002Fbooking_services`](\u002Fdevelopers\u002Freference-bookings#booking_services.list) returns every service of the team, each with its `meeting_type`, in one response that takes no `limit` or `cursor`. Services are not in the changes feed: read the list when you start syncing a team, when a booking names a service you do not know, and at least once a day. A deleted service drops out of the list while its bookings keep naming its id: do not re-read the list for an id it did not resolve last time, and if you show service names on older bookings, keep the name from an earlier read. Disabled services stay listed, with nothing that marks them as disabled.\n\nUse [`GET \u002Fv1\u002Fbookings`](\u002Fdevelopers\u002Freference-bookings#bookings.list) and [`GET \u002Fv1\u002Fbookings\u002F{id}`](\u002Fdevelopers\u002Freference-bookings#bookings.get) to look bookings up; `GET \u002Fv1\u002Fbookings?lead=` lists one lead's bookings. To keep a copy, follow the changes feed: [Keep a copy in sync](\u002Fdevelopers\u002Fsync) explains it.\n","reference",{"title":6,"description":204},"developers\u002Freference-bookings","reference-bookings","bgFQHMQyyMS-EZrdNtC5RyiuK5aMvVYfyzcSS2zb3rU",[220,234,257,301],{"section":221,"items":222},"start",[223,226,230],{"path":224,"title":15,"description":225},"\u002Fdevelopers","Read the leads, calls, conversations and bookings of your Totem teams from your own systems, and keep a copy in sync.",{"path":227,"title":228,"description":229},"\u002Fdevelopers\u002Fquickstart","Quickstart","Make your first requests to the Totem API in a few minutes. Check your key, find your team, list leads and start a sync.",{"path":231,"title":232,"description":233},"\u002Fdevelopers\u002Fauthentication","Authentication","Secret keys and where they may live, the Totem-Team header for keys with several teams, IP allowlists, and how to roll or revoke a key.",{"section":235,"items":236},"guides",[237,241,243,247,249,253],{"path":238,"title":239,"description":240},"\u002Fdevelopers\u002Ftypescript","TypeScript SDK","Use the official TypeScript client to read your Totem data, paginate lists and handle API errors from your server.",{"path":195,"title":196,"description":242},"Copy a team with the changes feed and keep the copy current. Apply pages safely, recover from errors, and start from a reference client that Totem tests.",{"path":244,"title":245,"description":246},"\u002Fdevelopers\u002Fpagination","Lists and pagination","How list endpoints return records a page at a time, how to read every page, and what order and filters a list supports.",{"path":147,"title":148,"description":248},"What Totem records, since when, and how to tell an empty value from a fact that was never recorded.",{"path":250,"title":251,"description":252},"\u002Fdevelopers\u002Ftesting","Testing and go-live","How to build and test an integration safely while the API has no test environment, and what to check before you go live.",{"path":254,"title":255,"description":256},"\u002Fdevelopers\u002Fsecurity","Security and personal data","How Totem protects API keys and the data the API serves, what it records about each key, where the API runs, and what to do with the personal data you copy.",{"section":214,"items":258},[259,263,267,271,276,281,286,291,292,297],{"path":260,"title":261,"description":262},"\u002Fdevelopers\u002Fconventions","Conventions","The notation these docs use, and the rules every response follows: ids, timestamps, empty values, amounts, enums, versions, stability, errors and untrusted text.",{"path":264,"title":265,"description":266},"\u002Fdevelopers\u002Ferrors","Errors","The error format, how your integration should handle each kind of error, and every error code with when it happens and what to do.",{"path":268,"title":269,"description":270},"\u002Fdevelopers\u002Frate-limits","Rate limits","How much a key can read per minute and per day, what counts toward each limit, how to retry after a 429, and how long an initial sync takes.",{"path":272,"title":273,"description":274,"apiTag":275},"\u002Fdevelopers\u002Freference-account","Account, teams and members","Check that a key works and what it can read, list its teams with their time zones, list each team's members, and check that the API is up.","account",{"path":277,"title":278,"description":279,"apiTag":280},"\u002Fdevelopers\u002Freference-leads","Leads, boards and activities","List, fetch and search a team's leads and clients, read each lead's activities, and list the boards and stages they move through.","leads",{"path":282,"title":283,"description":284,"apiTag":285},"\u002Fdevelopers\u002Freference-calls","Calls","List and fetch a team's calls, with their direction, timing and a normalized outcome. No recordings or transcripts.","calls",{"path":287,"title":288,"description":289,"apiTag":290},"\u002Fdevelopers\u002Freference-conversations","Conversations","List and fetch a team's conversations on every channel, with their status, assignee, whether a person has taken them over and when the last messages came and went. Never message content.","conversations",{"path":212,"title":6,"description":204,"apiTag":7},{"path":293,"title":294,"description":295,"apiTag":296},"\u002Fdevelopers\u002Freference-sync","Changes feed","One endpoint that copies a team and then returns every change, page by page.","sync",{"path":298,"title":299,"description":300},"\u002Fdevelopers\u002Fobjects","All objects","Every object the API returns, field by field, with an example of each.",{"section":302,"items":303},"resources",[304,308,312,316],{"path":305,"title":306,"description":307},"\u002Fdevelopers\u002Fchangelog","Changelog","Changes to the Totem API, newest first, each under the date it shipped.",{"path":309,"title":310,"description":311},"\u002Fdevelopers\u002Fsupport","Support","How to get help with the Totem API, what to include in a request, and what to do if a key leaks.",{"path":313,"title":314,"description":315},"\u002Fdevelopers\u002Fglossary","Glossary","The terms these docs use, defined in one place, each with a link to the page that explains it.",{"path":317,"title":318,"description":319},"\u002Fdevelopers\u002Ffaq","FAQ","Short answers to the questions developers ask most about the Totem API, with links to the details.","\u002Fdevelopers\u002Fes\u002Freference-bookings",{"ACTIVATION_MARGIN_MS":322,"ADMIN_ACCESS_DISCLOSURE_VERSION":323,"AUDIT_RETENTION_DAYS":324,"AUTH_FAILURE_LIMITS":325,"CAPTURE_LAG_FLOOR_MS":329,"CAPTURE_LAG_P99_MS":209,"CURSOR_MAX_AGE_DAYS":330,"DIRTY_TTL_DAYS":330,"FAMILY_TEAM_SCOPE":331,"FAMILY_TEAM_SCOPE_OPTIONS":332,"FEED_SETTLE_LAG_MS":334,"GATE_REFRESH_MS":322,"INTEGRATION_NAME_LENGTH":335,"INTEGRATION_PURPOSE_LENGTH":337,"KEY_CACHE_TTL_MS":340,"KEY_STATS_RETENTION_DAYS":341,"LEAD_RESPONSE_READ_BUDGET":342,"LIST_SCAN_MAX":345,"MAX_FAMILY_INTEGRATION_TEAMS":330,"MAX_INTEGRATIONS_PER_FAMILY":346,"MAX_IP_ALLOWLIST":327,"PAGE_LIMIT":347,"PLATFORM_CONFIG_TTL_MS":350,"REMOVAL_RETENTION_DAYS":351,"REQUEST_BODY_MAX_BYTES":352,"ROLL_GRACE_DEFAULT_HOURS":353,"ROLL_GRACE_HOURS":354,"SEARCH_MAX_RESULTS":346,"SENSITIVE_SECTOR_POLICY":357,"SENSITIVE_SECTOR_POLICY_OPTIONS":358,"SYNC_DAILY_BUDGET":360,"SYNC_VELOCITY":362,"TEAM_CACHE_TTL_MS":364},60000,"2026-10-17",365,{"perIpPerMinute":326,"perLookupIdPerMinute":327,"banMs":328},60,20,600000,300000,30,"explicit_list",[331,333],"all_family_teams",10000,{"min":203,"max":336},80,{"min":338,"max":339},1,280,5000,90,{"conversations":327,"messageReads":343,"calls":344},200,50,1000,10,{"default":348,"max":349},25,100,15000,45,16384,24,[355,338,353,356],0,168,"exclude",[357,359],"allow",{"floor":361,"recordsMultiplier":200},250000,{"perMinute":363,"burst":334},2000,30000,"1.0a",{"operations":367,"schemas":600,"errors":671,"commonErrors":782,"defaultStability":374,"policy":321,"problemExample":783},[368,464,559],{"id":369,"method":370,"path":371,"summary":372,"description":373,"stability":374,"scopes":375,"rateClass":296,"tenantBinding":377,"authenticated":210,"parameters":378,"parametersByLocation":402,"body":406,"bodyDescription":199,"responseFields":407,"responseComponent":433,"listOf":422,"example":434,"errors":445,"tag":7},"bookings.list","GET","\u002Fv1\u002Fbookings","List bookings","Returns a page of the team's bookings: appointments for a bookable service, events from the connected calendar and bookings imported from other systems, each with its status and times. Pass `lead` for one lead's bookings.","beta",[376],"calendar:read","team_header",[379,384,389,395],{"name":168,"type":380,"required":205,"description":381,"nullable":205,"typeLabel":380,"constraints":382,"location":383},"integer","Items per page, 1–100. Defaults to 25.",{"minimum":338,"maximum":349,"default":348},"query",{"name":171,"type":385,"required":205,"description":386,"nullable":205,"typeLabel":385,"constraints":387,"location":383},"string","The `next_cursor` of the previous page. Omit it for the first page.",{"minLength":338,"maxLength":388},512,{"name":390,"type":385,"required":205,"description":391,"nullable":205,"typeLabel":385,"constraints":392,"location":383},"lead","Only the bookings linked to this lead: every item's `lead` is this id. A lead of another team, or one that does not exist, matches nothing.",{"prefixes":393},[394],"lead_",{"name":396,"type":385,"required":205,"description":397,"nullable":205,"typeLabel":385,"constraints":398,"conditional":210,"location":401},"Totem-Team","The team to read, as a `team_…` id. Omit it when the key reads one team; it is required when the key reads several (`400 team_required`). When you send it, it must name a team the key reads: a malformed id gets `400 invalid_request`, and a team outside the key gets `404 team_not_accessible`, as does a request without it once the key reads no team at all.",{"prefixes":399},[400],"team_","header",{"path":403,"query":404,"header":405},[],[379,384,389],[395],[],[408,414,425,429],{"name":409,"type":410,"required":210,"description":411,"nullable":205,"typeLabel":385,"enumValues":412,"constant":210},"object","\"list\"","Always `list`.",[413],"list",{"name":415,"type":416,"required":210,"description":417,"nullable":205,"typeLabel":416,"typeTokens":418,"ref":422},"data","Array\u003CBooking>","The items of this page.",[419,421,423],{"text":420},"Array\u003C",{"text":422,"ref":422},"Booking",{"text":424},">",{"name":426,"type":427,"required":210,"description":428,"nullable":205,"typeLabel":427},"has_more","boolean","`true` when another page follows: fetch it with `next_cursor`, even if this page holds fewer items than `limit`.",{"name":430,"type":431,"required":210,"description":432,"nullable":210,"typeLabel":385},"next_cursor","string | null","Opaque cursor for the next page, or null on the last page. Never parse it.","BookingList",{"object":413,"data":435,"has_more":205,"next_cursor":209},[436],{"id":437,"object":23,"livemode":205,"team":438,"lead":439,"kind":38,"service":440,"status":64,"starts_at":441,"ends_at":442,"meeting_type":108,"source":92,"rescheduled_from":209,"rescheduled_to":209,"created_at":443,"version":338,"updated_at":444},"bkg_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMX3ttMKHRR9ADk3N7Cr3NSuY0","team_r9uYrIW4gSFJJ6hZQ9ip1UIpPaAD1CF7NR","lead_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXKSF0QbLS8CiUKJpEP34LFQG","svc_h42kgwwJGPzsm2Zoy1A1RBv1KIrX5","2026-10-06T15:00:00.000Z","2026-10-06T15:30:00.000Z","2026-10-01T09:01:00.000Z","2026-10-01T09:01:02.000Z",[446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463],"invalid_request","secret_key_in_browser","invalid_credentials","key_expired","insufficient_scope","plan_not_entitled","ip_not_allowed","capability_disabled","rate_limited","internal_error","api_disabled","service_unavailable","team_required","team_not_accessible","team_state_restricted","sector_restricted","capture_not_ready","quota_exceeded",{"id":465,"method":370,"path":466,"summary":467,"description":468,"stability":374,"scopes":469,"rateClass":470,"tenantBinding":471,"authenticated":210,"parameters":472,"parametersByLocation":480,"body":484,"bodyDescription":199,"responseFields":485,"responseComponent":422,"listOf":209,"example":556,"errors":557,"tag":7},"bookings.get","\u002Fv1\u002Fbookings\u002F{id}","Get a booking","Returns one booking by its id. A booking this key cannot read, or one that was removed, answers `404 resource_missing`.",[376],"read","resource_id",[473],{"name":474,"type":385,"required":210,"description":475,"nullable":205,"typeLabel":385,"constraints":476,"location":479},"id","The booking's public id.",{"prefixes":477},[478],"bkg_","path",{"path":481,"query":482,"header":483},[473],[],[],[],[486,490,494,497,502,506,510,515,519,524,527,531,535,539,543,547,551],{"name":474,"type":385,"required":210,"description":487,"nullable":205,"typeLabel":385,"constraints":488},"Public id of the record.",{"prefixes":489},[478],{"name":409,"type":491,"required":210,"description":492,"nullable":205,"typeLabel":385,"enumValues":493,"constant":210},"\"booking\"","Always `booking`.",[23],{"name":495,"type":427,"required":210,"description":496,"nullable":205,"typeLabel":427},"livemode","`true` for real data; `false` in example data.",{"name":498,"type":385,"required":210,"description":499,"nullable":205,"typeLabel":385,"constraints":500},"team","The team this record belongs to.",{"prefixes":501},[400],{"name":390,"type":431,"required":210,"description":503,"nullable":210,"typeLabel":385,"constraints":504},"The lead this booking belongs to, or null for a booking without a lead or when the lead no longer exists. Names and contact details appear only on the lead.",{"prefixes":505},[394],{"name":28,"type":507,"required":210,"description":508,"nullable":205,"typeLabel":385,"enumValues":509},"\"service_booking\" | \"calendar_event\" | \"external_import\"","`service_booking` (booked for a bookable service, by the AI, a customer or a person), `calendar_event` (an event from the connected calendar) or `external_import` (synced from an external booking system or read from a portal email). A booking from an origin this version does not know is reported as `calendar_event`.",[38,48,54],{"name":42,"type":431,"required":210,"description":511,"nullable":210,"typeLabel":385,"constraints":512},"The booked service (see `\u002Fbooking_services`) on a `service_booking`; null otherwise.",{"prefixes":513},[514],"svc_",{"name":60,"type":516,"required":210,"description":517,"nullable":210,"typeLabel":385,"enumValues":518},"\"scheduled\" | \"rescheduled\" | \"cancelled\" | \"postponed\" | \"attended\" | \"no_show\" | \"team_no_show\" | null","`scheduled`, `rescheduled`, `cancelled`, `postponed`, `attended`, `no_show` or `team_no_show` (attendance is recorded only by people); null for a value this version does not know. `rescheduled` means the booking was moved in place and its times are the new ones; a booking the AI replaced with a new one reads `cancelled`, with `rescheduled_to` set.",[64,68,71,74,77,80,84],{"name":118,"type":520,"required":210,"description":521,"nullable":210,"typeLabel":385,"constraints":522},"string (date-time) | null","When the booking starts (UTC).",{"format":523},"date-time",{"name":122,"type":520,"required":210,"description":525,"nullable":210,"typeLabel":385,"constraints":526},"When the booking ends (UTC).",{"format":523},{"name":102,"type":528,"required":210,"description":529,"nullable":210,"typeLabel":385,"enumValues":530},"\"online\" | \"in_person\" | \"phone\" | null","`online`, `in_person` or `phone`; null when not stored.",[105,108,111],{"name":88,"type":532,"required":210,"description":533,"nullable":210,"typeLabel":385,"enumValues":534},"\"ai\" | \"customer\" | \"operator\" | null","Who booked it: `ai`, `customer` or `operator`; null when not recorded.",[92,95,98],{"name":139,"type":431,"required":210,"description":536,"nullable":210,"typeLabel":385,"constraints":537},"The booking this one replaced in a reschedule, or null. For a few seconds the replaced booking can still read `scheduled`; bookings rescheduled before Totem started recording this link may not have it.",{"prefixes":538},[478],{"name":135,"type":431,"required":210,"description":540,"nullable":210,"typeLabel":385,"constraints":541},"The booking that replaced this one in a reschedule, or null. When it is set, this booking reads `cancelled`.",{"prefixes":542},[478],{"name":544,"type":520,"required":210,"description":545,"nullable":210,"typeLabel":385,"constraints":546},"created_at","When the booking was recorded in Totem (UTC).",{"format":523},{"name":548,"type":380,"required":210,"description":549,"nullable":205,"typeLabel":380,"constraints":550},"version","Increases every time one of the record's exported fields changes. Apply a change only when its version is greater than the one you hold.",{"minimum":338},{"name":552,"type":553,"required":210,"description":554,"nullable":205,"typeLabel":385,"constraints":555},"updated_at","string (date-time)","When Totem recorded this version (UTC). It is not the time the business event happened.",{"format":523},{"id":437,"object":23,"livemode":205,"team":438,"lead":439,"kind":38,"service":440,"status":64,"starts_at":441,"ends_at":442,"meeting_type":108,"source":92,"rescheduled_from":209,"rescheduled_to":209,"created_at":443,"version":338,"updated_at":444},[446,447,448,449,450,451,452,453,454,455,456,457,558,460,461,462],"resource_missing",{"id":560,"method":370,"path":561,"summary":562,"description":563,"stability":374,"scopes":564,"rateClass":296,"tenantBinding":377,"authenticated":210,"parameters":565,"parametersByLocation":569,"body":573,"bodyDescription":199,"responseFields":574,"responseComponent":593,"listOf":583,"example":594,"errors":599,"tag":7},"booking_services.list","\u002Fv1\u002Fbooking_services","List bookable services","Lists every bookable service of the team in one response that is never paged and takes no `limit` or `cursor`. Bookable services are not in the changes feed: read this list when you start syncing a team, again when a booking names a service you do not know, and at least once a day. A deleted service drops out of the list while its bookings keep naming its id, so keep a service name you need from an earlier read.",[376],[566],{"name":396,"type":385,"required":205,"description":397,"nullable":205,"typeLabel":385,"constraints":567,"conditional":210,"location":401},{"prefixes":568},[400],{"path":570,"query":571,"header":572},[],[],[566],[],[575,577,585,589],{"name":409,"type":410,"required":210,"description":411,"nullable":205,"typeLabel":385,"enumValues":576,"constant":210},[413],{"name":415,"type":578,"required":210,"description":579,"nullable":205,"typeLabel":578,"typeTokens":580,"ref":583},"Array\u003CBookingService>","Every bookable service of the team.",[581,582,584],{"text":420},{"text":583,"ref":583},"BookingService",{"text":424},{"name":426,"type":586,"required":210,"description":587,"nullable":205,"typeLabel":427,"enumValues":588,"constant":210},"false","Always `false`: this list is never paged.",[205],{"name":430,"type":590,"required":210,"description":591,"nullable":210,"typeLabel":590,"typeTokens":592},"null","Always `null`: there is no next page.",[],"BookingServiceList",{"object":413,"data":595,"has_more":205,"next_cursor":209},[596],{"id":440,"object":597,"livemode":205,"team":438,"name":598,"meeting_type":108},"booking_service","First visit",[446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463],[601,646],{"name":422,"description":602,"fields":603,"example":643,"variants":644,"sharedFields":645},"A booking and its `kind`: an appointment for a bookable service, an event from the connected calendar, or a booking imported from another system.",[604,607,609,610,613,616,618,621,623,625,627,629,631,634,637,639,641],{"name":474,"type":385,"required":210,"description":487,"nullable":205,"typeLabel":385,"constraints":605},{"prefixes":606},[478],{"name":409,"type":491,"required":210,"description":492,"nullable":205,"typeLabel":385,"enumValues":608,"constant":210},[23],{"name":495,"type":427,"required":210,"description":496,"nullable":205,"typeLabel":427},{"name":498,"type":385,"required":210,"description":499,"nullable":205,"typeLabel":385,"constraints":611},{"prefixes":612},[400],{"name":390,"type":431,"required":210,"description":503,"nullable":210,"typeLabel":385,"constraints":614},{"prefixes":615},[394],{"name":28,"type":507,"required":210,"description":508,"nullable":205,"typeLabel":385,"enumValues":617},[38,48,54],{"name":42,"type":431,"required":210,"description":511,"nullable":210,"typeLabel":385,"constraints":619},{"prefixes":620},[514],{"name":60,"type":516,"required":210,"description":517,"nullable":210,"typeLabel":385,"enumValues":622},[64,68,71,74,77,80,84],{"name":118,"type":520,"required":210,"description":521,"nullable":210,"typeLabel":385,"constraints":624},{"format":523},{"name":122,"type":520,"required":210,"description":525,"nullable":210,"typeLabel":385,"constraints":626},{"format":523},{"name":102,"type":528,"required":210,"description":529,"nullable":210,"typeLabel":385,"enumValues":628},[105,108,111],{"name":88,"type":532,"required":210,"description":533,"nullable":210,"typeLabel":385,"enumValues":630},[92,95,98],{"name":139,"type":431,"required":210,"description":536,"nullable":210,"typeLabel":385,"constraints":632},{"prefixes":633},[478],{"name":135,"type":431,"required":210,"description":540,"nullable":210,"typeLabel":385,"constraints":635},{"prefixes":636},[478],{"name":544,"type":520,"required":210,"description":545,"nullable":210,"typeLabel":385,"constraints":638},{"format":523},{"name":548,"type":380,"required":210,"description":549,"nullable":205,"typeLabel":380,"constraints":640},{"minimum":338},{"name":552,"type":553,"required":210,"description":554,"nullable":205,"typeLabel":385,"constraints":642},{"format":523},{"id":437,"object":23,"livemode":205,"team":438,"lead":439,"kind":38,"service":440,"status":64,"starts_at":441,"ends_at":442,"meeting_type":108,"source":92,"rescheduled_from":209,"rescheduled_to":209,"created_at":443,"version":338,"updated_at":444},[],[],{"name":583,"description":647,"fields":648,"example":668,"variants":669,"sharedFields":670},"A service customers can book, with its meeting type.",[649,652,656,657,660,664],{"name":474,"type":385,"required":210,"description":487,"nullable":205,"typeLabel":385,"constraints":650},{"prefixes":651},[514],{"name":409,"type":653,"required":210,"description":654,"nullable":205,"typeLabel":385,"enumValues":655,"constant":210},"\"booking_service\"","Always `booking_service`.",[597],{"name":495,"type":427,"required":210,"description":496,"nullable":205,"typeLabel":427},{"name":498,"type":385,"required":210,"description":499,"nullable":205,"typeLabel":385,"constraints":658},{"prefixes":659},[400],{"name":661,"type":431,"required":210,"description":662,"nullable":210,"typeLabel":385,"constraints":663},"name","The service's name, or null when none is stored.",{"minLength":338},{"name":102,"type":665,"required":210,"description":666,"nullable":205,"typeLabel":385,"enumValues":667},"\"online\" | \"in_person\" | \"phone\"","How the service happens: `online` (the default when none is stored), `in_person` or `phone`.",[105,108,111],{"id":440,"object":597,"livemode":205,"team":438,"name":598,"meeting_type":108},[],[],[672,679,683,687,693,697,703,709,713,717,722,726,731,737,744,750,756,763,767,773,778],{"code":446,"status":673,"title":674,"wireTitle":674,"action":675,"description":676,"fix":677,"retryable":205,"retry":678},400,"Invalid request","fix_request","Something in the request is not valid: an unknown, repeated or out-of-range query parameter, a query string or body on an endpoint that takes none, a cursor issued for another endpoint, filter or team, a malformed `Totem-Team` header, or a body that is not the JSON this endpoint expects. `param` names the parameter, header or field at fault. A conversations cursor is also refused once the conversation it points at has been erased.","Correct what `param` names before you retry: the same request fails the same way. For a cursor, send the `next_cursor` you received from the same endpoint, with the same filters and team. If a conversations cursor you did not change is refused, start that list again from the first page.","no",{"code":458,"status":673,"title":680,"wireTitle":680,"action":675,"description":681,"fix":682,"retryable":205,"retry":678},"Team required","The key reads more than one team and this endpoint reads one team's data, but the request does not say which team.","Send the team's id (`team_…`, as listed by `GET \u002Fv1\u002Fteams`) in the `Totem-Team` header.",{"code":447,"status":673,"title":684,"wireTitle":684,"action":675,"description":685,"fix":686,"retryable":205,"retry":678},"Secret key sent from a browser","The request carried a secret key together with an `Origin` header, which means it came from a browser. Totem refuses it before reading anything.","Call the API only from your server. If the key has been in a web page, a mobile app or a browser extension, treat it as leaked: roll it and mark it as compromised, so the old key stops working at once.",{"code":448,"status":688,"title":689,"wireTitle":689,"action":690,"description":691,"fix":692,"retryable":205,"retry":678},401,"Invalid credentials","check_credentials","The `Authorization` header is missing or malformed, or the key is unknown, wrong or revoked, or its integration is no longer active.","Send `Authorization: Bearer \u003Ckey>` with a current secret key. Do not retry in a loop: repeated failures from one IP address, or against one key, lock it out for a while with `429 rate_limited`.",{"code":449,"status":688,"title":694,"wireTitle":694,"action":690,"description":695,"fix":696,"retryable":205,"retry":678},"Key expired","The key was rolled and its grace period is over.","Deploy the key that replaced it: the old key is past its grace period and will not work again. If there is no replacement, create a new key in Settings → Developers.",{"code":450,"status":698,"title":699,"wireTitle":699,"action":700,"description":701,"fix":702,"retryable":205,"retry":678},403,"Insufficient scope","contact_support","The key lacks a permission this endpoint needs. Every v1.0a key holds the full read set, so this should not happen.","Contact support and quote the `Totem-Request-Id` of the response.",{"code":451,"status":698,"title":704,"wireTitle":704,"action":705,"description":706,"fix":707,"retryable":210,"retry":708},"Plan not entitled","keep_and_retry","The organization's plan does not include the Totem API at the moment.","Keep your data and cursors, and pause calls until the customer has a plan with API access again; then continue where you left off. While access is refused, the feed delivers nothing for the key's teams, removals included: if the refusal lasts longer than your retention policy allows, delete your copy.","restored",{"code":452,"status":698,"title":710,"wireTitle":710,"action":690,"description":711,"fix":712,"retryable":205,"retry":678},"IP address not allowed","The key is valid, but the request came from an IP address outside the integration's allowlist.","Call from an allowed address, or ask an administrator to add yours to the allowlist in Settings → Developers.",{"code":460,"status":698,"title":714,"wireTitle":714,"action":705,"description":715,"fix":716,"retryable":210,"retry":708},"Team restricted","The team is restricted for now: it is disabled (for example, suspended for non-payment), archived or billing-only, or its API access is paused. `GET \u002Fv1\u002Fteams` still lists it.","Keep the team's data and cursor, skip it for this run and try again later. The key's other teams are not affected. While the team is restricted, the feed delivers nothing for it, removals included: if the restriction lasts longer than your retention policy allows, delete the team's copy.",{"code":461,"status":698,"title":718,"wireTitle":718,"action":705,"description":719,"fix":720,"retryable":205,"retry":721},"Sector restricted","Totem does not export this team's data through the API because the team works in a sensitive sector, such as health care, where its records can reveal health information.","Skip the team: waiting does not change this. The feed delivers nothing for it, removals included, so keep what you already have only as long as your retention policy allows, then delete the team's copy. Talk to the customer or to Totem if you need its data.","blocked",{"code":453,"status":698,"title":723,"wireTitle":723,"action":705,"description":724,"fix":725,"retryable":210,"retry":708},"Capability disabled","Totem has temporarily switched this endpoint off for every key.","Keep your data and cursors and try again later; the other endpoints keep working.",{"code":558,"status":727,"title":728,"wireTitle":728,"action":675,"description":729,"fix":730,"retryable":205,"retry":678},404,"Resource not found","The record does not exist, was removed, belongs to a team this key does not read, or was created so recently that Totem has not prepared it yet. A `GET` or `POST` under `\u002Fv1\u002F` that matches no endpoint also gets this code. Any other method, and any path outside `\u002Fv1\u002F`, gets a plain `404` from the firewall in front of the API, with no problem body and no `Totem-Request-Id`.","Check the id and the path. If the record was created moments ago, do not retry in a loop: the changes feed delivers it as soon as it is ready.",{"code":459,"status":727,"title":732,"wireTitle":732,"action":733,"description":734,"fix":735,"retryable":205,"retry":736},"Team not accessible","drop_team","The `Totem-Team` header names a team this key does not read: one it never covered, one removed from the key or from the organization, or one that was deleted. Without the header, it means the key no longer reads any team.","Re-read `GET \u002Fv1\u002Fteams` before you act. If the team is no longer listed, delete its copy and its cursor; if it is still listed, keep everything and try again on the next run.","confirm",{"code":738,"status":739,"title":740,"wireTitle":740,"action":741,"description":742,"fix":743,"retryable":205,"retry":678},"resync_required",409,"Resync required","resync","Totem cannot continue the feed from this cursor: the data was restored from a backup, or a gap was found in the team's changes.","Run a full resync: forget the versions you stored for the team, read the feed again without a cursor, and once it has caught up delete every local record of the team it did not deliver. Keep using your current copy until then.",{"code":462,"status":739,"title":745,"wireTitle":745,"action":746,"description":747,"fix":748,"retryable":210,"retry":749},"Team data is still being prepared","wait_capture","Totem is still preparing this team's data for the API. This happens once per team, after it is first added to any key; adding it to another key later does not repeat it.","Keep whatever you hold for the team and try again in a few minutes; the key's other teams keep syncing meanwhile.","later",{"code":751,"status":752,"title":753,"wireTitle":753,"action":741,"description":754,"fix":755,"retryable":205,"retry":678},"sync_cursor_expired",410,"Sync cursor expired","The cursor is more than 30 days old, counted from the point in the feed it reached (or, while an initial sync is still running, from when that sync started).","Run a full resync, as for `resync_required`. To prevent it, save the `next_cursor` of every page, empty pages included: the cursor of a team you poll regularly never ages out.",{"code":454,"status":757,"title":758,"wireTitle":758,"action":759,"description":760,"fix":761,"retryable":210,"retry":762},429,"Rate limited","retry_after","The key went over its rate limit (items per minute), or too many failed authentication attempts from this IP address or against this key have locked it out for a while.","Wait the seconds in `Retry-After`, then retry the same request. Each request sets aside its full `limit` up front and gives back what it does not use, so a smaller `limit` keeps a nearly spent allowance moving.","after",{"code":463,"status":757,"title":764,"wireTitle":764,"action":759,"description":765,"fix":766,"retryable":210,"retry":762},"Daily quota exceeded","The key has spent its daily quota of items. Every item returned by the changes feed and by every list counts toward it, including `GET \u002Fv1\u002Fteams`, `GET \u002Fv1\u002Fmembers`, `GET \u002Fv1\u002Fbooking_services` and a lead's activities. The quota resets at 00:00 UTC.","Stop syncing until 00:00 UTC (`Retry-After` counts the seconds) and resume then with the same cursor: nothing is lost. Requests for one record, such as `GET \u002Fv1\u002Fleads\u002F{id}`, search and `GET \u002Fv1\u002Fme` do not count toward the quota and keep working.",{"code":455,"status":768,"title":769,"wireTitle":769,"action":770,"description":771,"fix":772,"retryable":210,"retry":770},500,"Internal error","backoff","Something went wrong inside Totem while answering this request.","Retry with exponential backoff. If it keeps failing, contact support and quote the `Totem-Request-Id`.",{"code":456,"status":774,"title":775,"wireTitle":775,"action":770,"description":776,"fix":777,"retryable":210,"retry":770},503,"API disabled","Totem has temporarily switched the API off for every key.","Keep your data and cursors and retry later with exponential backoff.",{"code":457,"status":774,"title":779,"wireTitle":779,"action":770,"description":780,"fix":781,"retryable":210,"retry":770},"Service unavailable","Reserved: the API itself does not return this code today. A `503` from the load balancer or the hosting platform in front of the API arrives without a problem body; treat it like this code.","Retry with exponential backoff; your data and cursors stay valid.",[446,447,448,449,450,451,452,453,454,455,456,457],{"type":784,"title":728,"status":727,"code":558,"request_id":785,"doc_url":784},"https:\u002F\u002Ftotemstudio.ai\u002Fdevelopers\u002Ferrors#resource_missing","req_0f6b2c1e-8d4a-4b7e-9c3f-5a2d1e7b9c40",[787,788,789,790,791,792],{"id":14,"text":15,"depth":203},{"id":369,"text":372,"depth":203},{"id":465,"text":467,"depth":203},{"id":560,"text":562,"depth":203},{"id":422,"text":422,"depth":203},{"id":583,"text":583,"depth":203},{"path":287,"title":288,"section":214},{"path":293,"title":294,"section":214},[796,797,798],{"id":369,"method":370,"path":371,"summary":372},{"id":465,"method":370,"path":466,"summary":467},{"id":560,"method":370,"path":561,"summary":562},1792502789563]