openapi: 3.1.0 info: title: Outpost API version: "0.0.1" description: The Outpost API is a REST-based JSON API for managing tenants, destinations, and publishing events. contact: name: Outpost Support email: support@hookdeck.com url: https://outpost.hookdeck.com/docs security: - AdminApiKey: [] - TenantJwt: [] servers: - url: http://localhost:3333/api/v1 description: Local development server base path components: securitySchemes: AdminApiKey: type: http scheme: bearer description: Admin API Key configured via API_KEY environment variable. TenantJwt: type: http scheme: bearer bearerFormat: JWT description: Per-tenant JWT token valid for 24 hours. When used, tenant_id path parameter is inferred. schemas: # Base Schemas Tenant: type: object properties: id: type: string description: User-defined system ID for the tenant. example: "123" destinations_count: type: integer description: Number of destinations associated with the tenant. example: 5 topics: type: array items: type: string description: List of subscribed topics across all destinations for this tenant. example: ["user.created", "user.deleted"] created_at: type: string format: date-time description: ISO Date when the tenant was created. example: "2024-01-01T00:00:00Z" PortalRedirect: type: object properties: redirect_url: type: string format: url description: Redirect URL containing a JWT to authenticate the user with the portal. example: "https://webhooks.acme.com/?token=JWT_TOKEN" TenantToken: type: object properties: token: type: string description: JWT token scoped to the tenant for safe browser API calls. example: "SOME_JWT_TOKEN" SuccessResponse: type: object properties: success: type: boolean example: true Topics: oneOf: - type: string enum: ["*"] - type: array items: type: string description: '"*" or an array of enabled topics.' example: "*" # Destination Type Specific Config/Credentials Schemas WebhookConfig: type: object required: [url] properties: url: type: string format: url description: The URL to send the webhook events to. example: "https://example.com/webhooks/user" WebhookCredentials: type: object properties: secret: type: string description: The secret used for signing webhook requests. Auto-generated if omitted on creation by admin. Read-only for tenants unless rotating. example: "whsec_abc123" previous_secret: type: string description: The previous secret used during rotation. Valid for 24 hours by default. Read-only. example: "whsec_xyz789" previous_secret_invalid_at: type: string format: date-time description: ISO timestamp when the previous secret becomes invalid. Read-only. example: "2024-01-02T00:00:00Z" AWSSQSConfig: type: object required: [queue_url] properties: endpoint: type: string format: url description: Optional. Custom AWS endpoint URL (e.g., for LocalStack or specific regions). example: "https://sqs.us-east-1.amazonaws.com" # Corrected Example queue_url: type: string format: url # Technically an ARN/URL hybrid, but URL format is close enough description: The URL of the SQS queue. example: "https://sqs.us-east-1.amazonaws.com/123456789012/my-queue" AWSSQSCredentials: type: object required: [key, secret] properties: key: type: string description: AWS Access Key ID. example: "AKIAIOSFODNN7EXAMPLE" secret: type: string description: AWS Secret Access Key. example: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" session: type: string description: Optional AWS Session Token (for temporary credentials). example: "AQoDYXdzEPT//////////wEXAMPLE..." RabbitMQConfig: type: object required: [server_url, exchange] properties: server_url: type: string description: RabbitMQ server address (host:port). example: "localhost:5672" exchange: type: string description: The exchange to publish messages to. example: "my-exchange" tls: type: string enum: ["true", "false"] description: Whether to use TLS connection (amqps). Defaults to "false". example: "false" RabbitMQCredentials: type: object required: [username, password] properties: username: type: string description: RabbitMQ username. example: "guest" password: type: string description: RabbitMQ password. example: "guest" HookdeckCredentials: # Hookdeck has no config fields, only credentials type: object required: [token] properties: token: type: string description: Hookdeck authentication token. example: "hd_token_..." AWSKinesisConfig: type: object required: [stream_name, region] properties: stream_name: type: string description: The name of the AWS Kinesis stream. example: "my-data-stream" region: type: string description: The AWS region where the Kinesis stream is located. example: "us-east-1" endpoint: type: string format: url description: Optional. Custom AWS endpoint URL (e.g., for LocalStack or VPC endpoints). example: "https://kinesis.us-east-1.amazonaws.com" partition_key_template: type: string description: Optional. JMESPath template to extract the partition key from the event payload (e.g., `metadata."event-id"`). Defaults to event ID. example: 'data."user_id"' AWSKinesisCredentials: type: object required: [key, secret] properties: key: type: string description: AWS Access Key ID. example: "AKIAIOSFODNN7EXAMPLE" secret: type: string description: AWS Secret Access Key. example: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" session: type: string description: Optional AWS Session Token (for temporary credentials). example: "AQoDYXdzEPT//////////wEXAMPLE..." # Type-Specific Destination Schemas (for Responses) DestinationWebhook: type: object # Properties duplicated from DestinationBase required: [id, type, topics, config, credentials, created_at, disabled_at] properties: id: type: string description: Control plane generated ID or user provided ID for the destination. example: "des_12345" type: type: string description: Type of the destination. enum: [webhook] # Specific type example: "webhook" topics: $ref: "#/components/schemas/Topics" disabled_at: type: string format: date-time nullable: true description: ISO Date when the destination was disabled, or null if enabled. example: null created_at: type: string format: date-time description: ISO Date when the destination was created. example: "2024-01-01T00:00:00Z" # Type-specific properties config: $ref: "#/components/schemas/WebhookConfig" credentials: $ref: "#/components/schemas/WebhookCredentials" target: type: string description: A human-readable representation of the destination target (e.g., URL host). Read-only. readOnly: true example: "my-service.com" target_url: type: string format: url nullable: true # Should always have a URL for webhook description: A URL link to the destination target (the webhook URL). Read-only. readOnly: true example: "https://my-service.com/webhook/handler" example: id: "des_webhook_123" type: "webhook" topics: ["user.created", "order.shipped"] disabled_at: null created_at: "2024-02-15T10:00:00Z" config: url: "https://my-service.com/webhook/handler" credentials: secret: "whsec_abc123def456" previous_secret: "whsec_prev789xyz012" previous_secret_invalid_at: "2024-02-16T10:00:00Z" DestinationAWSSQS: type: object # Properties duplicated from DestinationBase required: [id, type, topics, config, credentials, created_at, disabled_at] properties: id: type: string description: Control plane generated ID or user provided ID for the destination. example: "des_12345" type: type: string description: Type of the destination. enum: [aws_sqs] # Specific type example: "aws_sqs" topics: $ref: "#/components/schemas/Topics" disabled_at: type: string format: date-time nullable: true description: ISO Date when the destination was disabled, or null if enabled. example: null created_at: type: string format: date-time description: ISO Date when the destination was created. example: "2024-01-01T00:00:00Z" # Type-specific properties config: $ref: "#/components/schemas/AWSSQSConfig" credentials: $ref: "#/components/schemas/AWSSQSCredentials" target: type: string description: A human-readable representation of the destination target (SQS queue name). Read-only. readOnly: true example: "my-app-queue" target_url: type: string format: url nullable: true # Can construct AWS console URL description: A URL link to the destination target (AWS Console link to the queue). Read-only. readOnly: true example: "https://us-west-2.console.aws.amazon.com/sqs/v2/home?region=us-west-2#/queues/https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F123456789012%2Fmy-app-queue" example: id: "des_sqs_456" type: "aws_sqs" topics: ["*"] disabled_at: "2024-03-01T12:00:00Z" created_at: "2024-02-20T11:30:00Z" config: queue_url: "https://sqs.us-west-2.amazonaws.com/123456789012/my-app-queue" endpoint: "https://sqs.us-west-2.amazonaws.com" credentials: key: "AKIAIOSFODNN7EXAMPLE" secret: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" DestinationRabbitMQ: type: object # Properties duplicated from DestinationBase required: [id, type, topics, config, credentials, created_at, disabled_at] properties: id: type: string description: Control plane generated ID or user provided ID for the destination. example: "des_12345" type: type: string description: Type of the destination. enum: [rabbitmq] # Specific type example: "rabbitmq" topics: $ref: "#/components/schemas/Topics" disabled_at: type: string format: date-time nullable: true description: ISO Date when the destination was disabled, or null if enabled. example: null created_at: type: string format: date-time description: ISO Date when the destination was created. example: "2024-01-01T00:00:00Z" # Type-specific properties config: $ref: "#/components/schemas/RabbitMQConfig" credentials: $ref: "#/components/schemas/RabbitMQCredentials" target: type: string description: A human-readable representation of the destination target (RabbitMQ exchange). Read-only. readOnly: true example: "events-exchange" target_url: type: string format: url nullable: true # No direct URL for an exchange description: A URL link to the destination target (not applicable for RabbitMQ exchange). Read-only. readOnly: true example: null example: id: "des_rmq_789" type: "rabbitmq" topics: ["inventory.updated"] disabled_at: null created_at: "2024-01-10T09:00:00Z" config: server_url: "amqp.cloudamqp.com:5671" exchange: "events-exchange" tls: "true" credentials: username: "app_user" password: "secure_password_123" DestinationHookdeck: type: object # Properties duplicated from DestinationBase required: [id, type, topics, credentials, created_at, disabled_at] # No config properties: id: type: string description: Control plane generated ID or user provided ID for the destination. example: "des_12345" type: type: string description: Type of the destination. enum: [hookdeck] # Specific type example: "hookdeck" topics: $ref: "#/components/schemas/Topics" disabled_at: type: string format: date-time nullable: true description: ISO Date when the destination was disabled, or null if enabled. example: null created_at: type: string format: date-time description: ISO Date when the destination was created. example: "2024-01-01T00:00:00Z" # Type-specific properties config: {} # Empty config credentials: $ref: "#/components/schemas/HookdeckCredentials" target: type: string description: A human-readable representation of the destination target (Hookdeck). Read-only. readOnly: true example: "Hookdeck" target_url: type: string format: url nullable: true # Link to Hookdeck dashboard? TBD description: A URL link to the destination target (e.g., Hookdeck dashboard). Read-only. readOnly: true example: "https://dashboard.hookdeck.com/sources/src_xxxyyyzzz" example: id: "des_hkd_abc" type: "hookdeck" topics: ["*"] disabled_at: null created_at: "2024-04-01T10:00:00Z" config: {} credentials: token: "hd_token_..." DestinationAWSKinesis: type: object # Properties duplicated from DestinationBase required: [id, type, topics, config, credentials, created_at, disabled_at] properties: id: type: string description: Control plane generated ID or user provided ID for the destination. example: "des_12345" type: type: string description: Type of the destination. enum: [aws_kinesis] # Specific type example: "aws_kinesis" topics: $ref: "#/components/schemas/Topics" disabled_at: type: string format: date-time nullable: true description: ISO Date when the destination was disabled, or null if enabled. example: null created_at: type: string format: date-time description: ISO Date when the destination was created. example: "2024-01-01T00:00:00Z" # Type-specific properties config: $ref: "#/components/schemas/AWSKinesisConfig" credentials: $ref: "#/components/schemas/AWSKinesisCredentials" target: type: string description: A human-readable representation of the destination target (Kinesis stream name). Read-only. readOnly: true example: "production-events" target_url: type: string format: url nullable: true # Can construct AWS console URL description: A URL link to the destination target (AWS Console link to the stream). Read-only. readOnly: true example: "https://eu-west-1.console.aws.amazon.com/kinesis/home?region=eu-west-1#/streams/details/production-events/details" example: id: "des_kns_xyz" type: "aws_kinesis" topics: ["user.created", "user.updated"] disabled_at: null created_at: "2024-03-10T15:30:00Z" config: stream_name: "production-events" region: "eu-west-1" credentials: key: "AKIAIOSFODNN7EXAMPLE" secret: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" # Polymorphic Destination Schema (for Responses) Destination: oneOf: - $ref: "#/components/schemas/DestinationWebhook" - $ref: "#/components/schemas/DestinationAWSSQS" - $ref: "#/components/schemas/DestinationRabbitMQ" - $ref: "#/components/schemas/DestinationHookdeck" - $ref: "#/components/schemas/DestinationAWSKinesis" discriminator: propertyName: type mapping: webhook: "#/components/schemas/DestinationWebhook" aws_sqs: "#/components/schemas/DestinationAWSSQS" rabbitmq: "#/components/schemas/DestinationRabbitMQ" hookdeck: "#/components/schemas/DestinationHookdeck" aws_kinesis: "#/components/schemas/DestinationAWSKinesis" DestinationCreateWebhook: type: object # Properties duplicated from DestinationCreateBase required: [type, topics, config] # Credentials not required for webhook create base properties: id: type: string description: Optional user-provided ID. A UUID will be generated if empty. example: "user-provided-id" type: type: string description: Type of the destination. Must be 'webhook'. enum: [webhook] # Specific type topics: $ref: "#/components/schemas/Topics" # Type-specific properties config: $ref: "#/components/schemas/WebhookConfig" credentials: # Secret is optional on create for admin, forbidden for tenant $ref: "#/components/schemas/WebhookCredentials" DestinationCreateAWSSQS: type: object # Properties duplicated from DestinationCreateBase + specific required required: [type, topics, config, credentials] properties: id: type: string description: Optional user-provided ID. A UUID will be generated if empty. example: "user-provided-id" type: type: string description: Type of the destination. Must be 'aws_sqs'. enum: [aws_sqs] # Specific type topics: $ref: "#/components/schemas/Topics" # Type-specific properties config: $ref: "#/components/schemas/AWSSQSConfig" credentials: $ref: "#/components/schemas/AWSSQSCredentials" DestinationCreateRabbitMQ: type: object # Properties duplicated from DestinationCreateBase + specific required required: [type, topics, config, credentials] properties: id: type: string description: Optional user-provided ID. A UUID will be generated if empty. example: "user-provided-id" type: type: string description: Type of the destination. Must be 'rabbitmq'. enum: [rabbitmq] # Specific type topics: $ref: "#/components/schemas/Topics" # Type-specific properties config: $ref: "#/components/schemas/RabbitMQConfig" credentials: $ref: "#/components/schemas/RabbitMQCredentials" DestinationCreateHookdeck: type: object # Properties duplicated from DestinationCreateBase + specific required required: [type, topics, credentials] # No config properties: id: type: string description: Optional user-provided ID. A UUID will be generated if empty. example: "user-provided-id" type: type: string description: Type of the destination. Must be 'hookdeck'. enum: [hookdeck] # Specific type topics: $ref: "#/components/schemas/Topics" # Type-specific properties config: {} # Empty config credentials: $ref: "#/components/schemas/HookdeckCredentials" DestinationCreateAWSKinesis: type: object # Properties duplicated from DestinationCreateBase + specific required required: [type, topics, config, credentials] properties: id: type: string description: Optional user-provided ID. A UUID will be generated if empty. example: "user-provided-id" type: type: string description: Type of the destination. Must be 'aws_kinesis'. enum: [aws_kinesis] # Specific type topics: $ref: "#/components/schemas/Topics" # Type-specific properties config: $ref: "#/components/schemas/AWSKinesisConfig" credentials: $ref: "#/components/schemas/AWSKinesisCredentials" # Polymorphic Destination Creation Schema (for Request Bodies) DestinationCreate: oneOf: - $ref: "#/components/schemas/DestinationCreateWebhook" - $ref: "#/components/schemas/DestinationCreateAWSSQS" - $ref: "#/components/schemas/DestinationCreateRabbitMQ" - $ref: "#/components/schemas/DestinationCreateHookdeck" - $ref: "#/components/schemas/DestinationCreateAWSKinesis" discriminator: propertyName: type mapping: webhook: "#/components/schemas/DestinationCreateWebhook" aws_sqs: "#/components/schemas/DestinationCreateAWSSQS" rabbitmq: "#/components/schemas/DestinationCreateRabbitMQ" hookdeck: "#/components/schemas/DestinationCreateHookdeck" aws_kinesis: "#/components/schemas/DestinationCreateAWSKinesis" # Type-Specific Destination Update Schemas (for Request Bodies) WebhookCredentialsUpdate: type: object properties: secret: type: string description: New secret (only allowed for admin). previous_secret: type: string description: Previous secret for rotation (only allowed for admin). previous_secret_invalid_at: type: string format: date-time description: Invalidation time for previous secret (only allowed for admin). rotate_secret: type: boolean description: Set to true to rotate the secret. The current secret becomes the previous_secret, and a new secret is generated. `previous_secret_invalid_at` defaults to 24h if not provided. DestinationUpdateWebhook: type: object # Properties duplicated from DestinationUpdateBase properties: topics: $ref: "#/components/schemas/Topics" # Type-specific properties config: $ref: "#/components/schemas/WebhookConfig" # URL is required here, but PATCH means it's optional in the request credentials: $ref: "#/components/schemas/WebhookCredentialsUpdate" DestinationUpdateAWSSQS: type: object # Properties duplicated from DestinationUpdateBase properties: topics: $ref: "#/components/schemas/Topics" # Type-specific properties config: $ref: "#/components/schemas/AWSSQSConfig" # queue_url is required here, but PATCH means it's optional credentials: $ref: "#/components/schemas/AWSSQSCredentials" # key/secret required here, but PATCH means optional DestinationUpdateRabbitMQ: type: object # Properties duplicated from DestinationUpdateBase properties: topics: $ref: "#/components/schemas/Topics" # Type-specific properties config: $ref: "#/components/schemas/RabbitMQConfig" # server_url/exchange required here, but PATCH means optional credentials: $ref: "#/components/schemas/RabbitMQCredentials" # username/password required here, but PATCH means optional DestinationUpdateHookdeck: type: object # Properties duplicated from DestinationUpdateBase properties: topics: $ref: "#/components/schemas/Topics" # Type-specific properties config: {} # Empty config, cannot be updated credentials: $ref: "#/components/schemas/HookdeckCredentials" # token required here, but PATCH means optional DestinationUpdateAWSKinesis: type: object # Properties duplicated from DestinationUpdateBase properties: topics: $ref: "#/components/schemas/Topics" # Type-specific properties config: $ref: "#/components/schemas/AWSKinesisConfig" # stream_name/region required here, but PATCH means optional credentials: $ref: "#/components/schemas/AWSKinesisCredentials" # key/secret required here, but PATCH means optional # Polymorphic Destination Update Schema (for Request Bodies) DestinationUpdate: oneOf: - $ref: "#/components/schemas/DestinationUpdateWebhook" - $ref: "#/components/schemas/DestinationUpdateAWSSQS" - $ref: "#/components/schemas/DestinationUpdateRabbitMQ" - $ref: "#/components/schemas/DestinationUpdateHookdeck" - $ref: "#/components/schemas/DestinationUpdateAWSKinesis" # Event Schemas PublishRequest: type: object required: - topic - data properties: id: type: string description: Optional. A unique identifier for the event. If not provided, a UUID will be generated. example: "evt_custom_123" tenant_id: type: string description: The ID of the tenant to publish for. example: "" destination_id: type: string description: Optional. Route event to a specific destination. example: "" topic: type: string description: Topic name for the event. example: "topic.name" eligible_for_retry: type: boolean description: Should event delivery be retried on failure. metadata: type: object description: Any key-value string pairs for metadata. additionalProperties: type: string example: { "source": "crm" } data: type: object description: Any JSON payload for the event data. additionalProperties: true example: { "user_id": "userid", "status": "active" } Event: type: object properties: id: type: string example: "evt_123" destination_id: type: string example: "des_456" topic: type: string example: "user.created" time: type: string format: date-time description: Time the event was received/processed. example: "2024-01-01T00:00:00Z" successful_at: type: string format: date-time nullable: true description: Time the event was successfully delivered. example: "2024-01-01T00:00:00Z" metadata: type: object description: Key-value string pairs of metadata associated with the event. additionalProperties: type: string example: { "source": "crm" } data: type: object description: Freeform JSON data of the event. additionalProperties: true example: { "user_id": "userid", "status": "active" } DeliveryAttempt: type: object properties: delivered_at: type: string format: date-time example: "2024-01-01T00:00:00Z" status: type: string enum: [success, failed] example: "success" response_status_code: type: integer example: 200 response_body: type: string # Or potentially object if JSON example: '{"status":"ok"}' response_headers: type: object additionalProperties: type: string example: { "content-type": "application/json" } # Destination Type Schema (for Metadata endpoint) DestinationTypeSchema: type: object properties: type: type: string example: "webhook" label: type: string example: "Webhook" description: type: string example: "Send event via an HTTP POST request to a URL" icon: type: string description: SVG icon string. example: "" instructions: type: string description: Markdown instructions. example: "Some *markdown*" remote_setup_url: type: string format: url # Property is optional, not nullable description: >- Some destinations may have Oauth flow or other managed-setup flow that can be triggered with a link. If a `remote_setup_url` is set then the user should be prompted to follow the link to configure the destination. See the [building your own UI guide](https://outpost.hookdeck.com/guides/building-your-own-ui.mdx) for recommended UI patterns and wireframes for implementation in your own app. example: "https://dashboard.hookdeck.com/authorize?provider=acme" config_fields: type: array description: Config fields are non-secret values that can be stored and displayed to the user in plain text. items: $ref: "#/components/schemas/DestinationSchemaField" credential_fields: type: array description: Credential fields are secret values that will be AES encrypted and obfuscated to the user. Some credentials may not be obfuscated; the destination type dictates the obfuscation logic. items: $ref: "#/components/schemas/DestinationSchemaField" DestinationSchemaField: type: object required: [type, required] properties: type: type: string enum: [text, checkbox] example: "text" label: type: string example: "URL" description: type: string example: "The URL to send the event to" required: type: boolean example: true sensitive: type: boolean description: Indicates if the field contains sensitive information. example: false default: type: string description: Default value for the field. example: "default_value" minlength: type: integer description: Minimum length for a text input. example: 0 maxlength: type: integer description: Maximum length for a text input. example: 255 pattern: type: string description: Regex pattern for validation (compatible with HTML5 pattern attribute). example: "^[a-zA-Z0-9_]+$" # Security is applied per-operation based on AuthScope tags: - name: Health description: API Health Check - name: Tenants description: | The API segments resources per `tenant`. A tenant represents a user/team/organization in your product. The provided value determines the tenant's ID, which can be any string representation. If your system is not multi-tenant, create a single tenant with a hard-code tenant ID upon initialization. If your system has a single tenant but multiple environments, create a tenant per environment, like `live` and `test`. - name: Destinations description: | Destinations are the endpoints where events are sent. Each destination is associated with a tenant and can be configured to receive specific event topics. ```json { "id": "des_12345", // Control plane generated ID or user provided ID "type": "webhooks", // Type of the destination "topics": ["user.created", "user.updated"], // Topics of events this destination is eligible for "config": { // Destination type specific configuration. Schema of depends on type "url": "https://example.com/webhooks/user" }, "credentials": { // Destination type specific credentials. AES encrypted. Schema depends on type "secret": "some***********" }, "disabled_at": null, // null or ISO date if disabled "created_at": "2024-01-01T00:00:00Z" // Date the destination was created } ``` The `topics` array can contain either a list of topics or a wildcard `*` implying that all topics are supported. If you do not wish to implement topics for your application, you set all destination topics to `*`. By default all destination `credentials` are obfuscated and the values cannot be read. This does not apply to the `webhook` type destination secret and each destination can expose their own obfuscation logic. - name: Publish description: Operations for publishing events. - name: Schemas description: Operations for retrieving destination type schemas. - name: Topics description: Operations for retrieving available event topics. - name: Events description: Operations related to event history and deliveries. paths: /healthz: get: tags: [Health] summary: Health Check description: Simple health check endpoint. operationId: healthCheck security: [] responses: "200": description: Service is healthy. content: text/plain: schema: type: string example: OK # Tenants /{tenant_id}: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. put: tags: [Tenants] summary: Create or Update Tenant description: Idempotently creates or updates a tenant. Required before associating destinations. operationId: upsertTenant responses: "200": description: Tenant updated details. content: application/json: schema: $ref: "#/components/schemas/Tenant" examples: TenantExample: value: id: "tenant_123" destinations_count: 5 topics: ["user.created", "user.deleted"] created_at: "2024-01-01T00:00:00Z" "201": description: Tenant created details. content: application/json: schema: $ref: "#/components/schemas/Tenant" examples: TenantExample: value: id: "tenant_123" destinations_count: 5 topics: ["user.created", "user.deleted"] created_at: "2024-01-01T00:00:00Z" # Add error responses get: tags: [Tenants] summary: Get Tenant description: Retrieves details for a specific tenant. operationId: getTenant responses: "200": description: Tenant details. content: application/json: schema: $ref: "#/components/schemas/Tenant" examples: TenantExample: value: id: "tenant_123" destinations_count: 5 topics: ["user.created", "user.deleted"] created_at: "2024-01-01T00:00:00Z" "404": description: Tenant not found. # Add other error responses delete: tags: [Tenants] summary: Delete Tenant description: Deletes the tenant and all associated destinations. operationId: deleteTenant responses: "200": description: Success confirmation. content: application/json: schema: $ref: "#/components/schemas/SuccessResponse" examples: SuccessExample: value: success: true "404": description: Tenant not found. # Add other error responses /{tenant_id}/portal: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. get: tags: [Tenants] summary: Get Portal Redirect URL description: Returns a redirect URL containing a JWT to authenticate the user with the portal. operationId: getTenantPortalUrl parameters: - name: theme in: query required: false schema: type: string enum: [light, dark] description: Optional theme preference for the portal. responses: "200": description: Portal redirect URL. content: application/json: schema: $ref: "#/components/schemas/PortalRedirect" examples: PortalRedirectExample: value: redirect_url: "https://webhooks.acme.com/?token=JWT_TOKEN" "404": description: Tenant not found. # Add other error responses /{tenant_id}/token: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. get: tags: [Tenants] summary: Get Tenant JWT Token description: Returns a JWT token scoped to the tenant for safe browser API calls. operationId: getTenantToken responses: "200": description: Tenant JWT token. content: application/json: schema: $ref: "#/components/schemas/TenantToken" examples: TenantTokenExample: value: token: "SOME_JWT_TOKEN" "404": description: Tenant not found. # Add other error responses # Destinations /{tenant_id}/destinations: description: | Manage destinations for a specific tenant. Destinations determine where events are sent. The structure of `config` and `credentials` depends on the destination `type`. parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. get: tags: [Destinations] summary: List Destinations description: Return a list of the destinations for the tenant. The endpoint is not paged. operationId: listTenantDestinations parameters: - name: type in: query required: false schema: oneOf: - type: string enum: [webhook, aws_sqs, rabbitmq, hookdeck, aws_kinesis] - type: array items: type: string enum: [webhook, aws_sqs, rabbitmq, hookdeck, aws_kinesis] description: Filter destinations by type(s). - name: topics in: query required: false schema: oneOf: - type: string - type: array items: type: string description: Filter destinations by supported topic(s). responses: "200": description: A list of destinations. content: application/json: schema: type: array items: $ref: "#/components/schemas/Destination" examples: DestinationsListExample: value: - id: "des_webhook_123" type: "webhook" topics: ["user.created", "order.shipped"] disabled_at: null created_at: "2024-02-15T10:00:00Z" config: url: "https://my-service.com/webhook/handler" credentials: secret: "whsec_abc123def456" previous_secret: "whsec_prev789xyz012" previous_secret_invalid_at: "2024-02-16T10:00:00Z" - id: "des_sqs_456" type: "aws_sqs" topics: ["*"] disabled_at: "2024-03-01T12:00:00Z" created_at: "2024-02-20T11:30:00Z" config: queue_url: "https://sqs.us-west-2.amazonaws.com/123456789012/my-app-queue" endpoint: "https://sqs.us-west-2.amazonaws.com" credentials: key: "AKIAIOSFODNN7EXAMPLE" secret: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" "404": description: Tenant not found. # Add other error responses post: tags: [Destinations] summary: Create Destination description: Creates a new destination for the tenant. The request body structure depends on the `type`. operationId: createTenantDestination requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/DestinationCreate" responses: "201": description: Destination created successfully. content: application/json: schema: $ref: "#/components/schemas/Destination" examples: WebhookCreatedExample: # Example for one type, others similar value: id: "des_webhook_123" type: "webhook" topics: ["user.created", "order.shipped"] disabled_at: null created_at: "2024-02-15T10:00:00Z" config: url: "https://my-service.com/webhook/handler" credentials: secret: "whsec_abc123def456" # previous_secret and previous_secret_invalid_at are absent on creation "400": description: Invalid request body or configuration. "404": description: Tenant not found. # Add other error responses (e.g., max destinations reached) /{tenant_id}/destinations/{destination_id}: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. - name: destination_id in: path required: true schema: type: string description: The ID of the destination. get: tags: [Destinations] summary: Get Destination description: Retrieves details for a specific destination. operationId: getTenantDestination responses: "200": description: Destination details. content: application/json: schema: $ref: "#/components/schemas/Destination" examples: WebhookGetExample: # Example for one type, others similar value: id: "des_webhook_123" type: "webhook" topics: ["user.created", "order.shipped"] disabled_at: null created_at: "2024-02-15T10:00:00Z" config: url: "https://my-service.com/webhook/handler" credentials: secret: "whsec_abc123def456" previous_secret: "whsec_prev789xyz012" previous_secret_invalid_at: "2024-02-16T10:00:00Z" "404": description: Tenant or Destination not found. patch: tags: [Destinations] summary: Update Destination description: Updates the configuration of an existing destination. The request body structure depends on the destination's `type`. Type itself cannot be updated. May return an OAuth redirect URL for certain types. operationId: updateTenantDestination requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/DestinationUpdate" responses: "200": description: Destination updated successfully or OAuth redirect needed. content: application/json: schema: oneOf: - $ref: "#/components/schemas/Destination" examples: DestinationUpdatedExample: summary: Example of successful update returning destination details value: id: "des_webhook_123" type: "webhook" topics: ["user.created"] disabled_at: null created_at: "2024-02-15T10:00:00Z" config: url: "https://my-service.com/webhook/new-handler" # Updated URL credentials: secret: "whsec_abc123def456" previous_secret: "whsec_prev789xyz012" previous_secret_invalid_at: "2024-02-16T10:00:00Z" "400": description: Invalid request body or configuration. "404": description: Tenant or Destination not found. # Add other error responses delete: tags: [Destinations] summary: Delete Destination description: Deletes a specific destination. operationId: deleteTenantDestination responses: "200": description: Success confirmation. content: application/json: schema: $ref: "#/components/schemas/SuccessResponse" examples: SuccessExample: value: success: true "404": description: Tenant or Destination not found. # Add other error responses /{tenant_id}/destinations/{destination_id}/enable: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. - name: destination_id in: path required: true schema: type: string description: The ID of the destination. put: tags: [Destinations] summary: Enable Destination description: Enables a previously disabled destination. operationId: enableTenantDestination responses: "200": description: Destination enabled successfully. content: application/json: schema: $ref: "#/components/schemas/Destination" examples: WebhookEnabledExample: # Example for one type, others similar value: id: "des_webhook_123" type: "webhook" topics: ["user.created", "order.shipped"] disabled_at: null # Now enabled created_at: "2024-02-15T10:00:00Z" config: url: "https://my-service.com/webhook/handler" credentials: secret: "whsec_abc123def456" previous_secret: "whsec_prev789xyz012" previous_secret_invalid_at: "2024-02-16T10:00:00Z" "404": description: Tenant or Destination not found. # Add other error responses /{tenant_id}/destinations/{destination_id}/disable: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. - name: destination_id in: path required: true schema: type: string description: The ID of the destination. put: tags: [Destinations] summary: Disable Destination description: Disables a previously enabled destination. operationId: disableTenantDestination responses: "200": description: Destination disabled successfully. content: application/json: schema: $ref: "#/components/schemas/Destination" examples: WebhookDisabledExample: # Example for one type, others similar value: id: "des_webhook_123" type: "webhook" topics: ["user.created", "order.shipped"] disabled_at: "2024-04-11T21:00:00Z" # Now disabled created_at: "2024-02-15T10:00:00Z" config: url: "https://my-service.com/webhook/handler" credentials: secret: "whsec_abc123def456" previous_secret: "whsec_prev789xyz012" previous_secret_invalid_at: "2024-02-16T10:00:00Z" "404": description: Tenant or Destination not found. # Add other error responses # Publish (Admin Only) /publish: post: tags: [Publish] summary: Publish Event description: Publishes an event to the specified topic, potentially routed to a specific destination. Requires Admin API Key. operationId: publishEvent requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PublishRequest" responses: "202": description: Event accepted for publishing. Empty body. "400": description: Invalid request body. "401": description: Unauthorized (Admin API Key missing or invalid). "409": description: Conflict. An event with the provided `id` already exists. # Add other error responses # Schemas (Tenant Specific - Admin or JWT) /{tenant_id}/destination-types: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. get: tags: [Schemas] summary: List Destination Type Schemas (for Tenant) description: Returns a list of JSON-based input schemas for each available destination type. Requires Admin API Key or Tenant JWT. operationId: listTenantDestinationTypeSchemas responses: "200": description: A list of destination type schemas. content: application/json: schema: type: array items: $ref: "#/components/schemas/DestinationTypeSchema" examples: DestinationTypesExample: value: - type: "webhook" label: "Webhook" description: "Send event via an HTTP POST request to a URL" icon: "" instructions: "Enter the URL..." config_fields: [ { type: "text", label: "URL", description: "The URL to send the webhook to.", pattern: "^https?://.*", # Example pattern required: true, }, ] credential_fields: [ { type: "text", label: "Secret", description: "Optional signing secret.", required: false, sensitive: true, # Added sensitive }, ] - type: "aws_sqs" label: "AWS SQS" description: "Send event to an AWS SQS queue" icon: "" instructions: "Enter Queue URL..." config_fields: [ { type: "text", label: "Queue URL", description: "The URL of the SQS queue.", required: true, }, { type: "text", label: "Endpoint", description: "Optional custom AWS endpoint URL.", required: false, }, ] credential_fields: [ { type: "text", label: "Key", description: "AWS Access Key ID.", required: true, sensitive: true, }, { type: "text", label: "Secret", description: "AWS Secret Access Key.", required: true, sensitive: true, }, { type: "text", label: "Session", description: "Optional AWS Session Token.", required: false, sensitive: true, }, ] "404": description: Tenant not found. /{tenant_id}/destination-types/{type}: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. - name: type in: path required: true schema: type: string enum: [webhook, aws_sqs, rabbitmq, hookdeck, aws_kinesis] description: The type of the destination. get: tags: [Schemas] summary: Get Destination Type Schema (for Tenant) description: Returns the input schema for a specific destination type. Requires Admin API Key or Tenant JWT. operationId: getTenantDestinationTypeSchema responses: "200": description: The schema for the specified destination type. content: application/json: schema: $ref: "#/components/schemas/DestinationTypeSchema" examples: WebhookSchemaExample: value: type: "webhook" label: "Webhook" description: "Send event via an HTTP POST request to a URL" icon: "" instructions: "Enter the URL..." config_fields: [ { type: "text", label: "URL", description: "The URL to send the webhook to.", pattern: "^https?://.*", # Example pattern required: true, }, ] credential_fields: [ { type: "text", label: "Secret", description: "Optional signing secret.", required: false, sensitive: true, # Added sensitive }, ] "404": description: Tenant or Destination type not found. # Topics (Tenant Specific - Admin or JWT) /{tenant_id}/topics: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. get: tags: [Topics] summary: List Available Topics (for Tenant) description: Returns a list of available event topics configured in the Outpost instance. Requires Admin API Key or Tenant JWT. operationId: listTenantTopics responses: "200": description: A list of topic names. content: application/json: schema: type: array items: type: string examples: TopicsListExample: value: [ "user.created", "user.updated", "order.shipped", "inventory.updated", ] "404": description: Tenant not found. # Events (Tenant Specific - Admin or JWT) /{tenant_id}/events: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. get: tags: [Events] summary: List Events description: Retrieves a list of events for the tenant, supporting cursor navigation (details TBD) and filtering. operationId: listTenantEvents parameters: - name: destination_id in: query required: false schema: oneOf: - type: string - type: array items: type: string description: Filter events by destination ID(s). - name: status in: query required: false schema: type: string enum: [success, failed] description: Filter events by delivery status. # Add cursor parameters (e.g., 'after', 'limit') when defined responses: "200": description: A list of events. content: application/json: schema: type: array items: $ref: "#/components/schemas/Event" examples: EventsListExample: value: - id: "evt_123" destination_id: "des_456" topic: "user.created" time: "2024-01-01T00:00:00Z" successful_at: "2024-01-01T00:00:05Z" metadata: { "source": "crm" } data: { "user_id": "userid", "status": "active" } - id: "evt_789" destination_id: "des_456" topic: "order.shipped" time: "2024-01-02T10:00:00Z" successful_at: null metadata: { "source": "oms" } data: { "order_id": "orderid", "tracking": "1Z..." } "404": description: Tenant not found. # Add other error responses /{tenant_id}/events/{event_id}: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. - name: event_id in: path required: true schema: type: string description: The ID of the event. get: tags: [Events] summary: Get Event description: Retrieves details for a specific event. operationId: getTenantEvent responses: "200": description: Event details. content: application/json: schema: $ref: "#/components/schemas/Event" examples: EventExample: value: id: "evt_123" destination_id: "des_456" topic: "user.created" time: "2024-01-01T00:00:00Z" successful_at: "2024-01-01T00:00:05Z" metadata: { "source": "crm" } data: { "user_id": "userid", "status": "active" } "404": description: Tenant or Event not found. /{tenant_id}/events/{event_id}/deliveries: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. - name: event_id in: path required: true schema: type: string description: The ID of the event. get: tags: [Events] summary: List Event Delivery Attempts description: Retrieves a list of delivery attempts for a specific event, including response details. operationId: listTenantEventDeliveries responses: "200": description: A list of delivery attempts. content: application/json: schema: type: array items: $ref: "#/components/schemas/DeliveryAttempt" examples: DeliveriesListExample: value: - delivered_at: "2024-01-01T00:00:05Z" status: "success" response_status_code: 200 response_body: '{"status":"ok"}' response_headers: { "content-type": "application/json" } - delivered_at: "2024-01-01T00:00:01Z" status: "failed" response_status_code: 503 response_body: "Service Unavailable" response_headers: { "content-type": "text/plain" } "404": description: Tenant or Event not found. /{tenant_id}/destinations/{destination_id}/events: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. - name: destination_id in: path required: true schema: type: string description: The ID of the destination. get: tags: [Events] summary: List Events by Destination description: Retrieves events associated with a specific destination for the tenant. operationId: listTenantEventsByDestination parameters: - name: status in: query required: false schema: type: string enum: [success, failed] description: Filter events by delivery status. # Add cursor parameters responses: "200": description: A list of events for the destination. content: application/json: schema: type: array items: $ref: "#/components/schemas/Event" examples: EventsListExample: # Same as /{tenant_id}/events example value: - id: "evt_123" destination_id: "des_456" topic: "user.created" time: "2024-01-01T00:00:00Z" successful_at: "2024-01-01T00:00:05Z" metadata: { "source": "crm" } data: { "user_id": "userid", "status": "active" } - id: "evt_789" destination_id: "des_456" topic: "order.shipped" time: "2024-01-02T10:00:00Z" successful_at: null metadata: { "source": "oms" } data: { "order_id": "orderid", "tracking": "1Z..." } "404": description: Tenant or Destination not found. /{tenant_id}/destinations/{destination_id}/events/{event_id}: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. - name: destination_id in: path required: true schema: type: string description: The ID of the destination. - name: event_id in: path required: true schema: type: string description: The ID of the event. get: tags: [Events] summary: Get Event by Destination description: Retrieves a specific event associated with a specific destination for the tenant. operationId: getTenantEventByDestination responses: "200": description: Event details. content: application/json: schema: $ref: "#/components/schemas/Event" examples: EventExample: # Same as /{tenant_id}/events/{event_id} example value: id: "evt_123" destination_id: "des_456" topic: "user.created" time: "2024-01-01T00:00:00Z" successful_at: "2024-01-01T00:00:05Z" metadata: { "source": "crm" } data: { "user_id": "userid", "status": "active" } "404": description: Tenant, Destination or Event not found. /{tenant_id}/destinations/{destination_id}/events/{event_id}/retry: parameters: - name: tenant_id in: path required: true schema: type: string description: The ID of the tenant. Required when using AdminApiKey authentication. - name: destination_id in: path required: true schema: type: string description: The ID of the destination. - name: event_id in: path required: true schema: type: string description: The ID of the event to retry. post: tags: [Events] summary: Retry Event Delivery description: Triggers a retry for a failed event delivery. operationId: retryTenantEvent responses: "202": description: Retry accepted for processing. "404": description: Tenant, Destination or Event not found. "409": # Conflict might be appropriate if event is not retryable description: Event not eligible for retry. # Tenant Agnostic Routes (JWT Auth Only) - Mirroring tenant-specific routes where AllowTenantFromJWT=true # Note: Portal routes (/portal, /token) still require AdminApiKey even when tenant is inferred from JWT, # as per router.go logic (Mode=RouteModePortal, AuthScope=AuthScopeAdmin). # They are included here for completeness of paths derived from AllowTenantFromJWT=true, # but their security reflects the Admin requirement. /destination-types: get: tags: [Schemas] summary: List Destination Type Schemas (JWT Auth) description: Returns a list of JSON-based input schemas for each available destination type (infers tenant from JWT). operationId: listDestinationTypeSchemasJwt responses: "200": description: A list of destination type schemas. content: application/json: schema: type: array items: $ref: "#/components/schemas/DestinationTypeSchema" examples: DestinationTypesExample: # Same as /{tenant_id}/destination-types example value: - type: "webhook" label: "Webhook" description: "Send event via an HTTP POST request to a URL" icon: "" instructions: "Enter the URL..." config_fields: [ { type: "text", label: "URL", description: "The URL to send the webhook to.", pattern: "^https?://.*", # Example pattern required: true, }, ] credential_fields: [ { type: "text", label: "Secret", description: "Optional signing secret.", required: false, sensitive: true, # Added sensitive }, ] - type: "aws_sqs" label: "AWS SQS" description: "Send event to an AWS SQS queue" icon: "" instructions: "Enter Queue URL..." config_fields: [ { type: "text", label: "Queue URL", description: "The URL of the SQS queue.", required: true, }, { type: "text", label: "Endpoint", description: "Optional custom AWS endpoint URL.", required: false, }, ] credential_fields: [ { type: "text", label: "Key", description: "AWS Access Key ID.", required: true, sensitive: true, }, { type: "text", label: "Secret", description: "AWS Secret Access Key.", required: true, sensitive: true, }, { type: "text", label: "Session", description: "Optional AWS Session Token.", required: false, sensitive: true, }, ] "401": description: Unauthorized (Tenant JWT missing or invalid). /destination-types/{type}: parameters: - name: type in: path required: true schema: type: string enum: [webhook, aws_sqs, rabbitmq, hookdeck, aws_kinesis] description: The type of the destination. get: tags: [Schemas] summary: Get Destination Type Schema description: Returns the input schema for a specific destination type. operationId: getDestinationTypeSchema responses: "200": description: The schema for the specified destination type. content: application/json: schema: $ref: "#/components/schemas/DestinationTypeSchema" examples: WebhookSchemaExample: # Same as /{tenant_id}/destination-types/{type} example value: type: "webhook" label: "Webhook" description: "Send event via an HTTP POST request to a URL" icon: "" instructions: "Enter the URL..." # remote_setup_url is optional, omitted here config_fields: [ { type: "text", label: "URL", description: "The URL to send the webhook to.", pattern: "^https?://.*", # Example pattern required: true, }, ] credential_fields: [ { type: "text", label: "Secret", description: "Optional signing secret.", required: false, sensitive: true, # Added sensitive }, ] "401": description: Unauthorized (Tenant JWT missing or invalid). "404": description: Destination type not found. /topics: get: tags: [Topics] summary: List Available Topics) description: Returns a list of available event topics configured in the Outpost instance. operationId: listTopics responses: "200": description: A list of topic names. content: application/json: schema: type: array items: type: string examples: TopicsListExample: # Same as /{tenant_id}/topics example value: [ "user.created", "user.updated", "order.shipped", "inventory.updated", ] "401": description: Unauthorized (Tenant JWT missing or invalid).