add permissions list

This commit is contained in:
Simon Larsen 2023-03-19 14:11:55 +00:00
parent 5fb65efd31
commit ec565d4558
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
9 changed files with 201 additions and 414 deletions

View File

@ -1,17 +1,19 @@
{
"has_more": false,
"count": 10,
"limit": 3,
"skip": 0,
"data": [
{
"id": "WAz8eIbvDR60rouK",
// ...
"_id": "p39d997a-026c-44b2-8b02-7b2814d886d2",
// ...
},
{
"id": "hSIhXBhNe8X1d8Et"
// ...
"_id": "l34e743e-1af5-4b0a-998f-1d421c22f7a1",
// ...
},
{
"id": "fbwYwpi9C2ybt6Yb"
// ...
"_id": "6a5aa129-0b3e-45b7-a7f6-b4b6df338a19",
// ...
}
]
}

View File

@ -1,3 +1,4 @@
import { PermissionHelper, PermissionProps } from 'Common/Types/Permission';
import { ExpressRequest, ExpressResponse } from 'CommonServer/Utils/Express';
import ResourceUtil, { ModelDocumentation } from '../Utils/Resources';
@ -16,6 +17,8 @@ export default class ServiceHandler {
pageTitle = 'Permissions';
pageDescription = 'Learn how permisisons work with OneUptime';
pageData.permissions = PermissionHelper.getAllPermissionProps().filter((i: PermissionProps) => i.isAssignableToTenant);
return res.render('pages/index', {
page: page,
resources: Resources,

View File

@ -17,7 +17,7 @@
Authentication with API Key
</h2>
<p>You can use OneUptime API Key on Request Header when you're making a requst. You can use <code class="rounded p-0.5 px-1 text-sm text-gray-500 bg-gray-100 border-2 border-gray-200">Authorization</code> header with your API Key when you make a request.</p>
<%- include('../partials/code', {title: "Example request with API Key", code: "curl --header \"Authorization: Bearer {secret-api-key}\" https://oneuptime.com/api/\<path\>" }) -%>
<%- include('../partials/code', {title: "Example request with API Key", requestUrl: "", requestType: "", code: "curl --header \"Authorization: Bearer {secret-api-key}\" https://oneuptime.com/api/\<path\>" }) -%>
<p class="text-sm">Please don't commit your OneUptime API Key to GitHub, or on any other source control project. Please regenerate a new API Key, if your API Key is comitted by mistake.</p>
</article>
</main>

View File

@ -71,7 +71,7 @@
<p>Here is an example of an error message: </p>
</div>
<%- include('../partials/code', {title: "Example error response", code: "{ message: \"Name is required\" }" }) -%>
<%- include('../partials/code', {title: "Example error response", requestUrl: "", requestType: "", code: "{ \"message\": \"Name is required\" }" }) -%>
</div>
</article>
</main>

View File

@ -1,85 +1,116 @@
<main class="py-16">
<article class="prose dark:prose-invert">
<h1>Pagination</h1>
<p class="lead">In this guide, we will look at how to work with paginated responses when querying the OneUptime API. By default, all responses limit results to ten. </p>
<p>When an API response returns a list of objects, no matter the amount, pagination is supported. In paginated responses, objects are nested in a <code class="inline-code">data</code> attribute. The API response also has <code class="inline-code">count</code> attribute that indicates total count in the list with that query. You can use the <code class="inline-code">limit</code> and <code class="inline-code">skip</code> query parameters to query pages.</p>
<h2 id="example-using-cursors" class="scroll-mt-24">
Pagination Example
</h2>
<div class="grid grid-cols-1 items-start gap-x-16 gap-y-10 xl:max-w-none xl:grid-cols-2">
<div class="[&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>In this example, we request the page that starts after the conversation with id <code class="inline-code">s4WycXedwhQrEFuM</code>. As a result, we get a list of three conversations and can tell by the <code class="inline-code">has_more</code> attribute that we have reached the end of the resultset.</p>
<div class="my-6">
<ul role="list" class="m-0 max-w-[calc(theme(maxWidth.lg)-theme(spacing.8))] list-none divide-y divide-zinc-900/5 p-0 dark:divide-white/5">
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code class="inline-code">starting_after</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500">string</dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>The last ID on the page you're currently on when you want to fetch the next page.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code class="inline-code">ending_before</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500">string</dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>The first ID on the page you're currently on when you want to fetch the previous page.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code class="inline-code">limit</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500">integer</dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>Limit the number of items returned.</p>
</dd>
</dl>
</li>
</ul>
</div>
</div>
<div class="[&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<div class="not-prose my-6 overflow-hidden rounded-2xl bg-zinc-900 shadow-md dark:ring-1 dark:ring-white/10">
<div class="flex min-h-[calc(theme(spacing.12)+1px)] flex-wrap items-start gap-x-4 border-b border-zinc-700 bg-zinc-800 px-4 dark:border-zinc-800 dark:bg-transparent">
<h3 class="mr-auto pt-3 text-xs font-semibold text-white">Manual pagination using cURL</h3>
</div>
<div class="group dark:bg-white/2.5">
<div class="relative">
<pre class="overflow-x-auto p-4 text-xs text-white"><code class="language-bash"><span><span style="color: var(--shiki-color-text)">curl -G https://api.OneUptime.chat/v1/conversations \</span></span>
<span><span style="color: var(--shiki-color-text)"> -H </span><span style="color: var(--shiki-token-string-expression)">"Authorization: Bearer {token}"</span><span style="color: var(--shiki-color-text)"> \</span></span>
<span><span style="color: var(--shiki-color-text)"> -d starting_after=</span><span style="color: var(--shiki-token-string-expression)">"s4WycXedwhQrEFuM"</span><span style="color: var(--shiki-color-text)"> \</span></span>
<span><span style="color: var(--shiki-color-text)"> -d limit=10</span></span>
<span></span></code></pre>
<button type="button" class="group/button absolute top-3.5 right-4 overflow-hidden rounded-full py-1 pl-2 pr-3 text-2xs font-medium opacity-0 backdrop-blur transition focus:opacity-100 group-hover:opacity-100 bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 dark:hover:bg-white/5">
<span aria-hidden="false" class="pointer-events-none flex items-center gap-0.5 text-zinc-400 transition duration-300">
<svg viewBox="0 0 20 20" aria-hidden="true" class="h-5 w-5 fill-zinc-500/20 stroke-zinc-500 transition-colors group-hover/button:stroke-zinc-400">
<path stroke-width="0" d="M5.5 13.5v-5a2 2 0 0 1 2-2l.447-.894A2 2 0 0 1 9.737 4.5h.527a2 2 0 0 1 1.789 1.106l.447.894a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2Z"></path>
<path fill="none" stroke-linejoin="round" d="M12.5 6.5a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2m5 0-.447-.894a2 2 0 0 0-1.79-1.106h-.527a2 2 0 0 0-1.789 1.106L7.5 6.5m5 0-1 1h-3l-1-1"></path>
</svg>
Copy
</span>
<span aria-hidden="true" class="pointer-events-none absolute inset-0 flex items-center justify-center text-emerald-400 transition duration-300 translate-y-1.5 opacity-0">Copied!</span>
</button>
</div>
</div>
</div>
<%- include('../partials/code', {title: "Example request with API Key", code: pageData.responseCode }) -%>
</div>
</div>
</article>
</main>
<article class="prose dark:prose-invert">
<h1>Pagination</h1>
<p class="lead">In this guide, we will look at how to work with paginated responses when querying the OneUptime
API. By default, all responses limit results to ten. </p>
<p>When an API response returns a list of objects, no matter the amount, pagination is supported. In paginated
responses, objects are nested in a <code class="inline-code">data</code> attribute. The API response also has
<code class="inline-code">count</code> attribute that indicates total count in the list with that query. You
can use the <code class="inline-code">limit</code> and <code class="inline-code">skip</code> query parameters
to query pages.</p>
<h2 id="example-using-cursors" class="scroll-mt-24">
Pagination Example
</h2>
<div class="grid grid-cols-1 items-start gap-x-16 gap-y-10 xl:max-w-none xl:grid-cols-2">
<div class="[&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>In this example, we request the list fo monitors. As a result, we get a list of three monitors and can
tell by the <code class="inline-code">count</code> attribute that we have reached the end of the
resultset</p>
<h2 id="example-using-cursors" class="scroll-mt-24">
Query Parameters
</h2>
<div class="my-6">
<ul role="list"
class="m-0 max-w-[calc(theme(maxWidth.lg)-theme(spacing.8))] list-none divide-y divide-zinc-900/5 p-0 dark:divide-white/5">
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code class="inline-code">limit</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500">Number</dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>Number of items you need to fetch. More items will lead to slower responses. Max limit is
100.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code class="inline-code">skip</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500">Number</dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>Number of items to skip. This can be useful when you are paginating items.</p>
</dd>
</dl>
</li>
</ul>
</div>
<h2 id="example-using-cursors" class="scroll-mt-24">
Response Body
</h2>
<div class="my-6">
<ul role="list"
class="m-0 max-w-[calc(theme(maxWidth.lg)-theme(spacing.8))] list-none divide-y divide-zinc-900/5 p-0 dark:divide-white/5">
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code class="inline-code">data</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500">JSON Array</dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>List of items fetched.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code class="inline-code">count</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500">Number</dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>Total number of items in the database</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code class="inline-code">limit</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500">Number</dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>Number of items you need to fetch. More items will lead to slower responses. Max limit is
100.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code class="inline-code">skip</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500">Number</dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>Number of items to skip. This can be useful when you are paginating items.</p>
</dd>
</dl>
</li>
</ul>
</div>
</div>
<div class="[&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<%- include('../partials/code', {title: "Example Pagination Request", requestUrl: "/api/monitors/get-list?skip=0&limit=3", requestType: "GET", code: pageData.requestCode }) -%>
<%- include('../partials/code', {title: "Example Pagination Response" , requestUrl: "", requestType: "", code: pageData.responseCode }) -%>
</div>
</div>
</article>
</main>

View File

@ -1,342 +1,38 @@
<main class="py-16">
<article class="prose dark:prose-invert">
<h1>Webhooks</h1>
<p class="lead">In this guide, we will look at how to register and consume webhooks to integrate your app with Protocol. With webhooks, your app can know when something happens in Protocol, such as someone sending a message or adding a contact.</p>
<h2 id="registering-webhooks" class="scroll-mt-24">
<a class="group text-inherit no-underline hover:text-inherit" href="/webhooks#registering-webhooks">
<div class="absolute mt-1 ml-[calc(-1*var(--width))] hidden w-[var(--width)] opacity-0 transition [--width:calc(2.625rem+0.5px+50%-min(50%,calc(theme(maxWidth.lg)+theme(spacing.8))))] group-hover:opacity-100 group-focus:opacity-100 md:block lg:z-50 2xl:[--width:theme(spacing.10)]">
<div class="group/anchor block h-5 w-5 rounded-lg bg-zinc-50 ring-1 ring-inset ring-zinc-300 transition hover:ring-zinc-500 dark:bg-zinc-800 dark:ring-zinc-700 dark:hover:bg-zinc-700 dark:hover:ring-zinc-600">
<svg viewBox="0 0 20 20" fill="none" stroke-linecap="round" aria-hidden="true" class="h-5 w-5 stroke-zinc-500 transition dark:stroke-zinc-400 dark:group-hover/anchor:stroke-white">
<path d="m6.5 11.5-.964-.964a3.535 3.535 0 1 1 5-5l.964.964m2 2 .964.964a3.536 3.536 0 0 1-5 5L8.5 13.5m0-5 3 3"></path>
</svg>
</div>
</div>
Registering webhooks
</a>
<h1>Permissions</h1>
<p class="lead"> Your API Token needs permissions to create, update, read or delete any resource. If you do not have permissions to make a request a <code class="inline-code">4xx</code> status will be sent as response. You can manage permissions for your API Key in Project Settings > API Keys. </p>
<h2 id="consuming-webhooks" >
Permissions List
</h2>
<p>To register a new webhook, you need to have a URL in your app that Protocol can call. You can configure a new webhook from the Protocol dashboard under <a href="/webhooks#">API settings</a>. Give your webhook a name, pick the <a href="/webhooks#event-types">events</a> you want to listen for, and add your URL.</p>
<p>Now, whenever something of interest happens in your app, a webhook is fired off by Protocol. In the next section, we'll look at how to consume webhooks.</p>
<h2 id="consuming-webhooks" class="scroll-mt-24">
<a class="group text-inherit no-underline hover:text-inherit" href="/webhooks#consuming-webhooks">
<div class="absolute mt-1 ml-[calc(-1*var(--width))] hidden w-[var(--width)] opacity-0 transition [--width:calc(2.625rem+0.5px+50%-min(50%,calc(theme(maxWidth.lg)+theme(spacing.8))))] group-hover:opacity-100 group-focus:opacity-100 md:block lg:z-50 2xl:[--width:theme(spacing.10)]">
<div class="group/anchor block h-5 w-5 rounded-lg bg-zinc-50 ring-1 ring-inset ring-zinc-300 transition hover:ring-zinc-500 dark:bg-zinc-800 dark:ring-zinc-700 dark:hover:bg-zinc-700 dark:hover:ring-zinc-600">
<svg viewBox="0 0 20 20" fill="none" stroke-linecap="round" aria-hidden="true" class="h-5 w-5 stroke-zinc-500 transition dark:stroke-zinc-400 dark:group-hover/anchor:stroke-white">
<path d="m6.5 11.5-.964-.964a3.535 3.535 0 1 1 5-5l.964.964m2 2 .964.964a3.536 3.536 0 0 1-5 5L8.5 13.5m0-5 3 3"></path>
</svg>
</div>
</div>
Consuming webhooks
</a>
</h2>
<p>When your app receives a webhook request from Protocol, check the <code>type</code> attribute to see what event caused it. The first part of the event type will tell you the payload type, e.g., a conversation, message, etc.</p>
<div class="not-prose my-6 overflow-hidden rounded-2xl bg-zinc-900 shadow-md dark:ring-1 dark:ring-white/10">
<div class="flex min-h-[calc(theme(spacing.12)+1px)] flex-wrap items-start gap-x-4 border-b border-zinc-700 bg-zinc-800 px-4 dark:border-zinc-800 dark:bg-transparent">
<h3 class="mr-auto pt-3 text-xs font-semibold text-white">Example webhook payload</h3>
</div>
<div class="group dark:bg-white/2.5">
<div class="relative">
<pre class="overflow-x-auto p-4 text-xs text-white"><code class="language-json"><span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"id"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"a056V7R7NmNRjl70"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"type"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"conversation.updated"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"payload"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"id"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"WAz8eIbvDR60rouK"</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-comment)">// ...</span></span>
<span><span style="color: var(--shiki-color-text)"> }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span></code></pre>
<button type="button" class="group/button absolute top-3.5 right-4 overflow-hidden rounded-full py-1 pl-2 pr-3 text-2xs font-medium opacity-0 backdrop-blur transition focus:opacity-100 group-hover:opacity-100 bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 dark:hover:bg-white/5">
<span aria-hidden="false" class="pointer-events-none flex items-center gap-0.5 text-zinc-400 transition duration-300">
<svg viewBox="0 0 20 20" aria-hidden="true" class="h-5 w-5 fill-zinc-500/20 stroke-zinc-500 transition-colors group-hover/button:stroke-zinc-400">
<path stroke-width="0" d="M5.5 13.5v-5a2 2 0 0 1 2-2l.447-.894A2 2 0 0 1 9.737 4.5h.527a2 2 0 0 1 1.789 1.106l.447.894a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2Z"></path>
<path fill="none" stroke-linejoin="round" d="M12.5 6.5a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2m5 0-.447-.894a2 2 0 0 0-1.79-1.106h-.527a2 2 0 0 0-1.789 1.106L7.5 6.5m5 0-1 1h-3l-1-1"></path>
</svg>
Copy
</span>
<span aria-hidden="true" class="pointer-events-none absolute inset-0 flex items-center justify-center text-emerald-400 transition duration-300 translate-y-1.5 opacity-0">Copied!</span>
</button>
</div>
</div>
</div>
<p>In the example above, a conversation was <code>updated</code>, and the payload type is a <code>conversation</code>.</p>
<div class="not-prose">
<a class="inline-flex gap-0.5 justify-center overflow-hidden text-sm font-medium transition text-emerald-500 hover:text-emerald-600 dark:text-emerald-400 dark:hover:text-emerald-500" href="/webhooks#event-types">
See all event types
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true" class="mt-0.5 h-5 w-5 relative top-px -mr-1">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="m11.5 6.5 3 3.5m0 0-3 3.5m3-3.5h-9"></path>
</svg>
</a>
</div>
<hr>
<h2 id="event-types" class="scroll-mt-24"><a class="group text-inherit no-underline hover:text-inherit" href="/webhooks#event-types">Event types</a></h2>
<p>Here is a list of all the permissions:</p>
<div class="grid grid-cols-1 items-start gap-x-16 gap-y-10 xl:max-w-none xl:grid-cols-2">
<div class="[&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<div class="my-6">
<ul role="list" class="m-0 max-w-[calc(theme(maxWidth.lg)-theme(spacing.8))] list-none divide-y divide-zinc-900/5 p-0 dark:divide-white/5">
<% for(var i=0; i<pageData.permissions.length; i++) {%>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>contact.created</code></dd>
<dd><code class="inline-code"> <%= pageData.permissions[i].permission -%></code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"><%= pageData.permissions[i].title -%></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>A new contact was created.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>contact.updated</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>An existing contact was updated.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>contact.deleted</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>A contact was successfully deleted.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>conversation.created</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>A new conversation was created.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>conversation.updated</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>An existing conversation was updated.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>conversation.deleted</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>A conversation was successfully deleted.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>message.created</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>A new message was created.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>message.updated</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>An existing message was updated.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>message.deleted</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>A message was successfully deleted.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>group.created</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>A new group was created.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>group.updated</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>An existing group was updated.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>group.deleted</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>A group was successfully deleted.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>attachment.created</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>A new attachment was created.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>attachment.updated</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>An existing attachment was updated.</p>
</dd>
</dl>
</li>
<li class="m-0 px-0 py-4 first:pt-0 last:pb-0">
<dl class="m-0 flex flex-wrap items-center gap-x-3 gap-y-2">
<dt class="sr-only">Name</dt>
<dd><code>attachment.deleted</code></dd>
<dt class="sr-only">Type</dt>
<dd class="font-mono text-xs text-zinc-400 dark:text-zinc-500"></dd>
<dt class="sr-only">Description</dt>
<dd class="w-full flex-none [&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0">
<p>An attachment was successfully deleted.</p>
<p><%= pageData.permissions[i].description -%></p>
</dd>
</dl>
</li>
<% } %>
</ul>
</div>
</div>
<div class="[&amp;>:first-child]:mt-0 [&amp;>:last-child]:mb-0 xl:sticky xl:top-24">
<div class="not-prose my-6 overflow-hidden rounded-2xl bg-zinc-900 shadow-md dark:ring-1 dark:ring-white/10">
<div class="flex min-h-[calc(theme(spacing.12)+1px)] flex-wrap items-start gap-x-4 border-b border-zinc-700 bg-zinc-800 px-4 dark:border-zinc-800 dark:bg-transparent">
<h3 class="mr-auto pt-3 text-xs font-semibold text-white">Example payload</h3>
</div>
<div class="group dark:bg-white/2.5">
<div class="relative">
<pre class="overflow-x-auto p-4 text-xs text-white"><code class="language-json"><span><span style="color: var(--shiki-color-text)">{</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"id"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"a056V7R7NmNRjl70"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"type"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"message.updated"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"payload"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"id"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"SIuAFUNKdSYHZF2w"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"conversation_id"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"xgQQXg3hrtjh7AvZ"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"contact"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"id"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"WAz8eIbvDR60rouK"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"username"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"KevinMcCallister"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"phone_number"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"1-800-759-3000"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"avatar_url"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"https://assets.protocol.chat/avatars/kevin.jpg"</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"last_active_at"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">705103200</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"created_at"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">692233200</span></span>
<span><span style="color: var(--shiki-color-text)"> }</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"message"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">"Im traveling with my dad. Hes at a meeting. I hate meetings."</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"reactions"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> []</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"attachments"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> []</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"read_at"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">705103200</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"created_at"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">692233200</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">"updated_at"</span><span style="color: var(--shiki-token-punctuation)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">692233200</span></span>
<span><span style="color: var(--shiki-color-text)"> }</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span></code></pre>
<button type="button" class="group/button absolute top-3.5 right-4 overflow-hidden rounded-full py-1 pl-2 pr-3 text-2xs font-medium opacity-0 backdrop-blur transition focus:opacity-100 group-hover:opacity-100 bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 dark:hover:bg-white/5">
<span aria-hidden="false" class="pointer-events-none flex items-center gap-0.5 text-zinc-400 transition duration-300">
<svg viewBox="0 0 20 20" aria-hidden="true" class="h-5 w-5 fill-zinc-500/20 stroke-zinc-500 transition-colors group-hover/button:stroke-zinc-400">
<path stroke-width="0" d="M5.5 13.5v-5a2 2 0 0 1 2-2l.447-.894A2 2 0 0 1 9.737 4.5h.527a2 2 0 0 1 1.789 1.106l.447.894a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2Z"></path>
<path fill="none" stroke-linejoin="round" d="M12.5 6.5a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2m5 0-.447-.894a2 2 0 0 0-1.79-1.106h-.527a2 2 0 0 0-1.789 1.106L7.5 6.5m5 0-1 1h-3l-1-1"></path>
</svg>
Copy
</span>
<span aria-hidden="true" class="pointer-events-none absolute inset-0 flex items-center justify-center text-emerald-400 transition duration-300 translate-y-1.5 opacity-0">Copied!</span>
</button>
</div>
</div>
</div>
</div>
</div>
<hr>
<h2 id="security" class="scroll-mt-24"><a class="group text-inherit no-underline hover:text-inherit" href="/webhooks#security">Security</a></h2>
<p>To know for sure that a webhook was, in fact, sent by Protocol instead of a malicious actor, you can verify the request signature. Each webhook request contains a header named <code>x-protocol-signature</code>, and you can verify this signature by using your secret webhook key. The signature is an HMAC hash of the request payload hashed using your secret key. Here is an example of how to verify the signature in your app:</p>
<div class="not-prose my-6 overflow-hidden rounded-2xl bg-zinc-900 shadow-md dark:ring-1 dark:ring-white/10">
<div class="flex min-h-[calc(theme(spacing.12)+1px)] flex-wrap items-start gap-x-4 border-b border-zinc-700 bg-zinc-800 px-4 dark:border-zinc-800 dark:bg-transparent">
<h3 class="mr-auto pt-3 text-xs font-semibold text-white">Verifying a request</h3>
<div class="-mb-px flex gap-4 text-xs font-medium" role="tablist" aria-orientation="horizontal"><button class="border-b py-3 transition focus:[&amp;:not(:focus-visible)]:outline-none border-emerald-500 text-emerald-400" id="headlessui-tabs-tab-:r3:" role="tab" type="button" aria-selected="true" tabindex="0" data-headlessui-state="selected" aria-controls="headlessui-tabs-panel-:r6:">JavaScript</button><button class="border-b py-3 transition focus:[&amp;:not(:focus-visible)]:outline-none border-transparent text-zinc-400 hover:text-zinc-300" id="headlessui-tabs-tab-:r4:" role="tab" type="button" aria-selected="false" tabindex="-1" data-headlessui-state="" aria-controls="headlessui-tabs-panel-:r7:">Python</button><button class="border-b py-3 transition focus:[&amp;:not(:focus-visible)]:outline-none border-transparent text-zinc-400 hover:text-zinc-300" id="headlessui-tabs-tab-:r5:" role="tab" type="button" aria-selected="false" tabindex="-1" data-headlessui-state="" aria-controls="headlessui-tabs-panel-:r8:">PHP</button></div>
</div>
<div>
<div id="headlessui-tabs-panel-:r6:" role="tabpanel" tabindex="0" data-headlessui-state="selected" aria-labelledby="headlessui-tabs-tab-:r3:">
<div class="group dark:bg-white/2.5">
<div class="relative">
<pre class="overflow-x-auto p-4 text-xs text-white"><code class="language-js"><span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">signature</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">req</span><span style="color: var(--shiki-color-text)">.headers[</span><span style="color: var(--shiki-token-string-expression)">'x-protocol-signature'</span><span style="color: var(--shiki-color-text)">]</span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">hash</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">crypto</span><span style="color: var(--shiki-token-function)">.createHmac</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">'sha256'</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> secret)</span><span style="color: var(--shiki-token-function)">.update</span><span style="color: var(--shiki-color-text)">(payload)</span><span style="color: var(--shiki-token-function)">.digest</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">'hex'</span><span style="color: var(--shiki-color-text)">)</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">if</span><span style="color: var(--shiki-color-text)"> (hash </span><span style="color: var(--shiki-token-keyword)">===</span><span style="color: var(--shiki-color-text)"> signature) {</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-comment)">// Request is verified</span></span>
<span><span style="color: var(--shiki-color-text)">} </span><span style="color: var(--shiki-token-keyword)">else</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-comment)">// Request could not be verified</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span></code></pre>
<button type="button" class="group/button absolute top-3.5 right-4 overflow-hidden rounded-full py-1 pl-2 pr-3 text-2xs font-medium opacity-0 backdrop-blur transition focus:opacity-100 group-hover:opacity-100 bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 dark:hover:bg-white/5">
<span aria-hidden="false" class="pointer-events-none flex items-center gap-0.5 text-zinc-400 transition duration-300">
<svg viewBox="0 0 20 20" aria-hidden="true" class="h-5 w-5 fill-zinc-500/20 stroke-zinc-500 transition-colors group-hover/button:stroke-zinc-400">
<path stroke-width="0" d="M5.5 13.5v-5a2 2 0 0 1 2-2l.447-.894A2 2 0 0 1 9.737 4.5h.527a2 2 0 0 1 1.789 1.106l.447.894a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2Z"></path>
<path fill="none" stroke-linejoin="round" d="M12.5 6.5a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2m5 0-.447-.894a2 2 0 0 0-1.79-1.106h-.527a2 2 0 0 0-1.789 1.106L7.5 6.5m5 0-1 1h-3l-1-1"></path>
</svg>
Copy
</span>
<span aria-hidden="true" class="pointer-events-none absolute inset-0 flex items-center justify-center text-emerald-400 transition duration-300 translate-y-1.5 opacity-0">Copied!</span>
</button>
</div>
</div>
</div>
<span id="headlessui-tabs-panel-:r7:" role="tabpanel" tabindex="-1" style="position: fixed; top: 1px; left: 1px; width: 1px; height: 0px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; border-width: 0px;" aria-labelledby="headlessui-tabs-tab-:r4:"></span><span id="headlessui-tabs-panel-:r8:" role="tabpanel" tabindex="-1" style="position: fixed; top: 1px; left: 1px; width: 1px; height: 0px; padding: 0px; margin: -1px; overflow: hidden; clip: rect(0px, 0px, 0px, 0px); white-space: nowrap; border-width: 0px;" aria-labelledby="headlessui-tabs-tab-:r5:"></span>
</div>
</div>
<p>If your generated signature matches the <code>x-protocol-signature</code> header, you can be sure that the request was truly coming from Protocol. It's essential to keep your secret webhook key safe — otherwise, you can no longer be sure that a given webhook was sent by Protocol. Don't commit your secret webhook key to GitHub!</p>
</article>
</main>

