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 "signing_secret": "some***********" }, "disabled_at": null, // null or ISO date if disabled "created_at": "2024-01-01T00:00:00Z" // Date the destination was created }json
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.
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 returntopics
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 "signing_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 omited 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 "signing_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 "signing_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 "signing_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>", "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 of your choice", "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 of your choice", "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 API
GET
/:tenant_id/destination/:destination_id/events
Retrieve a list of events using a cursor navigation.
Supported parameters
destination_id
string | string[]
Return events for a specific destinationstatus
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", "succesful_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", "succesful_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/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
POST
/:tenant_id/destination/:destination_id/events/:event_id/retry
Submit an event for retry
Response
{ "success": true }json