# Webhooks — externally-triggered endpoints for agent/routine dispatch (PRD-19).

type Webhook {
  id: ID!
  tenantId: ID!
  name: String!
  description: String
  token: String!
  targetType: String!
  agentId: ID
  routineId: ID
  prompt: String
  config: AWSJSON
  enabled: Boolean!
  rateLimit: Int
  lastInvokedAt: AWSDateTime
  invocationCount: Int!
  createdByType: String
  createdById: String
  createdAt: AWSDateTime!
  updatedAt: AWSDateTime!
}

input CreateWebhookInput {
  tenantId: ID!
  name: String!
  description: String
  targetType: String!
  agentId: ID
  routineId: ID
  prompt: String
  config: AWSJSON
  rateLimit: Int
}

input UpdateWebhookInput {
  name: String
  description: String
  targetType: String
  agentId: ID
  routineId: ID
  prompt: String
  config: AWSJSON
  enabled: Boolean
  rateLimit: Int
}

"""
A single inbound webhook request as recorded by `POST /webhooks/{token}`.
Rows are PII-bearing (provider task titles, customer names, comment
text in `bodyPreview`); 90-day retention is enforced by a cleanup
Lambda. The GraphQL surface here intentionally redacts nothing — the
endpoint is admin-tier via `requireAdminOrServiceCaller`.
"""
type WebhookDelivery {
  id: ID!
  webhookId: ID
  tenantId: ID
  targetType: String
  providerName: String
  providerEventId: String
  externalTaskId: String
  providerUserId: String
  normalizedKind: String
  receivedAt: AWSDateTime!
  sourceIp: String
  bodyPreview: String
  bodySha256: String
  bodySizeBytes: Int
  signatureStatus: String!
  resolutionStatus: String!
  threadId: ID
  threadCreated: Boolean
  statusCode: Int
  errorMessage: String
  durationMs: Int
  retryCount: Int!
  isReplay: Boolean!
  createdAt: AWSDateTime!
}

extend type Query {
  webhooks(tenantId: ID!, targetType: String, enabled: Boolean, limit: Int): [Webhook!]!
  webhook(id: ID!): Webhook
  """
  List recent webhook deliveries for one webhook. Tenant-scoped via the
  webhook's row (cross-tenant ids return empty). Newest first. Hard
  cap of 500 rows; default 50.
  """
  webhookDeliveries(webhookId: ID!, limit: Int): [WebhookDelivery!]!
}

extend type Mutation {
  createWebhook(input: CreateWebhookInput!): Webhook!
  updateWebhook(id: ID!, input: UpdateWebhookInput!): Webhook!
  deleteWebhook(id: ID!): Boolean!
  regenerateWebhookToken(id: ID!): Webhook
  """
  Inserts a synthetic delivery row for the webhook so an operator can
  confirm the config exists and the delivery-log pipeline is reachable.
  Does NOT trigger any downstream dispatch — the row carries
  `resolutionStatus: "test"`, so a follow-up
  `webhookDeliveries(webhookId)` query shows it. For end-to-end
  reachability checks against the public URL, curl the webhook's
  token endpoint directly.
  """
  testWebhook(id: ID!): WebhookDelivery!
}
