Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
301 changes: 301 additions & 0 deletions spec/openapi.argus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ components:
schema:
type: string
format: uuid
deliveryID:
name: deliveryID
in: path
required: true
schema:
type: string
format: uuid

responses:
"400":
Expand Down Expand Up @@ -266,6 +273,159 @@ components:
type: string
description: Secret used to sign the webhook payloads

WebhookDelivery:
description: Webhook delivery attempt
required:
- id
- teamId
- webhookId
- eventId
- sandboxId
- eventType
- deliveryStatus
- durationMs
- requestUrl
- requestHeaders
- requestBody
- errorClass
- timestamp
properties:
id:
type: string
format: uuid
description: Delivery attempt identifier
teamId:
type: string
format: uuid
description: Team identifier
webhookId:
type: string
format: uuid
description: Webhook configuration identifier
eventId:
type: string
format: uuid
description: Sandbox event identifier
sandboxId:
type: string
description: Sandbox identifier
eventType:
type: string
description: Sandbox event type
deliveryStatus:
type: string
enum: [success, failed]
description: Delivery attempt status
httpStatusCode:
type: integer
format: int32
nullable: true
description: HTTP response status code, if a response was received
durationMs:
type: integer
format: int32
description: Delivery request duration in milliseconds
requestUrl:
type: string
format: uri
description: URL attempted for this delivery
requestHeaders:
type: string
description: JSON-encoded request headers with sensitive values redacted
requestBody:
type: string
description: Serialized webhook request body
responseHeaders:
type: string
nullable: true
description: JSON-encoded response headers, if a response was received
responseBody:
type: string
nullable: true
description: Truncated response body, if a response was received
errorClass:
type: string
description: Machine-readable non-HTTP or HTTP failure class
errorMessage:
type: string
nullable: true
description: Error message for failures without a useful response body
timestamp:
type: string
format: date-time
description: Time when the delivery attempt started

WebhookDeliveryStats:
description: Webhook delivery aggregate stats
required:
- buckets
- total
- failed
- minDurationMs
- avgDurationMs
- maxDurationMs
properties:
buckets:
type: array
items:
$ref: "#/components/schemas/WebhookDeliveryStatsBucket"
total:
type: integer
format: int64
failed:
type: integer
format: int64
minDurationMs:
type: integer
format: int32
avgDurationMs:
type: number
format: double
maxDurationMs:
type: integer
format: int32

WebhookDeliveryStatsBucket:
description: Webhook delivery stats for a time bucket
required:
- timestamp
- total
- failed
- avgDurationMs
properties:
timestamp:
type: string
format: date-time
total:
type: integer
format: int64
failed:
type: integer
format: int64
avgDurationMs:
type: number
format: double

WebhookDeliveryEvent:
description: Webhook delivery attempts grouped by sandbox event
required:
- eventId
- eventType
- sandboxId
- attempts
properties:
eventId:
type: string
format: uuid
eventType:
type: string
sandboxId:
type: string
attempts:
type: array
items:
$ref: "#/components/schemas/WebhookDelivery"

paths:
/health:
get:
Expand Down Expand Up @@ -501,5 +661,146 @@ paths:
$ref: "#/components/responses/404"
"401":
$ref: "#/components/responses/401"
"500":
$ref: "#/components/responses/500"

