Outpost API Reference

The API is a REST-based JSON API that can be publicly exposed or only available on your internal network / VPC, depending on your network topology.

Authentication

Admin API Key

The API uses bearer token authentication with a token of your choice configured through the API_KEY environment variable.

JWT Token

The API can also be authenticated using a per tenant token that’s valid for 24 hours. When using the a JWT token the /:tenant_id of each API endpoints is inferred to be the authenticated token and is not necessary.

Tenants

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.

Tenant Object

{ "id": "123", //User-defined system ID "destinations_count": 5, // Integer "topics": ["user.created", "user.deleted"], // List of subscribed topics across all destinations "created_at": "2024-01-01T00:00:00Z" // ISO Date }
json

PUT /:tenant_id

Idempotently creates the tenant. A tenant is required to associate a destination.

Request

Empty body

Response

{ "id": "123", "destinations_count": 5, "topics": ["user.created", "user.deleted"], "created_at": "2024-01-01T00:00:00Z" }
json

GET /:tenant_id

Get a tenant.

Response

{ "id": "123", "destinations_count": 5, "topics": ["user.created", "user.deleted"], "created_at": "2024-01-01T00:00:00Z" }
json

GET /:tenant_id/portal

Return a redirect URL for a user portal URL. The redirect URL contains a JWT that authenticates the user with the portal.

Request

Supported parameters:

  • ?theme=(light|dark) Optional query param to force a specific theme to display the portal in to match the current theme of your own dashboard

Response

{ "redirect_url": "https://webhooks.acme.com?token=JWT_TOKEN" // Redirect URL with authentication token }
json

GET /:tenant_id/token

Return a JTW token to authenticate the user with the API scoped to their specific tenant in order to call the API from the browser safely.

Response

{ "token": "SOME_JWT_TOKEN" }
json

DELETE /:tenant_id

Delete the tenant and all associated destinations

Request

Empty body

Response

{ "success": true }
json

Destinations

Destination Object

{ "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***********" }, "delivery_metadata": { // Optional. Static key-value pairs automatically merged into event metadata on every delivery "x-api-key": "sk_live_abc123", "x-tenant-id": "tenant_456" }, "metadata": { // Optional. Arbitrary contextual information stored with the destination "name": "Production Webhook Server", "description": "Main webhook endpoint for order processing" }, "disabled_at": null, // null or ISO date if disabled "created_at": "2024-01-01T00:00:00Z" // Date the destination was created }
json

Field Details

  • topics: 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, set all destination topics to *.

  • credentials (optional): By default all destination credentials are obfuscated and the values cannot be read. This does not apply to the webhook type destination secret—each destination type can expose their own obfuscation logic.

  • delivery_metadata (optional): Static key-value pairs automatically merged into event metadata on every delivery. Values are encrypted like credentials. Useful for destination-specific metadata like API keys, authentication tokens, tenant identifiers, or any custom headers/attributes required by the receiving service. For webhook destinations, these are translated to HTTP headers. The merge priority is: system metadata (event-id, topic, timestamp) < delivery_metadata < event metadata.

  • metadata (optional): Arbitrary contextual information stored with the destination for organizational purposes (e.g., name, description, notes). Not encrypted and not included in event deliveries. Useful for documenting what a destination is used for or adding labels for filtering.

GET /:tenant_id/destinations

Return a list of the destinations. The endpoint is not paged, and the maximum number is equivalent to the maximum configured number of destinations per tenant through the MAX_DESTINATIONS_PER_TENANT env variable.

Request

Supported Parameters:

  • type string | string[] The type of destinations to return
  • topics string | string[] Return destinations for a specific event type

Response

[ { "id": "dest_123456", // Control plane generated ID or user provided ID "type": "webhooks", // Type of the destination "topics": ["user.created", "user.updated"], // Type 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": "something-super-secret" }, "created_at": "2024-01-01T00:00:00Z" // Date the destination was created } ]
json

POST /:tenant_id/destinations

Create a new destination type with the provided configuration.

Request

{ "id": "123", // Optional, UUID will be generated if empty "type": "webhooks", // String of valid destination type "topics": "*", // '*' or String[] of enabled topics, "*" for all "config": { // Config object for the given type "url": "https://example.com/webhooks" }, "credentials": null // Credentials for the given type. It can be empty or null. }
json

Response

{ "id": "des_12345", // ID of the destination "type": "webhooks", // Type of the destination "topics": ["*"], // Topics of events this destination is eligible for "config": { // Destination type specific configuration. Schema of depends on type "url": "https://example.com/webhooks" }, "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 }
json

Webhook secret & rotation

Webhook secrets and rotations are a special case for the webhook destination type. The destination type credentials.secret is only a valid input when using the Admin API and can be omited when a secret is generated automatically.

Additionally, credentials.previous_secret can be used to set a rotated secret during a migration. credentials.rotate_secret can be used to automatically rotate the existing secret which results in a new credentials.secret and credentials.previous_secret value.

previous_secret are valid and used to “double” sign the request for 24 hours.

PATCH /:tenant_id/destinations/:destination_id

Update the destination configuration.

Request

{ "type": "webhooks", // Optional. String of valid destination type "topics": "*", // Optional. String[] of enabled topics, "*" for all "config": { // Optional. Config object for the given type "url": "https://example.com/webhooks" }, "credentials": null // Optional. Credentials for the given type. It can be empty or null. }
json

Response

{ "id": "des_12345", // Control plane generated ID "type": "webhooks", // Type of the destination "topics": "*", // Topics of events this destination is eligible for "config": { // Destination type specific configuration. Schema of depends on type "url": "https://example.com/webhooks" }, "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 }
json

If the destination uses OAuth:

{ "redirect_url": "https://dashboard.hookdeck.com/authorize?token=12313123" }
json

PUT /:tenant_id/destinations/:destination_id/enable

Enable a previously disabled destination.

Request

Empty body

Response

{ "id": "des_12345", // Control plane generated ID "type": "webhooks", // Type of the destination "topics": "*", // Topics of events this destination is eligible for "config": { // Destination type specific configuration. Schema of depends on type "url": "https://example.com/webhooks" }, "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 }
json

PUT /:tenant_id/destinations/:destination_id/disable

Disable a previously enabled destination.

Request

Empty body

Response

{ "id": "des_12345", // Control plane generated ID "type": "webhooks", // Type of the destination "topics": "*", // Topics of events this destination is eligible for "config": { // Destination type specific configuration. Schema of depends on type "url": "https://example.com/webhooks" }, "credentials": { // Destination type specific credentials. AES encrypted. Schema depends on type "secret": "some***********" }, "disabled_at": "2024-01-01T00:00:00Z", // null or ISO date if disabled "created_at": "2024-01-01T00:00:00Z" // Date the destination was created }
json

DELETE /:tenant_id/destinations/:destination_id

Delete the destination.

Request

Empty body

Response

{ "success": true }
json

Publish

Publish events on one or more topics.

POST /api/v1/publish

Publish an event.

Request

{ "tenant_id": "<TENANT_ID>", "destination_id": "<DESTINATION_ID>", // Optional. Provide a way of routing events to a specific destination "topic": "topic.name", // Topic defined in TOPICS environment variable "eligible_for_retry": true | false, // Should event delivery be retried "metadata": Payload, // can by any JSON payload, "data": Payload // can by any JSON payload }
json

Response

Empty body

Example

curl --location 'localhost:3333/api/v1/publish' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <API_KEY>' \ --data '{ "tenant_id": "<TENANT_ID>", "topic": "user.created", "eligible_for_retry": true, "metadata": { "meta": "data" }, "data": { "user_id": "userid" } }'
sh

Schemas

GET /destination-types

Runs a list of JSON-based input schemas for each destination type.

Request

No parameters.

Response

[ { "type": "webhook", "label": "Webhook", "description": "Send event via an HTTP POST request to a URL", "icon": "<svg />", "instructions": "Some *markdown*", "config_fields": [ { "type": "text", "label": "URL", "description": "The URL to send the event to", "validation": "/((([A-Za-z]{3,9}:(?://)?)(?:[-;:&=+$,w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:www.|[-;:&=+$,w]+@)[A-Za-z0-9.-]+)((?:/[+~%/.w-_]*)???(?:[-+=&;%@.w_]*)#?(?:[w]*))?)/", "required": true } ], "credential_fields": [] }, { "type": "hookdeck", "label": "Hookdeck Event Gateway", "description": "Send event to Hookdeck Event Gateway", "icon": "<svg />", "instructions": "Some *markdown*", "remote_setup_url": "https://dashboard.hookdeck.com/authorize?provider=acme", "config_fields": [], "credential_fields": [ { "type": "text", "label": "Publishing Key", "description": "Your Hookdeck source publishing key", "required": true } ] } ]
json

GET /destination-types/:type

Runs the input schemas for the specified destination type.

Response

{ "type": "webhook", "label": "Webhook", "description": "Send event via an HTTP POST request to a URL", "icon": "<svg />", "instructions": "Some *markdown*", "config_fields": [ { "type": "text", "label": "URL", "description": "The URL to send the event to", "validation": "/((([A-Za-z]{3,9}:(?://)?)(?:[-;:&=+$,w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:www.|[-;:&=+$,w]+@)[A-Za-z0-9.-]+)((?:/[+~%/.w-_]*)???(?:[-+=&;%@.w_]*)#?(?:[w]*))?)/", "required": true } ], "credential_fields": [] }
json

Events

GET /:tenant_id/events

Retrieve a list of events using a cursor navigation.

Supported parameters

  • destination_id string | string[] Return events for a specific destination
  • status success | failed Return events with a specific failed or success status

Response

[ { "id": "123", "destination_id": "456", "topic": "something.created", "time": "2024-01-01T00:00:00Z", "successful_at": "2024-01-01T00:00:00Z", "metadata": { "key": "value" // String, number or boolean }, "data": { // Freeform JSON data "hello": "world" } } ]
json

GET /:tenant_id/events/:event_id/deliveries

Retrieve a list of the delivery attempts with the associated responses.

Response

[ { "delivered_at": "2024-01-01T00:00:00Z", "status": "success", "code": "200", // "OK", "ERR" or a valid HTTP status code "response_data": { "hello": "world" } } ]
json

GET /:tenant_id/destination/:destination_id/events

Retrieve a list of events using a cursor navigation.

Supported parameters

  • status success | failed Return events with a specific failed or success status

Response

[{ "id": "123", "destination_id": "456", "topic": "something.created", "time": "2024-01-01T00:00:00Z", "successful_at": "2024-01-01T00:00:00Z" "metadata": { "key": "value" // String, number or boolean }, "data": { // Freeform JSON data "hello": "world" } }]
json

GET /:tenant_id/destination/:destination_id/events/:event_id

Retrieve a specific event and its associated data.

Response

[{ "id": "123", "destination_id": "456", "topic": "something.created", "time": "2024-01-01T00:00:00Z", "successful_at": "2024-01-01T00:00:00Z" "metadata": { "key": "value" // String, number or boolean }, "data": { // Freeform JSON data "hello": "world" } }]
json

POST /:tenant_id/destination/:destination_id/events/:event_id/retry

Submit an event for retry

Response

{ "success": true }
json