openapi: 3.2.0 info: title: Hookbase Sources API version: 1.0.0 description: Official OpenAPI 3.0 specification for the Hookbase webhook relay platform. Generated from the maintained Postman collection. Authenticate with an API key (whr_ prefix) as a Bearer token. contact: name: Hookbase url: https://www.hookbase.app servers: - url: https://api.hookbase.app description: Production security: - bearerAuth: [] tags: - name: Sources paths: /api/sources: post: tags: - Sources summary: Create source operationId: sources_create_source responses: '200': description: Created source. Includes the full signingSecret (once) and, for WhatsApp, verifyToken. content: application/json: schema: type: object properties: source: $ref: '#/components/schemas/CreatedSource' '400': description: Invalid body, unknown provider, unknown field, missing/ill-formatted vendor-issued secret, a secret sent for a built-in-key provider, verifyToken for a non-Meta provider, or duplicate slug. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Plan limit reached or feature not on plan. content: application/json: schema: $ref: '#/components/schemas/Error' description: 'Create an inbound source. Its `slug` becomes the public ingest path `/ingest/{orgSlug}/{slug}`. The body is strict: unknown fields are a 400.' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: Required. Display name (1–100 chars). slug: type: string description: Required. URL-safe id (1–50 chars, [a-z0-9-]); becomes the ingest path. provider: type: string description: 'Optional. Provider id selecting the signature scheme: any provider Hookbase verifies, plus custom (and its alias generic). Unknown values are a 400. List them with GET /api/catalog/providers (use an entry''s hookbaseProvider). Omit to verify as custom.' description: type: string description: Optional. Freeform description. signingSecret: type: string description: 'Optional. Secret or public key the signature is checked against; rules depend on the provider (catalog signatureVerification.secretSource). provider-issued: paste the vendor value (Standard Webhooks/whsec_ providers, airtable, gitlab-signing-token, supabase-auth-hooks: required and format-checked). operator: omit to have one generated and returned once. public_key: required. built_in (wise, wise-sandbox, aws-sns): must be omitted (400). asana/notion: omit; the vendor issues it after registration.' verifyToken: type: string description: 'Optional. WhatsApp (Meta) only: the Verify token Meta checks at registration, 8-256 visible ASCII characters. Generated when omitted. 400 for any other provider.' rejectInvalidSignatures: type: boolean description: Optional. Reject events whose signature fails verification. rateLimitPerMinute: type: integer description: Optional. Max inbound events/min (1–100000); null = unlimited. ipFilterMode: type: string description: 'Optional. IP filtering: none | allowlist | denylist | both.' ipAllowlist: type: array items: type: string description: Optional. CIDRs/IPs allowed (used when ipFilterMode includes allowlist). ipDenylist: type: array items: type: string description: Optional. CIDRs/IPs blocked (used when ipFilterMode includes denylist). encryptFields: type: array items: type: string description: Optional. JSON paths encrypted at rest. maskFields: type: array items: type: string description: Optional. JSON paths masked in the dashboard. dedupEnabled: type: boolean description: Optional. Enable event deduplication. dedupStrategy: type: string description: Optional. auto | provider_id | payload_hash | idempotency_key | none. dedupWindowHours: type: integer description: Optional. Dedup look-back window in hours (1–168). dedupCustomHeader: type: string description: Optional. Header to dedupe on (max 100 chars). transientMode: type: boolean description: 'Optional. Process-and-forget: don''t persist payloads.' allowedMethods: type: array items: type: string description: 'Optional. Accepted ingest HTTP methods: GET, POST, PUT, PATCH, DELETE, HEAD. Empty/omitted = any.' required: - name - slug additionalProperties: false example: name: GitHub Webhooks slug: github-webhooks provider: github description: Production org webhooks signingSecret: whsec_xxx rejectInvalidSignatures: true rateLimitPerMinute: 1000 ipFilterMode: none ipAllowlist: - 203.0.113.0/24 ipDenylist: - 198.51.100.7 encryptFields: - data.card.number maskFields: - data.email dedupEnabled: false dedupStrategy: auto dedupWindowHours: 24 dedupCustomHeader: X-Idempotency-Key transientMode: false allowedMethods: - POST get: tags: - Sources summary: List sources operationId: sources_list_sources parameters: - name: page in: query required: false schema: type: string example: '1' - name: pageSize in: query required: false schema: type: string example: '20' responses: '200': description: Sources (without ingestUrl) and pagination. content: application/json: schema: type: object properties: sources: type: array items: $ref: '#/components/schemas/Source' pagination: type: object properties: total: type: integer page: type: integer pageSize: type: integer description: List sources for the org (paginated), each with event and route counts. /api/sources/{sourceId}: get: tags: - Sources summary: Get source by id operationId: sources_get_source_by_id parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: The source. content: application/json: schema: type: object properties: source: $ref: '#/components/schemas/Source' '404': description: Source not found. content: application/json: schema: $ref: '#/components/schemas/Error' description: Fetch a single source by id or slug (signing secret masked). patch: tags: - Sources summary: Update source operationId: sources_update_source parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: 'Acknowledged ({"success": true}); read the source back for the new state.' '400': description: Invalid body or secret/verify-token rule violated. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Source not found. content: application/json: schema: $ref: '#/components/schemas/Error' description: Update a source. All fields optional; omitted fields are unchanged. requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: Optional. Display name (1–100 chars). description: type: string description: Optional. Freeform description (null to clear). provider: type: - string - 'null' description: 'Optional. Provider id selecting the signature scheme: any provider Hookbase verifies, plus custom (and its alias generic). Unknown values are a 400. List them with GET /api/catalog/providers (use an entry''s hookbaseProvider). null falls back to custom.' isActive: type: boolean description: Optional. Enable/disable ingestion for this source. signingSecret: type: - string - 'null' description: Optional. Replace the signing secret; null or "" clears it. Validated against the provider the source will have after the update. Switching to a vendor-issued-secret provider requires the new secret in the same request. verifyToken: type: - string - 'null' description: 'Optional. WhatsApp (Meta) only: set the Verify token; null or "" generates a new one. 400 for any other provider.' rejectInvalidSignatures: type: boolean description: Optional. Reject events failing signature verification. rateLimitPerMinute: type: integer description: Optional. Max inbound events/min (1–100000); null = unlimited. ipFilterMode: type: string description: Optional. none | allowlist | denylist | both. ipAllowlist: type: array items: type: string description: Optional. Allowed CIDRs/IPs. ipDenylist: type: array items: type: string description: Optional. Blocked CIDRs/IPs. encryptFields: type: array items: type: string description: Optional. JSON paths encrypted at rest. maskFields: type: array items: type: string description: Optional. JSON paths masked in the dashboard. dedupEnabled: type: boolean description: Optional. Enable deduplication. dedupStrategy: type: string description: Optional. auto | provider_id | payload_hash | idempotency_key | none. dedupWindowHours: type: integer description: Optional. Dedup window hours (1–168). dedupCustomHeader: type: string description: Optional. Header to dedupe on (max 100). transientMode: type: boolean description: Optional. Process-and-forget mode. allowedMethods: type: array items: type: string description: Optional. Accepted ingest methods (empty/null = any). additionalProperties: false example: name: GitHub Webhooks description: Updated description provider: github isActive: true signingSecret: whsec_new rejectInvalidSignatures: true rateLimitPerMinute: 1000 ipFilterMode: none ipAllowlist: - 203.0.113.0/24 ipDenylist: - 198.51.100.7 encryptFields: - data.card.number maskFields: - data.email dedupEnabled: false dedupStrategy: auto dedupWindowHours: 24 dedupCustomHeader: X-Idempotency-Key transientMode: false allowedMethods: - POST /api/sources/{sourceId}/rotate-secret: post: tags: - Sources summary: Rotate signing secret operationId: sources_rotate_signing_secret parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: The new secret. content: application/json: schema: type: object properties: signingSecret: type: string '400': description: The provider has no secret Hookbase can generate. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Source not found. content: application/json: schema: $ref: '#/components/schemas/Error' description: 'Generate a new signing secret and return it once. Meant for Hookbase-generated secrets (catalog secretSource operator, or custom sources); paste the new value into the vendor. Refused with 400 for built-in-key providers (wise, wise-sandbox, aws-sns), public-key providers (discord, sendgrid), vendor-issued base64 keys (Standard Webhooks/whsec_ providers, airtable, gitlab-signing-token, supabase-auth-hooks) and asana/notion: rotate those at the vendor and PATCH signingSecret.' /api/sources/{sourceId}/reveal-secret: get: tags: - Sources summary: Reveal signing secret operationId: sources_reveal_signing_secret parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: The secret. content: application/json: schema: type: object properties: signingSecret: type: string '404': description: Source not found or no signing secret stored. content: application/json: schema: $ref: '#/components/schemas/Error' description: Return the source's current signing secret in plaintext. Requires a write-scoped API key. /api/sources/{sourceId}/verify-token: get: tags: - Sources summary: Get verify token operationId: sources_get_verify_token parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: The verify token. content: application/json: schema: type: object properties: verifyToken: type: string '400': description: The provider has no verify token. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Source not found. content: application/json: schema: $ref: '#/components/schemas/Error' description: 'WhatsApp (Meta) only: return the Verify token Meta checks at registration. Requires a write-scoped API key.' /api/sources/{sourceId}/rotate-verify-token: post: tags: - Sources summary: Rotate verify token operationId: sources_rotate_verify_token parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: The verify token. content: application/json: schema: type: object properties: verifyToken: type: string '400': description: The provider has no verify token. content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Source not found. content: application/json: schema: $ref: '#/components/schemas/Error' description: 'WhatsApp (Meta) only: generate a new Verify token and return it. The old token stops working at once.' /api/sources/{sourceId}/pending-verification: get: tags: - Sources summary: Get pending verification token operationId: sources_get_pending_verification parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: The pending token. content: application/json: schema: type: object properties: provider: type: string token: type: string receivedAt: type: string format: date-time clientIp: type: - string - 'null' '404': description: Source not found, or no verification token is waiting. content: application/json: schema: $ref: '#/components/schemas/Error' description: Return a verification token the vendor (Notion) delivered to the ingest URL during registration and Hookbase is holding (24h) until adopted. Requires a write-scoped API key. /api/sources/{sourceId}/pending-verification/adopt: post: tags: - Sources summary: Adopt pending verification token operationId: sources_adopt_pending_verification parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: '{"success": true}' '404': description: Source not found, or no verification token is waiting. content: application/json: schema: $ref: '#/components/schemas/Error' description: Make the pending verification token the source's signing secret (after the vendor shows the subscription verified). Deletes the pending entry. /api/sources/{sourceId}/simulate: post: tags: - Sources summary: Simulate webhook pipeline operationId: sources_simulate_webhook_pipeline parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: Successful response description: Dry-run the full ingest→route→transform pipeline for a source. Provide exactly one of payload, payloadString, or fromEventId. requestBody: required: false content: application/json: schema: type: object properties: payload: type: object description: Optional. Inline JSON payload to simulate. payloadString: type: string description: Optional. Raw string payload (alternative to payload). fromEventId: type: string description: Optional. Replay an existing event's payload by id (UUID). headers: type: object description: Optional. Request headers to simulate. eventType: type: string description: Optional. Event type label for the simulated event. example: payload: action: opened number: 1 payloadString: '{"raw":"body"}' fromEventId: '{{eventId}}' headers: X-GitHub-Event: push eventType: push /api/sources/export: get: tags: - Sources summary: Export sources operationId: sources_export_sources parameters: - name: includeSensitive in: query required: false schema: type: string example: 'false' responses: '200': description: Successful response description: Export all sources (or a subset via ?ids=) as a portable JSON config document. `includeSensitive=true` includes signing secrets. /api/sources/import: post: tags: - Sources summary: Import sources operationId: sources_import_sources responses: '200': description: Successful response description: Import sources from the export format. Slugs that already exist are handled per `conflictStrategy`. requestBody: required: true content: application/json: schema: type: object properties: sources: type: array items: type: object description: Required. Array of source configs in the /export shape. conflictStrategy: type: string description: 'Required. On existing slug: skip | rename | overwrite.' validateOnly: type: boolean description: Optional. Validate without persisting. required: - sources - conflictStrategy example: sources: - name: GitHub Webhooks slug: github-webhooks provider: github conflictStrategy: skip validateOnly: false /api/sources/{sourceId}/schema-baseline: get: tags: - Sources summary: Get schema baseline (Pro+) operationId: sources_get_schema_baseline_pro parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: Successful response description: Return the inferred payload schema baseline used for drift detection (Pro plan and above). patch: tags: - Sources summary: Toggle schema drift detection (Pro+) operationId: sources_toggle_schema_drift_detection_pro parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: Successful response description: Enable or disable schema-drift detection for the source (Pro+). requestBody: required: true content: application/json: schema: type: object properties: driftEnabled: type: boolean description: Required. Turn drift detection on/off. required: - driftEnabled example: driftEnabled: true /api/sources/{sourceId}/schema-baseline/refresh: post: tags: - Sources summary: Refresh schema baseline (Pro+) operationId: sources_refresh_schema_baseline_pro parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. responses: '200': description: Successful response description: Recompute the source's schema baseline from recent events (Pro+). /api/sources/{sourceId}/schema-drift-events: get: tags: - Sources summary: List schema drift events (Pro+) operationId: sources_list_schema_drift_events_pro parameters: - name: sourceId in: path required: true schema: type: string description: Source ID or slug. - name: limit in: query required: false schema: type: string example: '50' responses: '200': description: Successful response description: List recent schema-drift events detected for the source (Pro+). /api/sources/bulk: delete: tags: - Sources summary: Bulk delete sources operationId: sources_bulk_delete_sources responses: '200': description: Successful response description: Delete multiple sources by id in one call (max 100). requestBody: required: true content: application/json: schema: type: object properties: ids: type: array items: type: string description: Required. Source ids to delete (max 100). required: - ids example: ids: - '{{sourceId}}' components: schemas: Error: type: object properties: error: type: string description: Human-readable reason. CreatedSource: allOf: - $ref: '#/components/schemas/Source' - type: object properties: signingSecret: type: - string - 'null' description: The full secret, returned only here. Hookbase-generated when omitted for providers that take an operator-chosen secret. null for built-in-key providers and for asana/notion until the vendor issues it. verifyToken: type: string description: 'WhatsApp only: the Meta Verify token, returned in full only here.' Source: type: object description: A source. The full signing secret is never included except in the create response. properties: id: type: string format: uuid organizationId: type: string format: uuid name: type: string slug: type: string provider: type: - string - 'null' description: Provider id selecting the signature scheme. null verifies as custom. description: type: - string - 'null' hasSigningSecret: type: boolean description: A signing secret is stored. signingSecretLast4: type: - string - 'null' description: Last four characters of the stored secret, e.g. "...a1b2". awaitingSigningSecret: type: boolean description: true when the provider issues its secret only after the ingest URL is registered (asana, notion) and none is set yet. Events are accepted unverified until it is. verifiesWithoutSecret: type: boolean description: true when the provider is verified with a key Hookbase already has (wise, wise-sandbox, aws-sns); no secret is stored or needed. rejectInvalidSignatures: type: boolean rateLimitPerMinute: type: - integer - 'null' isActive: type: boolean customDomainId: type: - string - 'null' ipFilterMode: type: string enum: - none - allowlist - denylist - both ipAllowlist: type: array items: type: string ipDenylist: type: array items: type: string encryptFields: type: array items: type: string maskFields: type: array items: type: string dedupEnabled: type: boolean dedupStrategy: type: string enum: - auto - provider_id - payload_hash - idempotency_key - none dedupWindowHours: type: integer dedupCustomHeader: type: - string - 'null' transientMode: type: boolean allowedMethods: type: array items: type: string description: '[] = any method.' createdAt: type: string format: date-time updatedAt: type: string format: date-time eventCount: type: integer routeCount: type: integer ingestUrl: type: string description: Get and create responses only. securitySchemes: bearerAuth: type: http scheme: bearer description: Hookbase API key with the whr_ prefix.