/events/webhooks/{webhookID}/deliveries:
get:
operationId: webhookDeliveriesList
description: List webhook delivery attempts.
tags: [webhooks]
security:
- ApiKeyAuth: []
- Supabase1TokenAuth: []
Supabase2TeamAuth: []
parameters:
- $ref: "#/components/parameters/webhookID"
- name: cursor
in: query
required: false
schema:
type: string
description: Opaque cursor from the X-Next-Cursor response header.
- name: limit
in: query
required: false
schema:
type: integer
format: int32
minimum: 1
maximum: 100
default: 25
- name: orderAsc
in: query
required: false
schema:
type: boolean
default: false
- name: deliveryStatus
in: query
required: false
style: form
explode: true
schema:
type: array
items:
type: string
enum: [success, failed]
description: Filter deliveries by delivery status
- name: eventType
in: query
required: false
style: form
explode: true
schema:
type: array
items:
type: string
description: Filter deliveries by event type
responses:
"200":
description: List of webhook delivery attempts grouped by event.
headers:
X-Next-Cursor:
description: Cursor to pass to the next list request, omitted when there is no next page.
schema:
type: string
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/WebhookDeliveryEvent"
"400":
$ref: "#/components/responses/400"
"404":
$ref: "#/components/responses/404"
"401":
$ref: "#/components/responses/401"
"500":
$ref: "#/components/responses/500"

/events/webhooks/{webhookID}/deliveries/{deliveryID}:
get:
operationId: webhookDeliveryGet
description: Get a webhook delivery attempt.
tags: [webhooks]
security:
- ApiKeyAuth: []
- Supabase1TokenAuth: []
Supabase2TeamAuth: []
parameters:
- $ref: "#/components/parameters/webhookID"
- $ref: "#/components/parameters/deliveryID"
responses:
"200":
description: Webhook delivery attempt.
content:
application/json:
schema:
$ref: "#/components/schemas/WebhookDelivery"
"404":
$ref: "#/components/responses/404"
"401":
$ref: "#/components/responses/401"
"500":
$ref: "#/components/responses/500"

/events/webhooks/{webhookID}/stats:
get:
operationId: webhookDeliveryStats
description: Get webhook delivery aggregate stats.
tags: [webhooks]
security:
- ApiKeyAuth: []
- Supabase1TokenAuth: []
Supabase2TeamAuth: []
parameters:
- $ref: "#/components/parameters/webhookID"
- name: start
in: query
required: false
schema:
type: string
format: date-time
description: Inclusive stats range start. Defaults to 24 hours ago.
- name: end
in: query
required: false
schema:
type: string
format: date-time
description: Exclusive stats range end. Defaults to now.
responses:
"200":
description: Webhook delivery stats.
content:
application/json:
schema:
$ref: "#/components/schemas/WebhookDeliveryStats"
"404":
$ref: "#/components/responses/404"
"401":
$ref: "#/components/responses/401"
"500":
$ref: "#/components/responses/500"
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { WebhookDeliveriesContent } from '@/features/dashboard/settings/webhooks/detail'
import { prefetch, trpc } from '@/trpc/server'

type WebhookDeliveriesPageProps = {
params: Promise<{
teamSlug: string
webhookId: string
}>
}

export default async function WebhookDeliveriesPage({
params,
}: WebhookDeliveriesPageProps) {
const { teamSlug, webhookId } = await params

prefetch(
trpc.webhooks.listDeliveries.infiniteQueryOptions({
teamSlug,
webhookId,
limit: 25,
deliveryStatus: 'all',
})
)

return <WebhookDeliveriesContent teamSlug={teamSlug} webhookId={webhookId} />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { notFound } from 'next/navigation'
import { INCLUDE_ARGUS } from '@/configs/flags'
import { WebhookDetailLayout } from '@/features/dashboard/settings/webhooks/detail'
import { HydrateClient, prefetch, trpc } from '@/trpc/server'

type WebhookTabsLayoutProps = {
children: React.ReactNode
params: Promise<{
teamSlug: string
webhookId: string
}>
}

export default async function WebhookTabsLayout({
children,
params,
}: WebhookTabsLayoutProps) {
if (!INCLUDE_ARGUS) {
return notFound()
}

const { teamSlug, webhookId } = await params

prefetch(trpc.webhooks.get.queryOptions({ teamSlug, webhookId }))

return (
<HydrateClient>
<WebhookDetailLayout teamSlug={teamSlug} webhookId={webhookId}>
{children}
</WebhookDetailLayout>
</HydrateClient>
)
}
Loading
Loading