[{"data":1,"prerenderedAt":581},["ShallowReactive",2],{"developers:\u002Fdevelopers\u002Fes\u002Fpagination":3},{"doc":4,"lang":407,"nav":418,"alternatePath":522,"policy":523,"specVersion":567,"reference":7,"layout":568,"toc":569,"prev":578,"next":579,"operations":580,"overview":7,"heroExample":7},{"id":5,"title":6,"apiTag":7,"body":8,"description":404,"draft":405,"extension":406,"lang":407,"meta":408,"navTitle":7,"navigation":409,"order":410,"path":411,"rawbody":412,"section":413,"seo":414,"stem":415,"translationKey":416,"version":7,"__hash__":417},"developers_es\u002Fdevelopers\u002Fes\u002Fpagination.md","Listas y paginación",null,{"type":9,"value":10,"toc":391},"minimark",[11,31,36,39,49,114,136,141,165,174,183,192,199,203,209,213,220,250,256,264,275,279,287,316,333,337,360,364,378,381],[12,13,14,15,23,24,30],"p",{},"Los endpoints de lista, como ",[16,17,19],"a",{"href":18},"\u002Fdevelopers\u002Fes\u002Freference-leads#leads.list",[20,21,22],"code",{},"GET \u002Fv1\u002Fleads"," o ",[16,25,27],{"href":26},"\u002Fdevelopers\u002Fes\u002Freference-calls#calls.list",[20,28,29],{},"GET \u002Fv1\u002Fcalls",", devuelven los registros de un equipo página a página. Esta página explica cómo leer todas las páginas, cómo se ordena y se filtra una lista y qué endpoints no se paginan.",[32,33,35],"h2",{"id":34},"páginas-y-cursores","Páginas y cursores",[12,37,38],{},"Todas las páginas llegan en el mismo sobre de lista:",[40,41,47],"pre",{"className":42,"code":44,"language":45,"meta":46},[43],"language-json","{\n  \"object\": \"list\",\n  \"data\": [\n    {\n      \"id\": \"call_m2kUbFcayHlZ5Lgs9xZNmDS3c3Jvk\",\n      \"object\": \"call\",\n      \"livemode\": false,\n      \"team\": \"team_r9uYrIW4gSFJJ6hZQ9ip1UIpPaAD1CF7NR\",\n      \"lead\": \"lead_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXKSF0QbLS8CiUKJpEP34LFQG\",\n      \"direction\": \"inbound\",\n      \"started_at\": \"2026-09-28T10:17:00.000Z\",\n      \"duration_seconds\": 184,\n      \"outcome\": \"answered_ai\",\n      \"outcome_basis\": \"inbound_verdict\",\n      \"version\": 2,\n      \"updated_at\": \"2026-09-28T10:21:04.010Z\"\n    }\n  ],\n  \"has_more\": true,\n  \"next_cursor\": \"eyJ2IjoxLCJrIjoiY2FsbCIsImEiOiJjYWxsX20ya1ViRmNheUhsWjVMZ3M5eFpObURTM2MzSnZrIiwicyI6ImM0OTk4YTdlNDJkYiJ9357H5Y\"\n}\n","json","",[20,48,44],{"__ignoreMap":46},[50,51,52,68,100],"ul",{},[53,54,55,58,59,63,64,67],"li",{},[20,56,57],{},"limit"," fija el tamaño de la página, de 1 a ",[60,61],"api-const",{"name":62},"PAGE_LIMIT.max",". Por defecto es ",[60,65],{"name":66},"PAGE_LIMIT.default",". Puedes cambiarlo de una página a otra.",[53,69,70,71,74,75,78,79,82,83,86,87,89,90,93,94,89,96,99],{},"Mientras ",[20,72,73],{},"has_more"," sea ",[20,76,77],{},"true",", devuelve ",[20,80,81],{},"next_cursor"," como ",[20,84,85],{},"cursor"," para obtener la página siguiente. En la última página, ",[20,88,73],{}," es ",[20,91,92],{},"false"," y ",[20,95,81],{},[20,97,98],{},"null",".",[53,101,102,103,105,106,109,110,74,112,99],{},"Una página puede traer menos elementos que ",[20,104,57],{},", o ninguno, y aun así indicar ",[20,107,108],{},"has_more: true",". Totem omite los registros que aún no ha preparado y prefiere terminar antes una página a hacerte esperar. Sigue pidiendo hasta que ",[20,111,73],{},[20,113,92],{},[12,115,116,117,120,121,124,125,127,128,130,131,124,133,135],{},"Un cursor es opaco: guárdalo tal como lo recibiste y no construyas ni modifiques ninguno. Solo sirve con el endpoint, los filtros y el equipo de los que salió. Cualquier otro uso recibe ",[20,118,119],{},"400 invalid_request",", con ",[20,122,123],{},"param"," igual a ",[20,126,85],{},". Un cursor de conversaciones también deja de funcionar si se suprime la conversación a la que apunta: si un cursor que no cambiaste recibe ",[20,129,119],{}," con ",[20,132,123],{},[20,134,85],{},", vuelve a empezar esa lista desde la primera página.",[137,138,140],"h3",{"id":139},"lee-todas-las-páginas","Lee todas las páginas",[12,142,143,144,147,148,74,150,152,153,156,157,160,161,164],{},"Para leer una lista entera, mantén los mismos filtros y el mismo ",[20,145,146],{},"Totem-Team"," en cada petición, y para solo cuando ",[20,149,73],{},[20,151,92],{},". Estos bucles listan las llamadas de un equipo con cURL y ",[20,154,155],{},"jq",", con TypeScript en Node.js 22.18 o posterior (un módulo ES, así que ",[20,158,159],{},"await"," funciona en el nivel superior) y con Python y ",[20,162,163],{},"requests",":",[40,166,172],{"className":167,"code":169,"filename":170,"language":171,"meta":46},[168],"language-bash","cursor=\"\"\nwhile :; do\n  page=$(curl -sS --fail-with-body \\\n    \"https:\u002F\u002Fapi.totemstudio.ai\u002Fv1\u002Fcalls?limit=100${cursor:+&cursor=$cursor}\" \\\n    -H \"Authorization: Bearer $TOTEM_API_KEY\" \\\n    -H \"Totem-Team: $TOTEM_TEAM_ID\") || { printf '%s\\n' \"$page\" >&2; break; }\n  printf '%s\\n' \"$page\" | jq -r '.data[].id'\n  [ \"$(printf '%s' \"$page\" | jq -r '.has_more')\" = true ] || break\n  next=$(printf '%s' \"$page\" | jq -er '.next_cursor') || { echo 'La página no trae next_cursor' >&2; break; }\n  [ \"$next\" != \"$cursor\" ] || { echo 'La lista repitió un cursor' >&2; break; }\n  cursor=$next\ndone\n","list-calls.sh","bash",[20,173,169],{"__ignoreMap":46},[40,175,181],{"className":176,"code":178,"filename":179,"language":180,"meta":46},[177],"language-ts","interface CallPage {\n  data: Array\u003C{ id: string }>\n  has_more: boolean\n  next_cursor: string | null\n}\n\nconst apiKey = process.env.TOTEM_API_KEY\nif (!apiKey) throw new Error('Define TOTEM_API_KEY en tu servidor')\nconst headers: Record\u003Cstring, string> = { Authorization: `Bearer ${apiKey}` }\nif (process.env.TOTEM_TEAM_ID) headers['Totem-Team'] = process.env.TOTEM_TEAM_ID\n\nlet cursor: string | null = null\nwhile (true) {\n  const url = new URL('https:\u002F\u002Fapi.totemstudio.ai\u002Fv1\u002Fcalls')\n  url.searchParams.set('limit', '100')\n  if (cursor) url.searchParams.set('cursor', cursor)\n  const response = await fetch(url, { headers, signal: AbortSignal.timeout(30_000) })\n  if (!response.ok) {\n    const problem = (await response.json().catch(() => ({}))) as { code?: string }\n    throw new Error(`Totem API ${response.status} ${problem.code ?? response.statusText}, request ${response.headers.get('Totem-Request-Id') ?? 'n\u002Fa'}`)\n  }\n  const page = (await response.json()) as CallPage\n  \u002F\u002F Aquí va tu código. Muestra identificadores, nunca registros enteros: contienen datos personales.\n  for (const call of page.data) console.log(call.id)\n  if (!page.has_more) break\n  if (!page.next_cursor || page.next_cursor === cursor) throw new Error('La lista no avanzó')\n  cursor = page.next_cursor\n}\n","list-calls.ts","ts",[20,182,178],{"__ignoreMap":46},[40,184,190],{"className":185,"code":187,"filename":188,"language":189,"meta":46},[186],"language-python","# pip install requests\nimport os\n\nimport requests\n\nheaders = {\"Authorization\": f\"Bearer {os.environ['TOTEM_API_KEY']}\"}\nif os.environ.get(\"TOTEM_TEAM_ID\"):\n    headers[\"Totem-Team\"] = os.environ[\"TOTEM_TEAM_ID\"]\n\nparams = {\"limit\": 100}\nwhile True:\n    response = requests.get(\"https:\u002F\u002Fapi.totemstudio.ai\u002Fv1\u002Fcalls\", headers=headers, params=params, timeout=30)\n    if not response.ok:\n        try:\n            code = response.json().get(\"code\")\n        except ValueError:\n            code = None\n        raise RuntimeError(\n            f\"Totem API {response.status_code} {code or response.reason}, \"\n            f\"request {response.headers.get('Totem-Request-Id', 'n\u002Fa')}\"\n        )\n    page = response.json()\n    # Aquí va tu código. Muestra identificadores, nunca registros enteros: contienen datos personales.\n    for call in page[\"data\"]:\n        print(call[\"id\"])\n    if not page[\"has_more\"]:\n        break\n    if not page[\"next_cursor\"] or page[\"next_cursor\"] == params.get(\"cursor\"):\n        raise RuntimeError(\"La lista no avanzó\")\n    params[\"cursor\"] = page[\"next_cursor\"]\n","list_calls.py","python",[20,191,187],{"__ignoreMap":46},[12,193,194,195,99],{},"Cada bucle se detiene también cuando la API responde con un error, o cuando una página repite el cursor que se le pidió, en lugar de pedir la misma página para siempre. Para mantener una copia de un equipo, usa el feed de cambios, como se explica en ",[16,196,198],{"href":197},"#mantener-una-copia","Mantener una copia",[32,200,202],{"id":201},"orden","Orden",[12,204,205,206,99],{},"Una lista llega en un orden estable que no significa nada: no es por fecha ni por nombre. Si necesitas un orden, ordena tú los datos, por ejemplo por ",[20,207,208],{},"created_at",[32,210,212],{"id":211},"filtros","Filtros",[12,214,215,219],{},[16,216,217],{"href":18},[20,218,22],{}," es la única lista con filtros. Admite como máximo uno, con un solo valor:",[50,221,222,232,241],{},[53,223,224,227,228,231],{},[20,225,226],{},"board",": los leads de un tablero (",[20,229,230],{},"brd_…",");",[53,233,234,237,238,231],{},[20,235,236],{},"stage",": los leads de una etapa (",[20,239,240],{},"stg_…",[53,242,243,246,247,99],{},[20,244,245],{},"status",": los leads con un estado, como ",[20,248,249],{},"qualified",[40,251,254],{"className":252,"code":253,"language":171,"meta":46},[168],"curl \"https:\u002F\u002Fapi.totemstudio.ai\u002Fv1\u002Fleads?status=qualified\" \\\n  -H \"Authorization: Bearer $TOTEM_API_KEY\" \\\n  -H \"Totem-Team: $TOTEM_TEAM_ID\"\n",[20,255,253],{"__ignoreMap":46},[12,257,258,259,120,261,263],{},"Dos filtros en una misma petición reciben ",[20,260,119],{},[20,262,123],{}," indicando uno de ellos. Un tablero o una etapa que el equipo no tiene devuelve una página vacía, no un error.",[12,265,266,267,270,271,99],{},"No existe un filtro ",[20,268,269],{},"updated_since",". Para saber qué ha cambiado, usa el feed de cambios, que se explica en ",[16,272,274],{"href":273},"\u002Fdevelopers\u002Fes\u002Fsync","Sincroniza una copia",[32,276,278],{"id":277},"listas-que-llegan-completas","Listas que llegan completas",[12,280,281,282,284,285,164],{},"Tres listas son cortas, así que llegan completas, en una sola respuesta, y no admiten ",[20,283,57],{}," ni ",[20,286,85],{},[50,288,289,298,307],{},[53,290,291,297],{},[16,292,294],{"href":293},"\u002Fdevelopers\u002Fes\u002Freference-account#teams.list",[20,295,296],{},"GET \u002Fv1\u002Fteams",", los equipos que lee tu clave;",[53,299,300,306],{},[16,301,303],{"href":302},"\u002Fdevelopers\u002Fes\u002Freference-account#members.list",[20,304,305],{},"GET \u002Fv1\u002Fmembers",", los miembros de un equipo;",[53,308,309,315],{},[16,310,312],{"href":311},"\u002Fdevelopers\u002Fes\u002Freference-bookings#booking_services.list",[20,313,314],{},"GET \u002Fv1\u002Fbooking_services",", los servicios reservables de un equipo.",[12,317,318,319,93,322,325,326,23,328,330,331,99],{},"Usan el mismo sobre, con ",[20,320,321],{},"has_more: false",[20,323,324],{},"next_cursor: null",". Si envías ",[20,327,57],{},[20,329,85],{}," a alguna de ellas, recibes ",[20,332,119],{},[32,334,336],{"id":335},"la-búsqueda-no-es-una-lista","La búsqueda no es una lista",[12,338,339,345,346,349,350,352,353,93,355,352,357,359],{},[16,340,342],{"href":341},"\u002Fdevelopers\u002Fes\u002Freference-leads#leads.search",[20,343,344],{},"POST \u002Fv1\u002Fleads\u002Fsearch"," busca leads por teléfono o correo electrónico exactos, enviados en el cuerpo JSON. Devuelve como máximo ",[60,347],{"name":348},"SEARCH_MAX_RESULTS"," leads, en una sola respuesta que nunca se pagina: ",[20,351,73],{}," siempre es ",[20,354,92],{},[20,356,81],{},[20,358,98],{},". Si muchos registros comparten un teléfono o una dirección de correo electrónico, puede que la búsqueda no los devuelva todos.",[32,361,363],{"id":362},"registros-que-aún-no-están-listos","Registros que aún no están listos",[12,365,366,367,373,374,377],{},"Totem prepara cada registro para la API poco después de que cambie. Hasta entonces, las listas y la búsqueda omiten un registro nuevo, y una petición de ese registro por su identificador, como ",[16,368,370],{"href":369},"\u002Fdevelopers\u002Fes\u002Freference-leads#leads.get",[20,371,372],{},"GET \u002Fv1\u002Fleads\u002F{id}",", responde ",[20,375,376],{},"404 resource_missing",". No reintentes en bucle: el feed de cambios entrega el registro en cuanto está listo.",[32,379,198],{"id":380},"mantener-una-copia",[12,382,383,384,388,389,99],{},"Una lista muestra los registros tal como están ahora. Sirve para consultar algo, no para mantener una copia: volver a leer todas las listas para encontrar cambios consume mucho más de tu ",[16,385,387],{"href":386},"\u002Fdevelopers\u002Fes\u002Frate-limits","cuota diaria"," y aun así no detecta las eliminaciones. Para mantener una copia de un equipo, sigue el feed de cambios, como explica ",[16,390,274],{"href":273},{"title":46,"searchDepth":392,"depth":392,"links":393},3,[394,398,399,400,401,402,403],{"id":34,"depth":395,"text":35,"children":396},2,[397],{"id":139,"depth":392,"text":140},{"id":201,"depth":395,"text":202},{"id":211,"depth":395,"text":212},{"id":277,"depth":395,"text":278},{"id":335,"depth":395,"text":336},{"id":362,"depth":395,"text":363},{"id":380,"depth":395,"text":198},"Cómo devuelven los endpoints de lista los registros página a página, cómo leer todas las páginas y qué orden y qué filtros admite una lista.",false,"md","es",{},true,"20","\u002Fdevelopers\u002Fes\u002Fpagination","---\ntitle: Listas y paginación\ndescription: Cómo devuelven los endpoints de lista los registros página a página, cómo leer todas las páginas y qué orden y qué filtros admite una lista.\nsection: guides\norder: 20\ntranslationKey: pagination\nlang: es\ndraft: false\n---\n\nLos endpoints de lista, como [`GET \u002Fv1\u002Fleads`](\u002Fdevelopers\u002Fes\u002Freference-leads#leads.list) o [`GET \u002Fv1\u002Fcalls`](\u002Fdevelopers\u002Fes\u002Freference-calls#calls.list), devuelven los registros de un equipo página a página. Esta página explica cómo leer todas las páginas, cómo se ordena y se filtra una lista y qué endpoints no se paginan.\n\n## Páginas y cursores\n\nTodas las páginas llegan en el mismo sobre de lista:\n\n```json\n{\n  \"object\": \"list\",\n  \"data\": [\n    {\n      \"id\": \"call_m2kUbFcayHlZ5Lgs9xZNmDS3c3Jvk\",\n      \"object\": \"call\",\n      \"livemode\": false,\n      \"team\": \"team_r9uYrIW4gSFJJ6hZQ9ip1UIpPaAD1CF7NR\",\n      \"lead\": \"lead_r72EfbRNUzuqORFJR0O8HxAwEXd93jGUTYMaMMXKSF0QbLS8CiUKJpEP34LFQG\",\n      \"direction\": \"inbound\",\n      \"started_at\": \"2026-09-28T10:17:00.000Z\",\n      \"duration_seconds\": 184,\n      \"outcome\": \"answered_ai\",\n      \"outcome_basis\": \"inbound_verdict\",\n      \"version\": 2,\n      \"updated_at\": \"2026-09-28T10:21:04.010Z\"\n    }\n  ],\n  \"has_more\": true,\n  \"next_cursor\": \"eyJ2IjoxLCJrIjoiY2FsbCIsImEiOiJjYWxsX20ya1ViRmNheUhsWjVMZ3M5eFpObURTM2MzSnZrIiwicyI6ImM0OTk4YTdlNDJkYiJ9357H5Y\"\n}\n```\n\n- `limit` fija el tamaño de la página, de 1 a :api-const{name=\"PAGE_LIMIT.max\"}. Por defecto es :api-const{name=\"PAGE_LIMIT.default\"}. Puedes cambiarlo de una página a otra.\n- Mientras `has_more` sea `true`, devuelve `next_cursor` como `cursor` para obtener la página siguiente. En la última página, `has_more` es `false` y `next_cursor` es `null`.\n- Una página puede traer menos elementos que `limit`, o ninguno, y aun así indicar `has_more: true`. Totem omite los registros que aún no ha preparado y prefiere terminar antes una página a hacerte esperar. Sigue pidiendo hasta que `has_more` sea `false`.\n\nUn cursor es opaco: guárdalo tal como lo recibiste y no construyas ni modifiques ninguno. Solo sirve con el endpoint, los filtros y el equipo de los que salió. Cualquier otro uso recibe `400 invalid_request`, con `param` igual a `cursor`. Un cursor de conversaciones también deja de funcionar si se suprime la conversación a la que apunta: si un cursor que no cambiaste recibe `400 invalid_request` con `param` igual a `cursor`, vuelve a empezar esa lista desde la primera página.\n\n### Lee todas las páginas\n\nPara leer una lista entera, mantén los mismos filtros y el mismo `Totem-Team` en cada petición, y para solo cuando `has_more` sea `false`. Estos bucles listan las llamadas de un equipo con cURL y `jq`, con TypeScript en Node.js 22.18 o posterior (un módulo ES, así que `await` funciona en el nivel superior) y con Python y `requests`:\n\n```bash [list-calls.sh]\ncursor=\"\"\nwhile :; do\n  page=$(curl -sS --fail-with-body \\\n    \"https:\u002F\u002Fapi.totemstudio.ai\u002Fv1\u002Fcalls?limit=100${cursor:+&cursor=$cursor}\" \\\n    -H \"Authorization: Bearer $TOTEM_API_KEY\" \\\n    -H \"Totem-Team: $TOTEM_TEAM_ID\") || { printf '%s\\n' \"$page\" >&2; break; }\n  printf '%s\\n' \"$page\" | jq -r '.data[].id'\n  [ \"$(printf '%s' \"$page\" | jq -r '.has_more')\" = true ] || break\n  next=$(printf '%s' \"$page\" | jq -er '.next_cursor') || { echo 'La página no trae next_cursor' >&2; break; }\n  [ \"$next\" != \"$cursor\" ] || { echo 'La lista repitió un cursor' >&2; break; }\n  cursor=$next\ndone\n```\n\n```ts [list-calls.ts]\ninterface CallPage {\n  data: Array\u003C{ id: string }>\n  has_more: boolean\n  next_cursor: string | null\n}\n\nconst apiKey = process.env.TOTEM_API_KEY\nif (!apiKey) throw new Error('Define TOTEM_API_KEY en tu servidor')\nconst headers: Record\u003Cstring, string> = { Authorization: `Bearer ${apiKey}` }\nif (process.env.TOTEM_TEAM_ID) headers['Totem-Team'] = process.env.TOTEM_TEAM_ID\n\nlet cursor: string | null = null\nwhile (true) {\n  const url = new URL('https:\u002F\u002Fapi.totemstudio.ai\u002Fv1\u002Fcalls')\n  url.searchParams.set('limit', '100')\n  if (cursor) url.searchParams.set('cursor', cursor)\n  const response = await fetch(url, { headers, signal: AbortSignal.timeout(30_000) })\n  if (!response.ok) {\n    const problem = (await response.json().catch(() => ({}))) as { code?: string }\n    throw new Error(`Totem API ${response.status} ${problem.code ?? response.statusText}, request ${response.headers.get('Totem-Request-Id') ?? 'n\u002Fa'}`)\n  }\n  const page = (await response.json()) as CallPage\n  \u002F\u002F Aquí va tu código. Muestra identificadores, nunca registros enteros: contienen datos personales.\n  for (const call of page.data) console.log(call.id)\n  if (!page.has_more) break\n  if (!page.next_cursor || page.next_cursor === cursor) throw new Error('La lista no avanzó')\n  cursor = page.next_cursor\n}\n```\n\n```python [list_calls.py]\n# pip install requests\nimport os\n\nimport requests\n\nheaders = {\"Authorization\": f\"Bearer {os.environ['TOTEM_API_KEY']}\"}\nif os.environ.get(\"TOTEM_TEAM_ID\"):\n    headers[\"Totem-Team\"] = os.environ[\"TOTEM_TEAM_ID\"]\n\nparams = {\"limit\": 100}\nwhile True:\n    response = requests.get(\"https:\u002F\u002Fapi.totemstudio.ai\u002Fv1\u002Fcalls\", headers=headers, params=params, timeout=30)\n    if not response.ok:\n        try:\n            code = response.json().get(\"code\")\n        except ValueError:\n            code = None\n        raise RuntimeError(\n            f\"Totem API {response.status_code} {code or response.reason}, \"\n            f\"request {response.headers.get('Totem-Request-Id', 'n\u002Fa')}\"\n        )\n    page = response.json()\n    # Aquí va tu código. Muestra identificadores, nunca registros enteros: contienen datos personales.\n    for call in page[\"data\"]:\n        print(call[\"id\"])\n    if not page[\"has_more\"]:\n        break\n    if not page[\"next_cursor\"] or page[\"next_cursor\"] == params.get(\"cursor\"):\n        raise RuntimeError(\"La lista no avanzó\")\n    params[\"cursor\"] = page[\"next_cursor\"]\n```\n\nCada bucle se detiene también cuando la API responde con un error, o cuando una página repite el cursor que se le pidió, en lugar de pedir la misma página para siempre. Para mantener una copia de un equipo, usa el feed de cambios, como se explica en [Mantener una copia](#mantener-una-copia).\n\n## Orden\n\nUna lista llega en un orden estable que no significa nada: no es por fecha ni por nombre. Si necesitas un orden, ordena tú los datos, por ejemplo por `created_at`.\n\n## Filtros\n\n[`GET \u002Fv1\u002Fleads`](\u002Fdevelopers\u002Fes\u002Freference-leads#leads.list) es la única lista con filtros. Admite como máximo uno, con un solo valor:\n\n- `board`: los leads de un tablero (`brd_…`);\n- `stage`: los leads de una etapa (`stg_…`);\n- `status`: los leads con un estado, como `qualified`.\n\n```bash\ncurl \"https:\u002F\u002Fapi.totemstudio.ai\u002Fv1\u002Fleads?status=qualified\" \\\n  -H \"Authorization: Bearer $TOTEM_API_KEY\" \\\n  -H \"Totem-Team: $TOTEM_TEAM_ID\"\n```\n\nDos filtros en una misma petición reciben `400 invalid_request`, con `param` indicando uno de ellos. Un tablero o una etapa que el equipo no tiene devuelve una página vacía, no un error.\n\nNo existe un filtro `updated_since`. Para saber qué ha cambiado, usa el feed de cambios, que se explica en [Sincroniza una copia](\u002Fdevelopers\u002Fes\u002Fsync).\n\n## Listas que llegan completas\n\nTres listas son cortas, así que llegan completas, en una sola respuesta, y no admiten `limit` ni `cursor`:\n\n- [`GET \u002Fv1\u002Fteams`](\u002Fdevelopers\u002Fes\u002Freference-account#teams.list), los equipos que lee tu clave;\n- [`GET \u002Fv1\u002Fmembers`](\u002Fdevelopers\u002Fes\u002Freference-account#members.list), los miembros de un equipo;\n- [`GET \u002Fv1\u002Fbooking_services`](\u002Fdevelopers\u002Fes\u002Freference-bookings#booking_services.list), los servicios reservables de un equipo.\n\nUsan el mismo sobre, con `has_more: false` y `next_cursor: null`. Si envías `limit` o `cursor` a alguna de ellas, recibes `400 invalid_request`.\n\n## La búsqueda no es una lista\n\n[`POST \u002Fv1\u002Fleads\u002Fsearch`](\u002Fdevelopers\u002Fes\u002Freference-leads#leads.search) busca leads por teléfono o correo electrónico exactos, enviados en el cuerpo JSON. Devuelve como máximo :api-const{name=\"SEARCH_MAX_RESULTS\"} leads, en una sola respuesta que nunca se pagina: `has_more` siempre es `false` y `next_cursor` siempre es `null`. Si muchos registros comparten un teléfono o una dirección de correo electrónico, puede que la búsqueda no los devuelva todos.\n\n## Registros que aún no están listos\n\nTotem prepara cada registro para la API poco después de que cambie. Hasta entonces, las listas y la búsqueda omiten un registro nuevo, y una petición de ese registro por su identificador, como [`GET \u002Fv1\u002Fleads\u002F{id}`](\u002Fdevelopers\u002Fes\u002Freference-leads#leads.get), responde `404 resource_missing`. No reintentes en bucle: el feed de cambios entrega el registro en cuanto está listo.\n\n## Mantener una copia\n\nUna lista muestra los registros tal como están ahora. Sirve para consultar algo, no para mantener una copia: volver a leer todas las listas para encontrar cambios consume mucho más de tu [cuota diaria](\u002Fdevelopers\u002Fes\u002Frate-limits) y aun así no detecta las eliminaciones. Para mantener una copia de un equipo, sigue el feed de cambios, como explica [Sincroniza una copia](\u002Fdevelopers\u002Fes\u002Fsync).\n","guides",{"title":6,"description":404},"developers\u002Fes\u002Fpagination","pagination","QX0WcrryuZrJgz-nQ-2I_nLeXKzmRxVxfINo3AjlZ_c",[419,434,455,503],{"section":420,"items":421},"start",[422,426,430],{"path":423,"title":424,"description":425},"\u002Fdevelopers\u002Fes","Introducción","Lee desde tus propios sistemas los leads, las llamadas, las conversaciones y las citas de tus equipos de Totem, y mantén una copia sincronizada.",{"path":427,"title":428,"description":429},"\u002Fdevelopers\u002Fes\u002Fquickstart","Inicio rápido","Haz tus primeras peticiones a la API de Totem en unos minutos. Comprueba tu clave, busca tu equipo, lista leads e inicia una sincronización.",{"path":431,"title":432,"description":433},"\u002Fdevelopers\u002Fes\u002Fauthentication","Autenticación","Las claves secretas y dónde pueden guardarse, la cabecera Totem-Team de las claves con varios equipos, la lista de IP permitidas y cómo rotar o revocar una clave.",{"section":413,"items":435},[436,440,442,443,447,451],{"path":437,"title":438,"description":439},"\u002Fdevelopers\u002Fes\u002Ftypescript","SDK de TypeScript","Usa el cliente oficial de TypeScript para leer tus datos de Totem, paginar listas y gestionar errores de la API desde tu servidor.",{"path":273,"title":274,"description":441},"Copia un equipo con el feed de cambios y mantén la copia al día. Aplica las páginas sin riesgos, recupérate de los errores y parte de un cliente de referencia que Totem prueba.",{"path":411,"title":6,"description":404},{"path":444,"title":445,"description":446},"\u002Fdevelopers\u002Fes\u002Fcoverage","Cobertura de los datos","Qué registra Totem, desde cuándo y cómo distinguir un valor vacío de un dato que nunca se registró.",{"path":448,"title":449,"description":450},"\u002Fdevelopers\u002Fes\u002Ftesting","Pruebas y puesta en producción","Cómo construir y probar una integración con seguridad mientras la API no tiene entorno de pruebas, y qué comprobar antes de pasar a producción.",{"path":452,"title":453,"description":454},"\u002Fdevelopers\u002Fes\u002Fsecurity","Seguridad y datos personales","Cómo protege Totem las claves de la API y los datos que sirve, qué registra de cada clave, dónde funciona la API y qué hacer con los datos personales que copias.",{"section":456,"items":457},"reference",[458,462,466,469,474,479,484,489,494,499],{"path":459,"title":460,"description":461},"\u002Fdevelopers\u002Fes\u002Fconventions","Convenciones","La notación de esta documentación y las reglas que siguen todas las respuestas: identificadores, fechas, valores vacíos, importes, enumeraciones, versiones, estabilidad, errores y textos no fiables.",{"path":463,"title":464,"description":465},"\u002Fdevelopers\u002Fes\u002Ferrors","Errores","El formato de los errores, cómo debe tratar tu integración cada tipo de error y todos los códigos de error, con cuándo ocurren y qué hacer.",{"path":386,"title":467,"description":468},"Límites de frecuencia y cuota","Cuánto puede leer una clave por minuto y por día, qué cuenta para cada límite, cómo reintentar tras un 429 y cuánto tarda una carga inicial.",{"path":470,"title":471,"description":472,"apiTag":473},"\u002Fdevelopers\u002Fes\u002Freference-account","Cuenta, equipos y miembros","Comprueba que una clave funciona y qué puede leer, lista sus equipos con su zona horaria, lista los miembros de cada equipo y comprueba que la API está funcionando.","account",{"path":475,"title":476,"description":477,"apiTag":478},"\u002Fdevelopers\u002Fes\u002Freference-leads","Leads, tableros y actividades","Lista, obtén y busca los leads y los clientes de un equipo, lee las actividades de cada lead y lista los tableros y las etapas por los que pasan.","leads",{"path":480,"title":481,"description":482,"apiTag":483},"\u002Fdevelopers\u002Fes\u002Freference-calls","Llamadas","Lista y obtén las llamadas de un equipo, con su dirección, su horario y un resultado normalizado. Sin grabaciones ni transcripciones.","calls",{"path":485,"title":486,"description":487,"apiTag":488},"\u002Fdevelopers\u002Fes\u002Freference-conversations","Conversaciones","Lista y obtén las conversaciones de un equipo en todos los canales, con su estado, la persona asignada, si una persona ha tomado el control y cuándo llegaron y salieron los últimos mensajes. Nunca el contenido de los mensajes.","conversations",{"path":490,"title":491,"description":492,"apiTag":493},"\u002Fdevelopers\u002Fes\u002Freference-bookings","Citas y servicios","Lista y obtén las citas de un equipo, y lista los servicios que pueden reservar sus clientes.","bookings",{"path":495,"title":496,"description":497,"apiTag":498},"\u002Fdevelopers\u002Fes\u002Freference-sync","Feed de cambios","Un único endpoint que copia un equipo y, después, devuelve cada cambio, página a página.","sync",{"path":500,"title":501,"description":502},"\u002Fdevelopers\u002Fes\u002Fobjects","Todos los objetos","Todos los objetos que devuelve la API, campo a campo, con un ejemplo de cada uno.",{"section":504,"items":505},"resources",[506,510,514,518],{"path":507,"title":508,"description":509},"\u002Fdevelopers\u002Fes\u002Fchangelog","Registro de cambios","Los cambios de la API de Totem, del más reciente al más antiguo, cada uno bajo la fecha en que se publicó.",{"path":511,"title":512,"description":513},"\u002Fdevelopers\u002Fes\u002Fsupport","Soporte","Cómo pedir ayuda con la API de Totem, qué incluir en una solicitud y qué hacer si se filtra una clave.",{"path":515,"title":516,"description":517},"\u002Fdevelopers\u002Fes\u002Fglossary","Glosario","Los términos de esta documentación, definidos en un solo lugar, cada uno con un enlace a la página que lo explica.",{"path":519,"title":520,"description":521},"\u002Fdevelopers\u002Fes\u002Ffaq","Preguntas frecuentes","Respuestas breves a las preguntas más habituales sobre la API de Totem, con enlaces a los detalles.","\u002Fdevelopers\u002Fpagination",{"ACTIVATION_MARGIN_MS":524,"ADMIN_ACCESS_DISCLOSURE_VERSION":525,"AUDIT_RETENTION_DAYS":526,"AUTH_FAILURE_LIMITS":527,"CAPTURE_LAG_FLOOR_MS":531,"CAPTURE_LAG_P99_MS":7,"CURSOR_MAX_AGE_DAYS":532,"DIRTY_TTL_DAYS":532,"FAMILY_TEAM_SCOPE":533,"FAMILY_TEAM_SCOPE_OPTIONS":534,"FEED_SETTLE_LAG_MS":536,"GATE_REFRESH_MS":524,"INTEGRATION_NAME_LENGTH":537,"INTEGRATION_PURPOSE_LENGTH":539,"KEY_CACHE_TTL_MS":542,"KEY_STATS_RETENTION_DAYS":543,"LEAD_RESPONSE_READ_BUDGET":544,"LIST_SCAN_MAX":547,"MAX_FAMILY_INTEGRATION_TEAMS":532,"MAX_INTEGRATIONS_PER_FAMILY":548,"MAX_IP_ALLOWLIST":529,"PAGE_LIMIT":549,"PLATFORM_CONFIG_TTL_MS":552,"REMOVAL_RETENTION_DAYS":553,"REQUEST_BODY_MAX_BYTES":554,"ROLL_GRACE_DEFAULT_HOURS":555,"ROLL_GRACE_HOURS":556,"SEARCH_MAX_RESULTS":548,"SENSITIVE_SECTOR_POLICY":559,"SENSITIVE_SECTOR_POLICY_OPTIONS":560,"SYNC_DAILY_BUDGET":562,"SYNC_VELOCITY":564,"TEAM_CACHE_TTL_MS":566},60000,"2026-10-17",365,{"perIpPerMinute":528,"perLookupIdPerMinute":529,"banMs":530},60,20,600000,300000,30,"explicit_list",[533,535],"all_family_teams",10000,{"min":395,"max":538},80,{"min":540,"max":541},1,280,5000,90,{"conversations":529,"messageReads":545,"calls":546},200,50,1000,10,{"default":550,"max":551},25,100,15000,45,16384,24,[557,540,555,558],0,168,"exclude",[559,561],"allow",{"floor":563,"recordsMultiplier":392},250000,{"perMinute":565,"burst":536},2000,30000,"1.0a","guide",[570,571,572,573,574,575,576,577],{"id":34,"text":35,"depth":395},{"id":139,"text":140,"depth":392},{"id":201,"text":202,"depth":395},{"id":211,"text":212,"depth":395},{"id":277,"text":278,"depth":395},{"id":335,"text":336,"depth":395},{"id":362,"text":363,"depth":395},{"id":380,"text":198,"depth":395},{"path":273,"title":274,"section":413},{"path":444,"title":445,"section":413},[],1792502790571]