[{"data":1,"prerenderedAt":1986},["ShallowReactive",2],{"docs:/docs/concepts/webhooks":3},{"id":4,"title":5,"body":6,"description":1979,"extension":1980,"meta":1981,"navigation":996,"path":1982,"seo":1983,"stem":1984,"__hash__":1985},"docs/docs/concepts/webhooks.md","Webhooks",{"type":7,"value":8,"toc":1960},"minimark",[9,13,17,34,39,44,47,52,176,186,190,197,304,308,311,314,435,438,441,445,451,483,487,491,506,510,820,824,827,848,859,863,866,870,892,896,899,916,920,923,927,962,966,969,1943,1950,1956],[10,11,5],"h1",{"id":12},"webhooks",[14,15,16],"p",{},"Webhooks allow your external systems to react to NoLag events. Configure per-topic webhooks to pre-populate state when actors subscribe, and trigger external workflows when messages are published. Webhook payloads include the actor's access scope for automatic multi-tenant isolation.",[18,19,21,27],"callout",{"type":20},"info",[14,22,23],{},[24,25,26],"strong",{},"Key Concept",[14,28,29,30,33],{},"Webhooks are configured ",[24,31,32],{},"per topic"," within your app's topic settings. Different topics can trigger different endpoints, giving you fine-grained control over integrations.",[35,36,38],"h2",{"id":37},"webhook-types","Webhook Types",[40,41,43],"h3",{"id":42},"hydration-webhook","Hydration Webhook",[14,45,46],{},"Called when an actor subscribes to a topic. Use this to pre-populate the actor's state with current data (e.g., recent messages, current game state, latest prices).",[48,49,51],"h4",{"id":50},"request-format","Request Format",[53,54,55],"code-tabs",{},[56,57,63],"pre",{"className":58,"code":59,"filename":60,"language":61,"meta":62,"style":62},"language-json shiki shiki-themes github-light github-dark","{\n  \"actorId\": \"act_xxx\",\n  \"roomName\": \"general-chat\",\n  \"topicName\": \"messages\",\n  \"scope\": {\n    \"accessScopeId\": \"01939f83-8b57-...\",\n    \"slug\": \"client-acme\",\n    \"name\": \"Acme Corp\"\n  }\n}\n","JSON","json","",[64,65,66,75,92,105,118,127,140,153,164,170],"code",{"__ignoreMap":62},[67,68,71],"span",{"class":69,"line":70},"line",1,[67,72,74],{"class":73},"sVt8B","{\n",[67,76,78,82,85,89],{"class":69,"line":77},2,[67,79,81],{"class":80},"sj4cs","  \"actorId\"",[67,83,84],{"class":73},": ",[67,86,88],{"class":87},"sZZnC","\"act_xxx\"",[67,90,91],{"class":73},",\n",[67,93,95,98,100,103],{"class":69,"line":94},3,[67,96,97],{"class":80},"  \"roomName\"",[67,99,84],{"class":73},[67,101,102],{"class":87},"\"general-chat\"",[67,104,91],{"class":73},[67,106,108,111,113,116],{"class":69,"line":107},4,[67,109,110],{"class":80},"  \"topicName\"",[67,112,84],{"class":73},[67,114,115],{"class":87},"\"messages\"",[67,117,91],{"class":73},[67,119,121,124],{"class":69,"line":120},5,[67,122,123],{"class":80},"  \"scope\"",[67,125,126],{"class":73},": {\n",[67,128,130,133,135,138],{"class":69,"line":129},6,[67,131,132],{"class":80},"    \"accessScopeId\"",[67,134,84],{"class":73},[67,136,137],{"class":87},"\"01939f83-8b57-...\"",[67,139,91],{"class":73},[67,141,143,146,148,151],{"class":69,"line":142},7,[67,144,145],{"class":80},"    \"slug\"",[67,147,84],{"class":73},[67,149,150],{"class":87},"\"client-acme\"",[67,152,91],{"class":73},[67,154,156,159,161],{"class":69,"line":155},8,[67,157,158],{"class":80},"    \"name\"",[67,160,84],{"class":73},[67,162,163],{"class":87},"\"Acme Corp\"\n",[67,165,167],{"class":69,"line":166},9,[67,168,169],{"class":73},"  }\n",[67,171,173],{"class":69,"line":172},10,[67,174,175],{"class":73},"}\n",[14,177,178,181,182,185],{},[64,179,180],{},"scope"," is ",[64,183,184],{},"null"," for unscoped actors, or an object with the actor's access scope details for multi-tenant routing.",[48,187,189],{"id":188},"response","Response",[14,191,192,193,196],{},"Return any JSON data. This will be forwarded to the subscribing actor as a ",[64,194,195],{},"hydration"," message.",[53,198,199],{},[56,200,202],{"className":58,"code":201,"filename":60,"language":61,"meta":62,"style":62},"{\n  \"recentMessages\": [\n    { \"from\": \"alice\", \"text\": \"Hello!\", \"timestamp\": 1234567890 },\n    { \"from\": \"bob\", \"text\": \"Hi there!\", \"timestamp\": 1234567891 }\n  ],\n  \"participantCount\": 5\n}\n",[64,203,204,208,216,253,285,290,300],{"__ignoreMap":62},[67,205,206],{"class":69,"line":70},[67,207,74],{"class":73},[67,209,210,213],{"class":69,"line":77},[67,211,212],{"class":80},"  \"recentMessages\"",[67,214,215],{"class":73},": [\n",[67,217,218,221,224,226,229,232,235,237,240,242,245,247,250],{"class":69,"line":94},[67,219,220],{"class":73},"    { ",[67,222,223],{"class":80},"\"from\"",[67,225,84],{"class":73},[67,227,228],{"class":87},"\"alice\"",[67,230,231],{"class":73},", ",[67,233,234],{"class":80},"\"text\"",[67,236,84],{"class":73},[67,238,239],{"class":87},"\"Hello!\"",[67,241,231],{"class":73},[67,243,244],{"class":80},"\"timestamp\"",[67,246,84],{"class":73},[67,248,249],{"class":80},"1234567890",[67,251,252],{"class":73}," },\n",[67,254,255,257,259,261,264,266,268,270,273,275,277,279,282],{"class":69,"line":107},[67,256,220],{"class":73},[67,258,223],{"class":80},[67,260,84],{"class":73},[67,262,263],{"class":87},"\"bob\"",[67,265,231],{"class":73},[67,267,234],{"class":80},[67,269,84],{"class":73},[67,271,272],{"class":87},"\"Hi there!\"",[67,274,231],{"class":73},[67,276,244],{"class":80},[67,278,84],{"class":73},[67,280,281],{"class":80},"1234567891",[67,283,284],{"class":73}," }\n",[67,286,287],{"class":69,"line":120},[67,288,289],{"class":73},"  ],\n",[67,291,292,295,297],{"class":69,"line":129},[67,293,294],{"class":80},"  \"participantCount\"",[67,296,84],{"class":73},[67,298,299],{"class":80},"5\n",[67,301,302],{"class":69,"line":142},[67,303,175],{"class":73},[40,305,307],{"id":306},"trigger-webhook","Trigger Webhook",[14,309,310],{},"Called when an actor publishes data to a topic. Use this to trigger external workflows, store messages, send notifications, or integrate with third-party services.",[48,312,51],{"id":313},"request-format-1",[53,315,316],{},[56,317,319],{"className":58,"code":318,"filename":60,"language":61,"meta":62,"style":62},"{\n  \"roomName\": \"general-chat\",\n  \"topicName\": \"messages\",\n  \"actorId\": \"act_xxx\",\n  \"data\": {\n    \"text\": \"Hello everyone!\",\n    \"timestamp\": 1234567890\n  },\n  \"scope\": {\n    \"accessScopeId\": \"01939f83-8b57-...\",\n    \"slug\": \"client-acme\",\n    \"name\": \"Acme Corp\"\n  }\n}\n",[64,320,321,325,335,345,355,362,374,384,389,395,405,416,425,430],{"__ignoreMap":62},[67,322,323],{"class":69,"line":70},[67,324,74],{"class":73},[67,326,327,329,331,333],{"class":69,"line":77},[67,328,97],{"class":80},[67,330,84],{"class":73},[67,332,102],{"class":87},[67,334,91],{"class":73},[67,336,337,339,341,343],{"class":69,"line":94},[67,338,110],{"class":80},[67,340,84],{"class":73},[67,342,115],{"class":87},[67,344,91],{"class":73},[67,346,347,349,351,353],{"class":69,"line":107},[67,348,81],{"class":80},[67,350,84],{"class":73},[67,352,88],{"class":87},[67,354,91],{"class":73},[67,356,357,360],{"class":69,"line":120},[67,358,359],{"class":80},"  \"data\"",[67,361,126],{"class":73},[67,363,364,367,369,372],{"class":69,"line":129},[67,365,366],{"class":80},"    \"text\"",[67,368,84],{"class":73},[67,370,371],{"class":87},"\"Hello everyone!\"",[67,373,91],{"class":73},[67,375,376,379,381],{"class":69,"line":142},[67,377,378],{"class":80},"    \"timestamp\"",[67,380,84],{"class":73},[67,382,383],{"class":80},"1234567890\n",[67,385,386],{"class":69,"line":155},[67,387,388],{"class":73},"  },\n",[67,390,391,393],{"class":69,"line":166},[67,392,123],{"class":80},[67,394,126],{"class":73},[67,396,397,399,401,403],{"class":69,"line":172},[67,398,132],{"class":80},[67,400,84],{"class":73},[67,402,137],{"class":87},[67,404,91],{"class":73},[67,406,408,410,412,414],{"class":69,"line":407},11,[67,409,145],{"class":80},[67,411,84],{"class":73},[67,413,150],{"class":87},[67,415,91],{"class":73},[67,417,419,421,423],{"class":69,"line":418},12,[67,420,158],{"class":80},[67,422,84],{"class":73},[67,424,163],{"class":87},[67,426,428],{"class":69,"line":427},13,[67,429,169],{"class":73},[67,431,433],{"class":69,"line":432},14,[67,434,175],{"class":73},[48,436,189],{"id":437},"response-1",[14,439,440],{},"Return any 2xx status code to acknowledge receipt. The response body is ignored.",[35,442,444],{"id":443},"scope-in-payloads","Scope in Payloads",[14,446,447,448,450],{},"All webhook payloads include a ",[64,449,180],{}," field containing the actor's access scope information. This allows your backend to route requests to the correct tenant without additional lookups.",[452,453,454,474],"ul",{},[455,456,457,460,461,463,464,231,467,470,471],"li",{},[24,458,459],{},"Scoped actors:"," ",[64,462,180],{}," contains ",[64,465,466],{},"accessScopeId",[64,468,469],{},"slug",", and ",[64,472,473],{},"name",[455,475,476,460,479,181,481],{},[24,477,478],{},"Unscoped actors:",[64,480,180],{},[64,482,184],{},[35,484,486],{"id":485},"configuration","Configuration",[40,488,490],{"id":489},"via-dashboard","Via Dashboard",[492,493,494,497,500,503],"ol",{},[455,495,496],{},"Navigate to your App's \"Webhooks\" page",[455,498,499],{},"Click on a topic to expand its webhook settings",[455,501,502],{},"Configure the On Subscribe (hydration) and/or On Publish (trigger) webhook URLs and headers",[455,504,505],{},"Save changes for that topic",[40,507,509],{"id":508},"via-rest-api","Via REST API",[53,511,512,626,733],{},[56,513,518],{"className":514,"code":515,"filename":516,"language":517,"meta":62,"style":62},"language-typescript shiki shiki-themes github-light github-dark","// Webhooks are configured per topic through the NoLag Dashboard\n// or via the REST API using topicConfigs:\n//\n// PATCH /v1/organizations/{orgId}/projects/{projId}/apps/{appId}\n// {\n//   \"topicConfigs\": {\n//     \"messages\": {\n//       \"webhooks\": {\n//         \"onSubscribe\": {\n//           \"url\": \"https://api.example.com/hydrate\",\n//           \"headers\": { \"Authorization\": \"Bearer xxx\" }\n//         },\n//         \"onPublish\": {\n//           \"url\": \"https://api.example.com/trigger\",\n//           \"headers\": { \"Authorization\": \"Bearer xxx\" }\n//         }\n//       }\n//     }\n//   }\n// }\n","TypeScript","typescript",[64,519,520,526,531,536,541,546,551,556,561,566,571,576,581,586,591,596,602,608,614,620],{"__ignoreMap":62},[67,521,522],{"class":69,"line":70},[67,523,525],{"class":524},"sJ8bj","// Webhooks are configured per topic through the NoLag Dashboard\n",[67,527,528],{"class":69,"line":77},[67,529,530],{"class":524},"// or via the REST API using topicConfigs:\n",[67,532,533],{"class":69,"line":94},[67,534,535],{"class":524},"//\n",[67,537,538],{"class":69,"line":107},[67,539,540],{"class":524},"// PATCH /v1/organizations/{orgId}/projects/{projId}/apps/{appId}\n",[67,542,543],{"class":69,"line":120},[67,544,545],{"class":524},"// {\n",[67,547,548],{"class":69,"line":129},[67,549,550],{"class":524},"//   \"topicConfigs\": {\n",[67,552,553],{"class":69,"line":142},[67,554,555],{"class":524},"//     \"messages\": {\n",[67,557,558],{"class":69,"line":155},[67,559,560],{"class":524},"//       \"webhooks\": {\n",[67,562,563],{"class":69,"line":166},[67,564,565],{"class":524},"//         \"onSubscribe\": {\n",[67,567,568],{"class":69,"line":172},[67,569,570],{"class":524},"//           \"url\": \"https://api.example.com/hydrate\",\n",[67,572,573],{"class":69,"line":407},[67,574,575],{"class":524},"//           \"headers\": { \"Authorization\": \"Bearer xxx\" }\n",[67,577,578],{"class":69,"line":418},[67,579,580],{"class":524},"//         },\n",[67,582,583],{"class":69,"line":427},[67,584,585],{"class":524},"//         \"onPublish\": {\n",[67,587,588],{"class":69,"line":432},[67,589,590],{"class":524},"//           \"url\": \"https://api.example.com/trigger\",\n",[67,592,594],{"class":69,"line":593},15,[67,595,575],{"class":524},[67,597,599],{"class":69,"line":598},16,[67,600,601],{"class":524},"//         }\n",[67,603,605],{"class":69,"line":604},17,[67,606,607],{"class":524},"//       }\n",[67,609,611],{"class":69,"line":610},18,[67,612,613],{"class":524},"//     }\n",[67,615,617],{"class":69,"line":616},19,[67,618,619],{"class":524},"//   }\n",[67,621,623],{"class":69,"line":622},20,[67,624,625],{"class":524},"// }\n",[56,627,632],{"className":628,"code":629,"filename":630,"language":631,"meta":62,"style":62},"language-python shiki shiki-themes github-light github-dark","# Webhooks are configured per topic through the NoLag Dashboard\n# or via the REST API using topicConfigs:\n#\n# PATCH /v1/organizations/{orgId}/projects/{projId}/apps/{appId}\n# {\n#   \"topicConfigs\": {\n#     \"messages\": {\n#       \"webhooks\": {\n#         \"onSubscribe\": {\n#           \"url\": \"https://api.example.com/hydrate\",\n#           \"headers\": { \"Authorization\": \"Bearer xxx\" }\n#         },\n#         \"onPublish\": {\n#           \"url\": \"https://api.example.com/trigger\",\n#           \"headers\": { \"Authorization\": \"Bearer xxx\" }\n#         }\n#       }\n#     }\n#   }\n# }\n","Python","python",[64,633,634,639,644,649,654,659,664,669,674,679,684,689,694,699,704,708,713,718,723,728],{"__ignoreMap":62},[67,635,636],{"class":69,"line":70},[67,637,638],{},"# Webhooks are configured per topic through the NoLag Dashboard\n",[67,640,641],{"class":69,"line":77},[67,642,643],{},"# or via the REST API using topicConfigs:\n",[67,645,646],{"class":69,"line":94},[67,647,648],{},"#\n",[67,650,651],{"class":69,"line":107},[67,652,653],{},"# PATCH /v1/organizations/{orgId}/projects/{projId}/apps/{appId}\n",[67,655,656],{"class":69,"line":120},[67,657,658],{},"# {\n",[67,660,661],{"class":69,"line":129},[67,662,663],{},"#   \"topicConfigs\": {\n",[67,665,666],{"class":69,"line":142},[67,667,668],{},"#     \"messages\": {\n",[67,670,671],{"class":69,"line":155},[67,672,673],{},"#       \"webhooks\": {\n",[67,675,676],{"class":69,"line":166},[67,677,678],{},"#         \"onSubscribe\": {\n",[67,680,681],{"class":69,"line":172},[67,682,683],{},"#           \"url\": \"https://api.example.com/hydrate\",\n",[67,685,686],{"class":69,"line":407},[67,687,688],{},"#           \"headers\": { \"Authorization\": \"Bearer xxx\" }\n",[67,690,691],{"class":69,"line":418},[67,692,693],{},"#         },\n",[67,695,696],{"class":69,"line":427},[67,697,698],{},"#         \"onPublish\": {\n",[67,700,701],{"class":69,"line":432},[67,702,703],{},"#           \"url\": \"https://api.example.com/trigger\",\n",[67,705,706],{"class":69,"line":593},[67,707,688],{},[67,709,710],{"class":69,"line":598},[67,711,712],{},"#         }\n",[67,714,715],{"class":69,"line":604},[67,716,717],{},"#       }\n",[67,719,720],{"class":69,"line":610},[67,721,722],{},"#     }\n",[67,724,725],{"class":69,"line":616},[67,726,727],{},"#   }\n",[67,729,730],{"class":69,"line":622},[67,731,732],{},"# }\n",[56,734,738],{"className":735,"code":515,"filename":736,"language":737,"meta":62,"style":62},"language-go shiki shiki-themes github-light github-dark","Go","go",[64,739,740,744,748,752,756,760,764,768,772,776,780,784,788,792,796,800,804,808,812,816],{"__ignoreMap":62},[67,741,742],{"class":69,"line":70},[67,743,525],{},[67,745,746],{"class":69,"line":77},[67,747,530],{},[67,749,750],{"class":69,"line":94},[67,751,535],{},[67,753,754],{"class":69,"line":107},[67,755,540],{},[67,757,758],{"class":69,"line":120},[67,759,545],{},[67,761,762],{"class":69,"line":129},[67,763,550],{},[67,765,766],{"class":69,"line":142},[67,767,555],{},[67,769,770],{"class":69,"line":155},[67,771,560],{},[67,773,774],{"class":69,"line":166},[67,775,565],{},[67,777,778],{"class":69,"line":172},[67,779,570],{},[67,781,782],{"class":69,"line":407},[67,783,575],{},[67,785,786],{"class":69,"line":418},[67,787,580],{},[67,789,790],{"class":69,"line":427},[67,791,585],{},[67,793,794],{"class":69,"line":432},[67,795,590],{},[67,797,798],{"class":69,"line":593},[67,799,575],{},[67,801,802],{"class":69,"line":598},[67,803,601],{},[67,805,806],{"class":69,"line":604},[67,807,607],{},[67,809,810],{"class":69,"line":610},[67,811,613],{},[67,813,814],{"class":69,"line":616},[67,815,619],{},[67,817,818],{"class":69,"line":622},[67,819,625],{},[35,821,823],{"id":822},"authentication","Authentication",[14,825,826],{},"Webhooks support two authentication methods:",[452,828,829,838],{},[455,830,831,834,835],{},[24,832,833],{},"Query Parameters"," - Add auth tokens directly in the URL: ",[64,836,837],{},"https://api.example.com/webhook?api_key=xxx",[455,839,840,843,844,847],{},[24,841,842],{},"Request Headers"," - Add custom headers like ",[64,845,846],{},"Authorization"," or API key headers",[18,849,851,856],{"type":850},"warning",[14,852,853],{},[24,854,855],{},"Security Note",[14,857,858],{},"Always use HTTPS for webhook URLs. Webhook headers are stored encrypted at rest.",[35,860,862],{"id":861},"dead-letter-queue-dlq","Dead Letter Queue (DLQ)",[14,864,865],{},"When a webhook call fails after all retry attempts, the failed request is stored in the Dead Letter Queue. You can view and retry these failed requests from the dashboard.",[40,867,869],{"id":868},"retry-behavior","Retry Behavior",[452,871,872,879,882,885],{},[455,873,874,875,878],{},"Webhooks are retried up to ",[24,876,877],{},"3 times"," with exponential backoff",[455,880,881],{},"Server errors (5xx) and network errors trigger retries",[455,883,884],{},"Client errors (4xx) do not trigger retries",[455,886,887,888,891],{},"Timeout is ",[24,889,890],{},"30 seconds"," per request",[40,893,895],{"id":894},"dlq-entry-contents","DLQ Entry Contents",[14,897,898],{},"Each DLQ entry contains:",[452,900,901,904,907,910,913],{},[455,902,903],{},"Original webhook URL",[455,905,906],{},"Request headers and body",[455,908,909],{},"Response status code (if received)",[455,911,912],{},"Error message",[455,914,915],{},"Timestamp and retry count",[40,917,919],{"id":918},"viewing-the-dlq","Viewing the DLQ",[14,921,922],{},"Failed webhook requests can be viewed and retried from the NoLag Dashboard. Navigate to your App settings and look for the Dead Letter Queue section.",[35,924,926],{"id":925},"best-practices","Best Practices",[452,928,929,935,941,950,956],{},[455,930,931,934],{},[24,932,933],{},"Respond quickly"," - Webhook handlers should respond within a few seconds. Use async processing for heavy work.",[455,936,937,940],{},[24,938,939],{},"Idempotency"," - Design your handlers to be idempotent since retries may cause duplicate calls.",[455,942,943,946,947,949],{},[24,944,945],{},"Use scope for tenant isolation"," - Use the ",[64,948,180],{}," field in webhook payloads to route data to the correct tenant.",[455,951,952,955],{},[24,953,954],{},"Logging"," - Log incoming webhook requests for debugging and auditing.",[455,957,958,961],{},[24,959,960],{},"Monitoring"," - Monitor your DLQ and set up alerts for failed webhooks.",[35,963,965],{"id":964},"example-chat-application","Example: Chat Application",[14,967,968],{},"Here's a complete webhook handler example for a chat application:",[53,970,971,1420,1682],{},[56,972,975],{"className":514,"code":973,"filename":974,"language":517,"meta":62,"style":62},"import express from 'express'\n\nconst app = express()\napp.use(express.json())\n\n// Hydration: Return recent messages when user joins\napp.post('/nolag/hydration', async (req, res) => {\n  const { actorId, roomName, topicName, scope } = req.body\n\n  // scope is null for unscoped actors, or:\n  // { accessScopeId: \"...\", slug: \"client-acme\", name: \"Acme Corp\" }\n  const tenantFilter = scope ? { tenantId: scope.accessScopeId } : {}\n\n  const messages = await db.messages.findMany({\n    where: { room: roomName, ...tenantFilter },\n    orderBy: { createdAt: 'desc' },\n    take: 50\n  })\n\n  res.json({ messages: messages.reverse() })\n})\n\n// Trigger: Store message and send notifications\napp.post('/nolag/trigger', async (req, res) => {\n  const { roomName, topicName, actorId, data, scope } = req.body\n\n  await db.messages.create({\n    data: {\n      room: roomName,\n      actorId,\n      content: data.text,\n      tenantId: scope?.accessScopeId\n    }\n  })\n\n  await pushService.notifyRoom(roomName, data)\n  res.status(200).send('OK')\n})\n","Express.js",[64,976,977,992,998,1016,1032,1036,1041,1080,1114,1118,1123,1128,1152,1156,1177,1188,1198,1206,1211,1215,1231,1237,1242,1248,1278,1310,1315,1328,1334,1340,1346,1352,1358,1364,1369,1374,1388,1415],{"__ignoreMap":62},[67,978,979,983,986,989],{"class":69,"line":70},[67,980,982],{"class":981},"szBVR","import",[67,984,985],{"class":73}," express ",[67,987,988],{"class":981},"from",[67,990,991],{"class":87}," 'express'\n",[67,993,994],{"class":69,"line":77},[67,995,997],{"emptyLinePlaceholder":996},true,"\n",[67,999,1000,1003,1006,1009,1013],{"class":69,"line":94},[67,1001,1002],{"class":981},"const",[67,1004,1005],{"class":80}," app",[67,1007,1008],{"class":981}," =",[67,1010,1012],{"class":1011},"sScJk"," express",[67,1014,1015],{"class":73},"()\n",[67,1017,1018,1021,1024,1027,1029],{"class":69,"line":107},[67,1019,1020],{"class":73},"app.",[67,1022,1023],{"class":1011},"use",[67,1025,1026],{"class":73},"(express.",[67,1028,61],{"class":1011},[67,1030,1031],{"class":73},"())\n",[67,1033,1034],{"class":69,"line":120},[67,1035,997],{"emptyLinePlaceholder":996},[67,1037,1038],{"class":69,"line":129},[67,1039,1040],{"class":524},"// Hydration: Return recent messages when user joins\n",[67,1042,1043,1045,1048,1051,1054,1056,1059,1062,1066,1068,1071,1074,1077],{"class":69,"line":142},[67,1044,1020],{"class":73},[67,1046,1047],{"class":1011},"post",[67,1049,1050],{"class":73},"(",[67,1052,1053],{"class":87},"'/nolag/hydration'",[67,1055,231],{"class":73},[67,1057,1058],{"class":981},"async",[67,1060,1061],{"class":73}," (",[67,1063,1065],{"class":1064},"s4XuR","req",[67,1067,231],{"class":73},[67,1069,1070],{"class":1064},"res",[67,1072,1073],{"class":73},") ",[67,1075,1076],{"class":981},"=>",[67,1078,1079],{"class":73}," {\n",[67,1081,1082,1085,1088,1091,1093,1096,1098,1101,1103,1105,1108,1111],{"class":69,"line":155},[67,1083,1084],{"class":981},"  const",[67,1086,1087],{"class":73}," { ",[67,1089,1090],{"class":80},"actorId",[67,1092,231],{"class":73},[67,1094,1095],{"class":80},"roomName",[67,1097,231],{"class":73},[67,1099,1100],{"class":80},"topicName",[67,1102,231],{"class":73},[67,1104,180],{"class":80},[67,1106,1107],{"class":73}," } ",[67,1109,1110],{"class":981},"=",[67,1112,1113],{"class":73}," req.body\n",[67,1115,1116],{"class":69,"line":166},[67,1117,997],{"emptyLinePlaceholder":996},[67,1119,1120],{"class":69,"line":172},[67,1121,1122],{"class":524},"  // scope is null for unscoped actors, or:\n",[67,1124,1125],{"class":69,"line":407},[67,1126,1127],{"class":524},"  // { accessScopeId: \"...\", slug: \"client-acme\", name: \"Acme Corp\" }\n",[67,1129,1130,1132,1135,1137,1140,1143,1146,1149],{"class":69,"line":418},[67,1131,1084],{"class":981},[67,1133,1134],{"class":80}," tenantFilter",[67,1136,1008],{"class":981},[67,1138,1139],{"class":73}," scope ",[67,1141,1142],{"class":981},"?",[67,1144,1145],{"class":73}," { tenantId: scope.accessScopeId } ",[67,1147,1148],{"class":981},":",[67,1150,1151],{"class":73}," {}\n",[67,1153,1154],{"class":69,"line":427},[67,1155,997],{"emptyLinePlaceholder":996},[67,1157,1158,1160,1163,1165,1168,1171,1174],{"class":69,"line":432},[67,1159,1084],{"class":981},[67,1161,1162],{"class":80}," messages",[67,1164,1008],{"class":981},[67,1166,1167],{"class":981}," await",[67,1169,1170],{"class":73}," db.messages.",[67,1172,1173],{"class":1011},"findMany",[67,1175,1176],{"class":73},"({\n",[67,1178,1179,1182,1185],{"class":69,"line":593},[67,1180,1181],{"class":73},"    where: { room: roomName, ",[67,1183,1184],{"class":981},"...",[67,1186,1187],{"class":73},"tenantFilter },\n",[67,1189,1190,1193,1196],{"class":69,"line":598},[67,1191,1192],{"class":73},"    orderBy: { createdAt: ",[67,1194,1195],{"class":87},"'desc'",[67,1197,252],{"class":73},[67,1199,1200,1203],{"class":69,"line":604},[67,1201,1202],{"class":73},"    take: ",[67,1204,1205],{"class":80},"50\n",[67,1207,1208],{"class":69,"line":610},[67,1209,1210],{"class":73},"  })\n",[67,1212,1213],{"class":69,"line":616},[67,1214,997],{"emptyLinePlaceholder":996},[67,1216,1217,1220,1222,1225,1228],{"class":69,"line":622},[67,1218,1219],{"class":73},"  res.",[67,1221,61],{"class":1011},[67,1223,1224],{"class":73},"({ messages: messages.",[67,1226,1227],{"class":1011},"reverse",[67,1229,1230],{"class":73},"() })\n",[67,1232,1234],{"class":69,"line":1233},21,[67,1235,1236],{"class":73},"})\n",[67,1238,1240],{"class":69,"line":1239},22,[67,1241,997],{"emptyLinePlaceholder":996},[67,1243,1245],{"class":69,"line":1244},23,[67,1246,1247],{"class":524},"// Trigger: Store message and send notifications\n",[67,1249,1251,1253,1255,1257,1260,1262,1264,1266,1268,1270,1272,1274,1276],{"class":69,"line":1250},24,[67,1252,1020],{"class":73},[67,1254,1047],{"class":1011},[67,1256,1050],{"class":73},[67,1258,1259],{"class":87},"'/nolag/trigger'",[67,1261,231],{"class":73},[67,1263,1058],{"class":981},[67,1265,1061],{"class":73},[67,1267,1065],{"class":1064},[67,1269,231],{"class":73},[67,1271,1070],{"class":1064},[67,1273,1073],{"class":73},[67,1275,1076],{"class":981},[67,1277,1079],{"class":73},[67,1279,1281,1283,1285,1287,1289,1291,1293,1295,1297,1300,1302,1304,1306,1308],{"class":69,"line":1280},25,[67,1282,1084],{"class":981},[67,1284,1087],{"class":73},[67,1286,1095],{"class":80},[67,1288,231],{"class":73},[67,1290,1100],{"class":80},[67,1292,231],{"class":73},[67,1294,1090],{"class":80},[67,1296,231],{"class":73},[67,1298,1299],{"class":80},"data",[67,1301,231],{"class":73},[67,1303,180],{"class":80},[67,1305,1107],{"class":73},[67,1307,1110],{"class":981},[67,1309,1113],{"class":73},[67,1311,1313],{"class":69,"line":1312},26,[67,1314,997],{"emptyLinePlaceholder":996},[67,1316,1318,1321,1323,1326],{"class":69,"line":1317},27,[67,1319,1320],{"class":981},"  await",[67,1322,1170],{"class":73},[67,1324,1325],{"class":1011},"create",[67,1327,1176],{"class":73},[67,1329,1331],{"class":69,"line":1330},28,[67,1332,1333],{"class":73},"    data: {\n",[67,1335,1337],{"class":69,"line":1336},29,[67,1338,1339],{"class":73},"      room: roomName,\n",[67,1341,1343],{"class":69,"line":1342},30,[67,1344,1345],{"class":73},"      actorId,\n",[67,1347,1349],{"class":69,"line":1348},31,[67,1350,1351],{"class":73},"      content: data.text,\n",[67,1353,1355],{"class":69,"line":1354},32,[67,1356,1357],{"class":73},"      tenantId: scope?.accessScopeId\n",[67,1359,1361],{"class":69,"line":1360},33,[67,1362,1363],{"class":73},"    }\n",[67,1365,1367],{"class":69,"line":1366},34,[67,1368,1210],{"class":73},[67,1370,1372],{"class":69,"line":1371},35,[67,1373,997],{"emptyLinePlaceholder":996},[67,1375,1377,1379,1382,1385],{"class":69,"line":1376},36,[67,1378,1320],{"class":981},[67,1380,1381],{"class":73}," pushService.",[67,1383,1384],{"class":1011},"notifyRoom",[67,1386,1387],{"class":73},"(roomName, data)\n",[67,1389,1391,1393,1396,1398,1401,1404,1407,1409,1412],{"class":69,"line":1390},37,[67,1392,1219],{"class":73},[67,1394,1395],{"class":1011},"status",[67,1397,1050],{"class":73},[67,1399,1400],{"class":80},"200",[67,1402,1403],{"class":73},").",[67,1405,1406],{"class":1011},"send",[67,1408,1050],{"class":73},[67,1410,1411],{"class":87},"'OK'",[67,1413,1414],{"class":73},")\n",[67,1416,1418],{"class":69,"line":1417},38,[67,1419,1236],{"class":73},[56,1421,1424],{"className":628,"code":1422,"filename":1423,"language":631,"meta":62,"style":62},"from fastapi import FastAPI\nfrom pydantic import BaseModel\nfrom typing import Optional\n\napp = FastAPI()\n\nclass ScopeInfo(BaseModel):\n    accessScopeId: str\n    slug: str\n    name: str\n\nclass HydrationRequest(BaseModel):\n    actorId: str\n    roomName: str\n    topicName: str\n    scope: Optional[ScopeInfo] = None\n\nclass TriggerRequest(BaseModel):\n    roomName: str\n    topicName: str\n    actorId: str\n    data: dict\n    scope: Optional[ScopeInfo] = None\n\n# Hydration: Return recent messages when user joins\n@app.post('/nolag/hydration')\nasync def hydration(req: HydrationRequest):\n    filters = {'room': req.roomName}\n    if req.scope:\n        filters['tenant_id'] = req.scope.accessScopeId\n\n    messages = await db.messages.find_many(\n        where=filters,\n        order_by={'created_at': 'desc'},\n        take=50\n    )\n    return {'messages': list(reversed(messages))}\n\n# Trigger: Store message and send notifications\n@app.post('/nolag/trigger')\nasync def trigger(req: TriggerRequest):\n    await db.messages.create(\n        data={\n            'room': req.roomName,\n            'actor_id': req.actorId,\n            'content': req.data['text'],\n            'tenant_id': req.scope.accessScopeId if req.scope else None\n        }\n    )\n    await push_service.notify_room(req.roomName, req.data)\n    return {'status': 'ok'}\n","FastAPI",[64,1425,1426,1431,1436,1441,1445,1450,1454,1459,1464,1469,1474,1478,1483,1488,1493,1498,1503,1507,1512,1516,1520,1524,1529,1533,1537,1542,1547,1552,1557,1562,1567,1571,1576,1581,1586,1591,1596,1601,1605,1611,1617,1623,1629,1635,1641,1647,1653,1659,1665,1670,1676],{"__ignoreMap":62},[67,1427,1428],{"class":69,"line":70},[67,1429,1430],{},"from fastapi import FastAPI\n",[67,1432,1433],{"class":69,"line":77},[67,1434,1435],{},"from pydantic import BaseModel\n",[67,1437,1438],{"class":69,"line":94},[67,1439,1440],{},"from typing import Optional\n",[67,1442,1443],{"class":69,"line":107},[67,1444,997],{"emptyLinePlaceholder":996},[67,1446,1447],{"class":69,"line":120},[67,1448,1449],{},"app = FastAPI()\n",[67,1451,1452],{"class":69,"line":129},[67,1453,997],{"emptyLinePlaceholder":996},[67,1455,1456],{"class":69,"line":142},[67,1457,1458],{},"class ScopeInfo(BaseModel):\n",[67,1460,1461],{"class":69,"line":155},[67,1462,1463],{},"    accessScopeId: str\n",[67,1465,1466],{"class":69,"line":166},[67,1467,1468],{},"    slug: str\n",[67,1470,1471],{"class":69,"line":172},[67,1472,1473],{},"    name: str\n",[67,1475,1476],{"class":69,"line":407},[67,1477,997],{"emptyLinePlaceholder":996},[67,1479,1480],{"class":69,"line":418},[67,1481,1482],{},"class HydrationRequest(BaseModel):\n",[67,1484,1485],{"class":69,"line":427},[67,1486,1487],{},"    actorId: str\n",[67,1489,1490],{"class":69,"line":432},[67,1491,1492],{},"    roomName: str\n",[67,1494,1495],{"class":69,"line":593},[67,1496,1497],{},"    topicName: str\n",[67,1499,1500],{"class":69,"line":598},[67,1501,1502],{},"    scope: Optional[ScopeInfo] = None\n",[67,1504,1505],{"class":69,"line":604},[67,1506,997],{"emptyLinePlaceholder":996},[67,1508,1509],{"class":69,"line":610},[67,1510,1511],{},"class TriggerRequest(BaseModel):\n",[67,1513,1514],{"class":69,"line":616},[67,1515,1492],{},[67,1517,1518],{"class":69,"line":622},[67,1519,1497],{},[67,1521,1522],{"class":69,"line":1233},[67,1523,1487],{},[67,1525,1526],{"class":69,"line":1239},[67,1527,1528],{},"    data: dict\n",[67,1530,1531],{"class":69,"line":1244},[67,1532,1502],{},[67,1534,1535],{"class":69,"line":1250},[67,1536,997],{"emptyLinePlaceholder":996},[67,1538,1539],{"class":69,"line":1280},[67,1540,1541],{},"# Hydration: Return recent messages when user joins\n",[67,1543,1544],{"class":69,"line":1312},[67,1545,1546],{},"@app.post('/nolag/hydration')\n",[67,1548,1549],{"class":69,"line":1317},[67,1550,1551],{},"async def hydration(req: HydrationRequest):\n",[67,1553,1554],{"class":69,"line":1330},[67,1555,1556],{},"    filters = {'room': req.roomName}\n",[67,1558,1559],{"class":69,"line":1336},[67,1560,1561],{},"    if req.scope:\n",[67,1563,1564],{"class":69,"line":1342},[67,1565,1566],{},"        filters['tenant_id'] = req.scope.accessScopeId\n",[67,1568,1569],{"class":69,"line":1348},[67,1570,997],{"emptyLinePlaceholder":996},[67,1572,1573],{"class":69,"line":1354},[67,1574,1575],{},"    messages = await db.messages.find_many(\n",[67,1577,1578],{"class":69,"line":1360},[67,1579,1580],{},"        where=filters,\n",[67,1582,1583],{"class":69,"line":1366},[67,1584,1585],{},"        order_by={'created_at': 'desc'},\n",[67,1587,1588],{"class":69,"line":1371},[67,1589,1590],{},"        take=50\n",[67,1592,1593],{"class":69,"line":1376},[67,1594,1595],{},"    )\n",[67,1597,1598],{"class":69,"line":1390},[67,1599,1600],{},"    return {'messages': list(reversed(messages))}\n",[67,1602,1603],{"class":69,"line":1417},[67,1604,997],{"emptyLinePlaceholder":996},[67,1606,1608],{"class":69,"line":1607},39,[67,1609,1610],{},"# Trigger: Store message and send notifications\n",[67,1612,1614],{"class":69,"line":1613},40,[67,1615,1616],{},"@app.post('/nolag/trigger')\n",[67,1618,1620],{"class":69,"line":1619},41,[67,1621,1622],{},"async def trigger(req: TriggerRequest):\n",[67,1624,1626],{"class":69,"line":1625},42,[67,1627,1628],{},"    await db.messages.create(\n",[67,1630,1632],{"class":69,"line":1631},43,[67,1633,1634],{},"        data={\n",[67,1636,1638],{"class":69,"line":1637},44,[67,1639,1640],{},"            'room': req.roomName,\n",[67,1642,1644],{"class":69,"line":1643},45,[67,1645,1646],{},"            'actor_id': req.actorId,\n",[67,1648,1650],{"class":69,"line":1649},46,[67,1651,1652],{},"            'content': req.data['text'],\n",[67,1654,1656],{"class":69,"line":1655},47,[67,1657,1658],{},"            'tenant_id': req.scope.accessScopeId if req.scope else None\n",[67,1660,1662],{"class":69,"line":1661},48,[67,1663,1664],{},"        }\n",[67,1666,1668],{"class":69,"line":1667},49,[67,1669,1595],{},[67,1671,1673],{"class":69,"line":1672},50,[67,1674,1675],{},"    await push_service.notify_room(req.roomName, req.data)\n",[67,1677,1679],{"class":69,"line":1678},51,[67,1680,1681],{},"    return {'status': 'ok'}\n",[56,1683,1686],{"className":735,"code":1684,"filename":1685,"language":737,"meta":62,"style":62},"package main\n\nimport \"github.com/gin-gonic/gin\"\n\ntype ScopeInfo struct {\n    AccessScopeID string `json:\"accessScopeId\"`\n    Slug          string `json:\"slug\"`\n    Name          string `json:\"name\"`\n}\n\ntype HydrationRequest struct {\n    ActorID   string     `json:\"actorId\"`\n    RoomName  string     `json:\"roomName\"`\n    TopicName string     `json:\"topicName\"`\n    Scope     *ScopeInfo `json:\"scope\"`\n}\n\ntype TriggerRequest struct {\n    RoomName  string                 `json:\"roomName\"`\n    TopicName string                 `json:\"topicName\"`\n    ActorID   string                 `json:\"actorId\"`\n    Data      map[string]interface{} `json:\"data\"`\n    Scope     *ScopeInfo             `json:\"scope\"`\n}\n\nfunc main() {\n    r := gin.Default()\n\n    // Hydration: Return recent messages\n    r.POST(\"/nolag/hydration\", func(c *gin.Context) {\n        var req HydrationRequest\n        c.BindJSON(&req)\n\n        tenantID := \"\"\n        if req.Scope != nil {\n            tenantID = req.Scope.AccessScopeID\n        }\n\n        messages := db.GetRecentMessages(req.RoomName, 50, tenantID)\n        c.JSON(200, gin.H{\"messages\": messages})\n    })\n\n    // Trigger: Store message and notify\n    r.POST(\"/nolag/trigger\", func(c *gin.Context) {\n        var req TriggerRequest\n        c.BindJSON(&req)\n\n        db.CreateMessage(req.RoomName, req.ActorID, req.Data, req.Scope)\n        pushService.NotifyRoom(req.RoomName, req.Data)\n        c.String(200, \"OK\")\n    })\n\n    r.Run(\":8080\")\n}\n","Gin",[64,1687,1688,1693,1697,1702,1706,1711,1716,1721,1726,1730,1734,1739,1744,1749,1754,1759,1763,1767,1772,1777,1782,1787,1792,1797,1801,1805,1810,1815,1819,1824,1829,1834,1839,1843,1848,1853,1858,1862,1866,1871,1876,1881,1885,1890,1895,1900,1904,1908,1913,1918,1923,1927,1932,1938],{"__ignoreMap":62},[67,1689,1690],{"class":69,"line":70},[67,1691,1692],{},"package main\n",[67,1694,1695],{"class":69,"line":77},[67,1696,997],{"emptyLinePlaceholder":996},[67,1698,1699],{"class":69,"line":94},[67,1700,1701],{},"import \"github.com/gin-gonic/gin\"\n",[67,1703,1704],{"class":69,"line":107},[67,1705,997],{"emptyLinePlaceholder":996},[67,1707,1708],{"class":69,"line":120},[67,1709,1710],{},"type ScopeInfo struct {\n",[67,1712,1713],{"class":69,"line":129},[67,1714,1715],{},"    AccessScopeID string `json:\"accessScopeId\"`\n",[67,1717,1718],{"class":69,"line":142},[67,1719,1720],{},"    Slug          string `json:\"slug\"`\n",[67,1722,1723],{"class":69,"line":155},[67,1724,1725],{},"    Name          string `json:\"name\"`\n",[67,1727,1728],{"class":69,"line":166},[67,1729,175],{},[67,1731,1732],{"class":69,"line":172},[67,1733,997],{"emptyLinePlaceholder":996},[67,1735,1736],{"class":69,"line":407},[67,1737,1738],{},"type HydrationRequest struct {\n",[67,1740,1741],{"class":69,"line":418},[67,1742,1743],{},"    ActorID   string     `json:\"actorId\"`\n",[67,1745,1746],{"class":69,"line":427},[67,1747,1748],{},"    RoomName  string     `json:\"roomName\"`\n",[67,1750,1751],{"class":69,"line":432},[67,1752,1753],{},"    TopicName string     `json:\"topicName\"`\n",[67,1755,1756],{"class":69,"line":593},[67,1757,1758],{},"    Scope     *ScopeInfo `json:\"scope\"`\n",[67,1760,1761],{"class":69,"line":598},[67,1762,175],{},[67,1764,1765],{"class":69,"line":604},[67,1766,997],{"emptyLinePlaceholder":996},[67,1768,1769],{"class":69,"line":610},[67,1770,1771],{},"type TriggerRequest struct {\n",[67,1773,1774],{"class":69,"line":616},[67,1775,1776],{},"    RoomName  string                 `json:\"roomName\"`\n",[67,1778,1779],{"class":69,"line":622},[67,1780,1781],{},"    TopicName string                 `json:\"topicName\"`\n",[67,1783,1784],{"class":69,"line":1233},[67,1785,1786],{},"    ActorID   string                 `json:\"actorId\"`\n",[67,1788,1789],{"class":69,"line":1239},[67,1790,1791],{},"    Data      map[string]interface{} `json:\"data\"`\n",[67,1793,1794],{"class":69,"line":1244},[67,1795,1796],{},"    Scope     *ScopeInfo             `json:\"scope\"`\n",[67,1798,1799],{"class":69,"line":1250},[67,1800,175],{},[67,1802,1803],{"class":69,"line":1280},[67,1804,997],{"emptyLinePlaceholder":996},[67,1806,1807],{"class":69,"line":1312},[67,1808,1809],{},"func main() {\n",[67,1811,1812],{"class":69,"line":1317},[67,1813,1814],{},"    r := gin.Default()\n",[67,1816,1817],{"class":69,"line":1330},[67,1818,997],{"emptyLinePlaceholder":996},[67,1820,1821],{"class":69,"line":1336},[67,1822,1823],{},"    // Hydration: Return recent messages\n",[67,1825,1826],{"class":69,"line":1342},[67,1827,1828],{},"    r.POST(\"/nolag/hydration\", func(c *gin.Context) {\n",[67,1830,1831],{"class":69,"line":1348},[67,1832,1833],{},"        var req HydrationRequest\n",[67,1835,1836],{"class":69,"line":1354},[67,1837,1838],{},"        c.BindJSON(&req)\n",[67,1840,1841],{"class":69,"line":1360},[67,1842,997],{"emptyLinePlaceholder":996},[67,1844,1845],{"class":69,"line":1366},[67,1846,1847],{},"        tenantID := \"\"\n",[67,1849,1850],{"class":69,"line":1371},[67,1851,1852],{},"        if req.Scope != nil {\n",[67,1854,1855],{"class":69,"line":1376},[67,1856,1857],{},"            tenantID = req.Scope.AccessScopeID\n",[67,1859,1860],{"class":69,"line":1390},[67,1861,1664],{},[67,1863,1864],{"class":69,"line":1417},[67,1865,997],{"emptyLinePlaceholder":996},[67,1867,1868],{"class":69,"line":1607},[67,1869,1870],{},"        messages := db.GetRecentMessages(req.RoomName, 50, tenantID)\n",[67,1872,1873],{"class":69,"line":1613},[67,1874,1875],{},"        c.JSON(200, gin.H{\"messages\": messages})\n",[67,1877,1878],{"class":69,"line":1619},[67,1879,1880],{},"    })\n",[67,1882,1883],{"class":69,"line":1625},[67,1884,997],{"emptyLinePlaceholder":996},[67,1886,1887],{"class":69,"line":1631},[67,1888,1889],{},"    // Trigger: Store message and notify\n",[67,1891,1892],{"class":69,"line":1637},[67,1893,1894],{},"    r.POST(\"/nolag/trigger\", func(c *gin.Context) {\n",[67,1896,1897],{"class":69,"line":1643},[67,1898,1899],{},"        var req TriggerRequest\n",[67,1901,1902],{"class":69,"line":1649},[67,1903,1838],{},[67,1905,1906],{"class":69,"line":1655},[67,1907,997],{"emptyLinePlaceholder":996},[67,1909,1910],{"class":69,"line":1661},[67,1911,1912],{},"        db.CreateMessage(req.RoomName, req.ActorID, req.Data, req.Scope)\n",[67,1914,1915],{"class":69,"line":1667},[67,1916,1917],{},"        pushService.NotifyRoom(req.RoomName, req.Data)\n",[67,1919,1920],{"class":69,"line":1672},[67,1921,1922],{},"        c.String(200, \"OK\")\n",[67,1924,1925],{"class":69,"line":1678},[67,1926,1880],{},[67,1928,1930],{"class":69,"line":1929},52,[67,1931,997],{"emptyLinePlaceholder":996},[67,1933,1935],{"class":69,"line":1934},53,[67,1936,1937],{},"    r.Run(\":8080\")\n",[67,1939,1941],{"class":69,"line":1940},54,[67,1942,175],{},[14,1944,1945],{},[1946,1947,1949],"a",{"href":1948},"/docs/concepts/qos","Quality of Service",[14,1951,1952],{},[1946,1953,1955],{"href":1954},"/docs/concepts/acl","Access Control",[1957,1958,1959],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":62,"searchDepth":77,"depth":77,"links":1961},[1962,1966,1967,1971,1972,1977,1978],{"id":37,"depth":77,"text":38,"children":1963},[1964,1965],{"id":42,"depth":94,"text":43},{"id":306,"depth":94,"text":307},{"id":443,"depth":77,"text":444},{"id":485,"depth":77,"text":486,"children":1968},[1969,1970],{"id":489,"depth":94,"text":490},{"id":508,"depth":94,"text":509},{"id":822,"depth":77,"text":823},{"id":861,"depth":77,"text":862,"children":1973},[1974,1975,1976],{"id":868,"depth":94,"text":869},{"id":894,"depth":94,"text":895},{"id":918,"depth":94,"text":919},{"id":925,"depth":77,"text":926},{"id":964,"depth":77,"text":965},"Learn how to use NoLag webhooks for hydration and triggers to integrate with external systems.","md",{},"/docs/concepts/webhooks",{"title":5,"description":1979},"docs/concepts/webhooks","wdPBPhfhpvrI9tev-4ns5sDWnXpatLstwivwsQLiTnE",1788160343254]