1import{B as e,Ct as t,M as n,R as r,St as i,kt as a,ot as o,st as s}from"./CzsObDY8.js";import"./xihTtKlq.js";import"./C5qy-xbg.js";var c=a({default:()=>p,metadata:()=>l}),l={title:`Webhooks`,description:`Learn how to use Pockethost webhooks to schedule reliable API calls without external cron jobs. Automate tasks like backups, data cleanup, notifications, and integrationsâeven when your instance is hibernated`},{title:u,description:d}=l,f=e(`<h1>Webhooks</h1> <p>Webhooks allow you to schedule API calls to your PocketBase instance at specific times, replacing the need for external cron job schedulers. This feature enables automated tasks like data cleanup, backups, notifications, and integrations with external services.</p> <blockquote><p><strong>Important</strong>: Webhooks replace PocketBaseâs built-in <a href="https://pocketbase.io/docs/js-jobs-scheduling/" rel="nofollow">cron job scheduling</a> (<code>cronAdd</code>) on PocketHost. While <code>cronAdd</code> works in standard PocketBase deployments, it becomes unreliable on PocketHost due to instance hibernation. Scheduled webhooks will always execute reliably, even when your instance is hibernated.</p></blockquote> <h2>Overview</h2> <p>Webhooks are configured through the PocketHost dashboard and automatically send HTTP GET requests to your specified endpoints at scheduled intervals. Each webhook consists of:</p> <ul><li><strong>API Endpoint</strong>: The URL path within your instance to call</li> <li><strong>Schedule</strong>: A cron expression defining when the webhook executes</li></ul> <p>All webhooks execute in <strong>UTC time</strong>. Make sure to adjust your cron schedules accordingly.</p> <h3>Why Use Webhooks Instead of <code>cronAdd</code>?</h3> <p>On PocketHost, webhooks provide several advantages over PocketBaseâs built-in <code>cronAdd</code>:</p> <ul><li><strong>Reliability</strong>: Webhooks execute even when your instance is hibernated</li> <li><strong>Consistency</strong>: No dependency on your instanceâs uptime</li> <li><strong>Scalability</strong>: Handled by PocketHostâs infrastructure, not your instance</li> <li><strong>Monitoring</strong>: Better visibility into execution status and failures</li></ul> <h2>Configuration</h2> <h3>API Endpoint</h3> <p>The API endpoint must be a valid path within your PocketBase instance:</p> <ul><li>Must start with <code>/</code> (e.g., <code>/api/webhooks/backup</code>)</li> <li>Can include query parameters (e.g., <code>/api/cron?token=abc123</code>)</li> <li>Cannot include protocol or host (no <code>http://</code> or <code>https://</code>)</li> <li>Supports any valid URL path structure</li></ul> <p><strong>Examples:</strong></p> <ul><li><code>/api/webhooks/daily-cleanup</code></li> <li><code>/api/backup?type=full&compress=true</code></li> <li><code>/webhook/slack/notifications</code></li> <li><code>/api/maintenance/cleanup-old-records</code></li></ul> <h3>Schedule (Cron Expression)</h3> <p>Webhooks use standard cron expressions to define execution schedules. You can use either:</p> <h4>Predefined Macros</h4> <table><thead><tr><th>Macro</th><th>Description</th><th>Equivalent Expression</th></tr></thead><tbody><tr><td><code>@yearly</code></td><td>Once a year at midnight, January 1st</td><td><code>0 0 1 1 *</code></td></tr><tr><td><code>@annually</code></td><td>Same as <code>@yearly</code></td><td><code>0 0 1 1 *</code></td></tr><tr><td><code>@monthly</code></td><td>Once a month at midnight, first day</td><td><code>0 0 1 * *</code></td></tr><tr><td><code>@weekly</code></td><td>Once a week at midnight on Sunday</td><td><code>0 0 * * 0</code></td></tr><tr><td><code>@daily</code></td><td>Once a day at midnight</td><td><code>0 0 * * *</code></td></tr><tr><td><code>@midnight</code></td><td>Same as <code>@daily</code></td><td><code>0 0 * * *</code></td></tr><tr><td><code>@hourly</code></td><td>Once an hour at the beginning</td><td><code>0 * * * *</code></td></tr><tr><td><code>@minutely</code></td><td>Once a minute</td><td><code>* * * * *</code></td></tr><tr><td><code>@secondly</code></td><td>Once a second</td><td><code>* * * * * *</code></td></tr><tr><td><code>@weekdays</code></td><td>Every weekday at midnight</td><td><code>0 0 * * 1-5</code></td></tr><tr><td><code>@weekends</code></td><td>Every weekend at midnight</td><td><code>0 0 * * 0,6</code></td></tr></tbody></table> <h4>Standard Cron Expressions</h4> <p>Standard cron expressions use 5 fields: <code>minute hour day month weekday</code></p> <table><thead><tr><th>
1Field</th><th>Values</th><th>Special Characters</th><th>Description</th></tr></thead><tbody><tr><td>Minute</td><td>0-59</td><td><code>* , - / ?</code></td><td>Minute of the hour</td></tr><tr><td>Hour</td><td>0-23</td><td><code>* , - / ?</code></td><td>Hour of the day</td></tr><tr><td>Day of Month</td><td>1-31</td><td><code>* , - / ? L W</code></td><td>Day of the month</td></tr><tr><td>Month</td><td>1-12</td><td><code>* , - / ?</code></td><td>Month of the year</td></tr><tr><td>Day of Week</td><td>0-6</td><td><code>* , - / ? L #</code></td><td>Day of the week (0=Sunday)</td></tr></tbody></table> <p><strong>Special Characters:</strong></p> <ul><li><code>*</code> - Any value</li> <li><code>,</code> - Value list separator</li> <li><code>-</code> - Range of values</li> <li><code>/</code> - Step values</li> <li><code>?</code> - Any value (alias for <code>*</code>)</li> <li><code>L</code> - Last day of month/week</li> <li><code>W</code> - Weekday (nearest to given day)</li> <li><code>#</code> - Nth day of month</li></ul> <h3>Timing</h3> <p>All webhooks execute in <strong>UTC time</strong>. When scheduling webhooks, convert your local time to UTC:</p> <ul><li><strong>EST (UTC-5)</strong>: 9 AM EST = 2 PM UTC (14:00)</li> <li><strong>PST (UTC-8)</strong>: 6 PM PST = 2 AM UTC next day (02:00)</li> <li><strong>GMT+3</strong>: 3 PM = 12 PM UTC (12:00)</li></ul> <p>Use online UTC converters to help calculate the correct schedule times.</p> <h2>Common Examples</h2> <h3>Business Operations (UTC Time)</h3> <pre class="hljs language-cron"></pre> <h3>Data Management (UTC Time)</h3> <pre class="hljs language-cron"></pre> <h3>Using Macros</h3> <pre class="hljs language-cron"></pre> <h2>Implementation</h2> <h3>Creating Webhook Endpoints</h3> <p>Create API endpoints in your PocketBase instance to handle webhook requests using <a href="https://pocketbase.io/docs/js-routing/" rel="nofollow">PocketBaseâs routing system</a>:</p> <pre class="hljs language-javascript"></pre> <h3>Error Handling</h3> <p>Webhooks should return appropriate HTTP status codes:</p> <ul><li><code>200</code> - Success</li> <li><code>400</code> - Bad request</li> <li><code>500</code> - Internal server error</li></ul> <pre class="hljs language-javascript"></pre> <h3>Authentication</h3> <p>For secure webhooks, include authentication in your endpoints:</p> <pre class="hljs language-javascript"></pre> <h2>Best Practices</h2> <h3>1. Idempotency</h3> <p>Make your webhooks idempotent so they can be safely retried:</p> <pre class="hljs language-javascript"></pre> <h3>2. Logging</h3> <p>Always log webhook executions for debugging:</p> <pre class="hljs language-javascript"></pre> <h2>Troubleshooting</h2> <h3>Common Issues</h3> <ol><li><strong>Webhook not executing</strong>: Check the cron expression syntax and ensure times are in UTC</li> <li><strong>Endpoint not found</strong>: Ensure the API endpoint exists in your PocketBase instance using <a href="https://pocketbase.io/docs/js-routing/" rel="nofollow">PocketBase routing</a></li> <li><strong>Authentication errors</strong>: Verify any required tokens or secrets</li> <li><strong>Timeout errors</strong>: Optimize webhook execution time</li> <li><strong>Using <code>cronAdd</code> instead of webhooks</strong>: Replace <code>cronAdd</code> calls with scheduled webhooks for reliable execution on PocketHost</li> <li><strong>Wrong execution time</strong>: Remember all schedules are in UTC - convert your local time accordingly</li></ol> <h2>Limitations</h2> <ul><li>Concurrent webhook executions may be limited</li> <li>Webhooks may not run exactly at the time specified, depending on system load and instance state</li> <li>Webhooks are triggered by PocketHostâs scheduling system, not your instanceâs internal clock</li></ul>`,1);function p(e){var a=f(),c=s(o(a),62);n(c,()=>`<code class="hljs language-cron"><span class="hljs-comment"># Weekdays at 9 AM UTC</span> 2<span class="hljs-attribute">0</span> <span class="hljs-number">9</span> * * <span class="hljs-number">1</span>-<span class="hljs-number">5</span> 3 4<span class="hljs-comment"># Every Monday at noon UTC</span> 5<span class="hljs-attribute">0</span> <span class="hljs-number">12</span> * * <span class="hljs-number">1</span> 6 7<span class="hljs-comment"># Every Friday at 6 PM UTC</span> 8<span class="hljs-attribute">0</span> <span class="hljs-number">18</span> * * <span class="hljs-number">5</span> 9 10<span class="hljs-comment"># First day of every month at midnight UTC</span> 11<span class="hljs-attribute">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> * * 12 13<span class="hljs-comment"># 15th of every month at 8 AM UTC</span> 14<span class="hljs-attribute">0</span> <span class="hljs-number">8</span> <span class="hljs-number">15</span> * *</code>`,!0),t(c);var l=s(c,4);n(l,()=>`<code class="hljs language-cron"><span class="hljs-comment"># Daily backup at 2 AM UTC</span> 15<span class="hljs-attribute">0</span> <span class="hljs-number">2</span> * * * 16 17<span class="hljs-comment"># Cleanup old records every 6 hours</span> 18<span class="hljs-attribute">0</span> */<span class="hljs-number">6</span> * * * 19 20<span class="hljs-comment"># Weekly data export on Sundays at midnight UTC</span> 21<span class="hljs-attribute">0</span> <span class="hljs-number">0</span> * * <span class="hljs-number">0</span> 22 23<span class="hljs-comment"># Monthly maintenance on the 1st at midnight UTC</span> 24<span class="hljs-attribute">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> * *</code>`,!0),t(l);var u=s(l,4);n(u,()=>`<code class="hljs language-cron"><span class="hljs-meta"># Daily operations</span> 25<span class="hljs-symbol">@daily</span> 26 27<span class="hljs-meta"># Weekly reports</span> 28<span class="hljs-symbol">@weekly</span> 29 30<span class="hljs-meta"># Monthly cleanup</span> 31<span class="hljs-symbol">@monthly</span> 32 33<span class="hljs-meta"># Business hours only</span> 34<span class="hljs-symbol">@weekdays</span></code>`,!0),t(u);var d=s(u,8);n(d,()=>`<code class="hljs language-javascript"><span class="hljs-comment">// pb_hooks/onRequest.pb.js</span> 35<span class="hljs-title function_">routerAdd</span>(<span class="hljs-string">'GET'</span>, <span class="hljs-string">'/api/webhooks/backup'</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =></span> { 36 <span class="hljs-comment">// Your backup logic here</span> 37 <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Backup webhook triggered'</span>) 38 39 <span class="hljs-comment">// Example: Create a backup record</span> 40 <span class="hljs-keyword">const</span> backup = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Record</span>($app.<span class="hljs-title function_">findCollectionByNameOrId</span>(<span class="hljs-string">'backups'</span>), { 41 <span class="hljs-attr">timestamp</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>().<span class="hljs-title function_">toISOString</span>(), 42 <span class="hljs-attr">status</span>: <span class="hljs-string">'completed'</span>, 43 <span class="hljs-attr">size</span>: <span class="hljs-string">'1.2GB'</span>, 44 }) 45 46 $app.<span class="hljs-title function_">save</span>(backup) 47 48 <span class="hljs-keyword">return</span> e.<span class="hljs-title function_">json</span>(<span class="hljs-number">200</span>, { <span class="hljs-attr">status</span>: <span class="hljs-string">'
48success'</span> }) 49})</code>`,!0),t(d);var p=s(d,8);n(p,()=>`<code class="hljs language-javascript"><span class="hljs-title function_">routerAdd</span>(<span class="hljs-string">'GET'</span>, <span class="hljs-string">'/api/webhooks/cleanup'</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =></span> { 50 <span class="hljs-keyword">try</span> { 51 <span class="hljs-comment">// Your cleanup logic</span> 52 <span class="hljs-keyword">return</span> e.<span class="hljs-title function_">json</span>(<span class="hljs-number">200</span>, { <span class="hljs-attr">status</span>: <span class="hljs-string">'success'</span> }) 53 } <span class="hljs-keyword">catch</span> (error) { 54 <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Webhook error:'</span>, error) 55 <span class="hljs-keyword">return</span> e.<span class="hljs-title function_">json</span>(<span class="hljs-number">500</span>, { <span class="hljs-attr">error</span>: <span class="hljs-string">'Internal server error'</span> }) 56 } 57})</code>`,!0),t(p);var m=s(p,6);n(m,()=>`<code class="hljs language-javascript"><span class="hljs-title function_">routerAdd</span>(<span class="hljs-string">'GET'</span>, <span class="hljs-string">'/api/webhooks/secure'</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =></span> { 58 <span class="hljs-keyword">const</span> token = e.<span class="hljs-property">request</span>.<span class="hljs-property">url</span>.<span class="hljs-title function_">query</span>().<span class="hljs-title function_">
58get</span>(<span class="hljs-string">'token'</span>) 59 60 <span class="hljs-keyword">if</span> (token !== process.<span class="hljs-property">env</span>.<span class="hljs-property">WEBHOOK_SECRET</span>) { 61 <span class="hljs-keyword">return</span> e.<span class="hljs-title function_">json</span>(<span class="hljs-number">401</span>, { <span class="hljs-attr">error</span>: <span class="hljs-string">'Unauthorized'</span> }) 62 } 63 64 <span class="hljs-comment">// Your secure webhook logic</span> 65 <span class="hljs-keyword">return</span> e.<span class="hljs-title function_">json</span>(<span class="hljs-number">200</span>, { <span class="hljs-attr">status</span>: <span class="hljs-string">'success'</span> }) 66})</code>`,!0),t(m);var h=s(m,8);n(h,()=>`<code class="hljs language-javascript"><span class="hljs-title function_">routerAdd</span>(<span class="hljs-string">'GET'</span>, <span class="hljs-string">'/api/webhooks/process'</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =></span> { 67 <span class="hljs-keyword">const</span> jobId = e.<span class="hljs-property">request</span>.<span class="hljs-property">url</span>.<span class="hljs-title function_">query</span>().<span class="hljs-title function_">
67get</span>(<span class="hljs-string">'jobId'</span>) 68 69 <span class="hljs-comment">// Check if already processed</span> 70 <span class="hljs-keyword">const</span> existing = $app.<span class="hljs-title function_">findFirstRecordByData</span>(<span class="hljs-string">'jobs'</span>, <span class="hljs-string">'jobId'</span>, jobId) 71 <span class="hljs-keyword">if</span> (existing && existing.<span class="hljs-title function_">get</span>(<span class="hljs-string">'status'</span>) === <span class="hljs-string">'completed'</span>) { 72 <span class="hljs-keyword">return</span> e.<span class="hljs-title function_">json</span>(<span class="hljs-number">200</span>, { <span class="hljs-attr">status</span>: <span class="hljs-string">'already_processed'</span> }) 73 } 74 75 <span class="hljs-comment">// Process the job</span> 76 <span class="hljs-comment">// ...</span> 77})</code>`,!0),t(h);var g=s(h,6);n(g,()=>`<code class="hljs language-javascript"><span class="hljs-title function_">routerAdd</span>(<span class="hljs-string">'GET'</span>, <span class="hljs-string">'/api/webhooks/backup'</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =></span> { 78 <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Backup webhook triggered at <span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString()}</span>`</span>) 79 80 <span class="hljs-comment">// Your backup logic</span> 81 82 <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Backup webhook completed successfully'</span>) 83 <span class="hljs-keyword">return</span> e.<span class="hljs-title function_">json</span>(<span class="hljs-number">200</span>, { <span class="hljs-attr">status</span>: <span class="hljs-string">'success'</span> }) 84})</code>`,!0),t(g),i(10),r(e,a)}export{p as n,c as t};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.