View File

@ -3,8 +3,22 @@
<h3 class="mr-auto pt-3 text-xs font-semibold text-white"><%= title -%></h3>
</div>
<div class="group dark:bg-white/2.5">
<% if(requestType && requestUrl){ %>
<div class="flex h-9 items-center gap-2 border-b-white/7.5 bg-zinc-900 bg-white/2.5 px-4 dark:border-b-white/5 dark:bg-white/1 mb-2">
<% if( requestType === "GET"){ %>
<div class="dark flex"><span class="font-mono text-sm font-semibold leading-6 text-emerald-500 dark:text-emerald-400">GET</span></div>
<% } %>
<span class="h-0.5 w-0.5 rounded-full bg-zinc-500"></span><span class="font-mono text-sm text-zinc-300"><%= requestUrl -%></span>
</div>
<% } %>
<% if(code){ %>
<div class="relative">
<pre class="overflow-x-auto p-4 text-xs text-white"><code class="text-base"><%= code -%></code></pre>
<pre class="overflow-x-auto p-4 text-xs text-white"><code class="text-sm"><%= code -%></code></pre>
</div>
<% } %>
</div>
</div>

View File

@ -63,6 +63,10 @@
font-weight: unset;
}
.hljs-attr{
color: #fda4af;
}
* {
font-family: Inter;
}

View File

@ -73,6 +73,24 @@ export default class BaseAPI<
}
);
// List
router.get(
`${new this.entityType().getCrudApiPath()?.toString()}/get-list`,
UserMiddleware.getUserMiddleware,
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
) => {
try {
await this.getList(req, res);
} catch (err) {
next(err);
}
}
);
// count
router.post(
`${new this.entityType().getCrudApiPath()?.toString()}/count`,
@ -109,6 +127,25 @@ export default class BaseAPI<
}
);
// Get Item
router.get(
`${new this.entityType()
.getCrudApiPath()
?.toString()}/:id/get-item`,
UserMiddleware.getUserMiddleware,
async (
req: ExpressRequest,
res: ExpressResponse,
next: NextFunction
) => {
try {
await this.getItem(req, res);
} catch (err) {
next(err);
}
}
);
// Update
router.put(
`${new this.entityType().getCrudApiPath()?.toString()}/:id`,