Upgrade to v0.12

This guide covers breaking changes and migration steps when upgrading from v0.11 to v0.12.

Version Information

This guide covers upgrading Outpost platform from v0.11 to v0.12.

Important: Outpost platform versions (v0.12) are separate from SDK versions.

  • Outpost Platform: The server/API version (currently v0.12)
  • SDKs: Client library versions (TypeScript v0.6.0, Python v0.5.0, Go v0.5.1)

SDK versions may not always match platform versions, as SDKs can have their own release cycle.

Breaking Changes Overview

ChangeImpactAction Required
API route prefixAll tenant-scoped endpointsUpdate API client paths
Webhook signature defaultsSignature verificationUpdate receivers or configure for backward compatibility
List Tenants & Redis migrationsNew feature + data formatRun migrations
SDK request body field namesAll SDK methodsUpdate method calls to use params instead of operation-specific field names
SDK response structureAll SDK response accessUpdate response access from response.result.data to response.data
SDK pagination field namesTypeScript & Go SDKsUpdate pagination field access from nextCursor/prevCursor to next/prev

API Route Prefix

All tenant-scoped API endpoints now use a /tenants/ prefix.

Old PathNew Path
PUT /api/v1/:tenant_idPUT /api/v1/tenants/:tenant_id
GET /api/v1/:tenant_idGET /api/v1/tenants/:tenant_id
DELETE /api/v1/:tenant_idDELETE /api/v1/tenants/:tenant_id
GET /api/v1/:tenant_id/destinationsGET /api/v1/tenants/:tenant_id/destinations
POST /api/v1/:tenant_id/destinationsPOST /api/v1/tenants/:tenant_id/destinations
GET /api/v1/:tenant_id/eventsGET /api/v1/tenants/:tenant_id/events
......

The pattern applies to all endpoints that previously started with /:tenant_id.

Action: Update your API clients to use the new /tenants/ prefixed paths before upgrading.

Webhook Signature Defaults

The default webhook signature templates have changed to a simpler format without timestamps.

SettingOld Default (v0.11)New Default (v0.12)
DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE{{.Timestamp.Unix}}.{{.Body}}{{.Body}}
DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATEt={{.Timestamp.Unix}},v0={{.Signatures | join ","}}v0={{.Signatures | join ","}}

If your webhook receivers verify signatures using the old format, signature verification will fail after upgrading.

To maintain backward compatibility, set these environment variables:

DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE="{{.Timestamp.Unix}}.{{.Body}}" DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE="t={{.Timestamp.Unix}},v0={{.Signatures | join \",\"}}"
bash

SDK Request Body Field Names (All SDKs)

All SDKs (TypeScript v0.6.0, Python v0.5.0, Go v0.5.1) now use a consistent params field name for request bodies instead of operation-specific names like destinationCreate or destinationUpdate.

Examples

Examples shown in TypeScript, but changes apply to all SDKs (TypeScript, Python, Go).

Before

// Creating a destination await outpost.destinations.create({ tenantId: "acme-corp", destinationCreate: { type: "webhook", topics: ["order.created"], config: { url: "https://acme.com/webhooks" }, }, }); // Updating a destination await outpost.destinations.update({ tenantId: "acme-corp", destinationId: "des_123", destinationUpdate: { topics: ["order.updated"], }, });
typescript

After

// Creating a destination await outpost.destinations.create({ tenantId: "acme-corp", params: { type: "webhook", topics: ["order.created"], config: { url: "https://acme.com/webhooks" }, }, }); // Updating a destination await outpost.destinations.update({ tenantId: "acme-corp", destinationId: "des_123", params: { topics: ["order.updated"], }, });
typescript

Action: Update all SDK method calls that use destinationCreate, destinationUpdate, or similar operation-specific field names to use params instead.

SDK Response Structure (All SDKs)

All SDKs (TypeScript v0.6.0, Python v0.5.0, Go v0.5.1) response structure has changed. Paginated responses (like events lists) now return data directly on the response object instead of nested under a result property.

Examples

Examples shown in TypeScript, but changes apply to all SDKs (TypeScript, Python, Go).

Before

// Listing events by destination const response = await outpost.events.listByDestination({ tenantId: "acme-corp", destinationId: "des_123", }); const events = response?.result?.data || []; // Listing tenant events const response = await outpost.events.list({ tenantId: "acme-corp", }); const events = response?.result?.data || [];
typescript

After

// Listing events by destination const response = await outpost.events.listByDestination({ tenantId: "acme-corp", destinationId: "des_123", }); const events = response?.data || []; // Listing tenant events const response = await outpost.events.list({ tenantId: "acme-corp", }); const events = response?.data || [];
typescript

Action: Update all code that accesses paginated response data from response.result.data to response.data. This affects:

  • events.listByDestination() - returns ListTenantEventsByDestinationResponse with data directly
  • events.list() - returns ListTenantEventsResponse with data directly
  • Other paginated list endpoints

SDK Pagination Field Names

Previously, all SDKs (TypeScript, Go, and Python) used nextCursor/prevCursor (or next_cursor/prev_cursor in Python) for pagination fields due to a shared overlay that renamed these fields to avoid Python's built-in next() function conflict.

With this release, we've separated the pagination overlay to be Python-specific. TypeScript v0.6.0 and Go v0.5.1 now use next and prev for pagination fields (both query parameters and response properties), matching the OpenAPI specification. Python v0.5.0 continues using next_cursor and prev_cursor consistently to avoid conflicts with Python's built-in next() function.

Examples

Examples shown in TypeScript, but changes apply to TypeScript and Go SDKs. Python SDK uses next_cursor/prev_cursor instead.

Before (TypeScript & Go)

// Accessing pagination cursor from response const response = await outpost.events.list({ tenantId: "acme-corp", }); const nextCursor = response?.nextCursor; // or response?.prevCursor // Using pagination cursor in next request const nextPage = await outpost.events.list({ tenantId: "acme-corp", next: nextCursor, });
typescript

After (TypeScript & Go)

// Accessing pagination cursor from response const response = await outpost.events.list({ tenantId: "acme-corp", }); const nextCursor = response?.next; // or response?.prev // Using pagination cursor in next request const nextPage = await outpost.events.list({ tenantId: "acme-corp", next: nextCursor, });
typescript

Action: Update all code that accesses pagination fields:

  • TypeScript & Go: Change nextCursor/prevCursor to next/prev in response objects. Query parameters remain next/prev (no change).
  • Python: Update query parameters from next/prev to next_cursor/prev_cursor. Response fields already use next_cursor/prev_cursor (no change).

This affects:

  • Response properties:
    • TypeScript/Go: response.nextCursorresponse.next, response.prevCursorresponse.prev (reverting to OpenAPI spec)
    • Python: No change - continues using response.next_cursor/response.prev_cursor
  • Query parameters:
    • TypeScript/Go: No change - continue using next and prev
    • Python: next/prevnext_cursor/prev_cursor (previously used next/prev)

List Tenants & Redis Migrations

v0.12 introduces a new GET /api/v1/tenants endpoint for listing all tenants with cursor-based pagination. This feature requires Redis migrations to be run.

RediSearch Required

This endpoint requires Redis with the RediSearch module (e.g., redis/redis-stack-server). If RediSearch is not available, the endpoint returns 501 Not Implemented.

See the API Reference for details.

Migrations Included

  • 002_timestamps: Converts timestamp fields to Unix format for timezone-agnostic sorting
  • 003_entity: Creates RediSearch indexes for tenant listing

Running Migrations

Migrations run automatically at startup. For production environments, manual migration is recommended.

These commands require environment variables for Redis connection (REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, etc.). You can also use --config to pass a config file. See the Schema Migration Guide for details.

# Preview changes docker run --rm -e REDIS_HOST=... -e REDIS_PASSWORD=... hookdeck/outpost:v0.12.0 migrate plan # Apply migrations docker run --rm -it -e REDIS_HOST=... -e REDIS_PASSWORD=... hookdeck/outpost:v0.12.0 migrate apply # Verify migrations docker run --rm -e REDIS_HOST=... -e REDIS_PASSWORD=... hookdeck/outpost:v0.12.0 migrate verify
bash

For systems with high write throughput, re-run migrations after the initial upgrade:

docker run --rm -it -e REDIS_HOST=... -e REDIS_PASSWORD=... hookdeck/outpost:v0.12.0 migrate apply --rerun
bash

Migration Tool Reference

For detailed information on the migration workflow, safety features, and troubleshooting, see the Schema Migration Guide.

Upgrade Checklist

  1. Before upgrading:

    • Update API clients to use /tenants/ prefix paths
    • Update SDK calls (all languages) to use params instead of operation-specific field names
    • Update SDK response access (all languages) from response.result.data to response.data
    • Update pagination field names (TypeScript/Go: nextCursor/prevCursornext/prev)
    • Decide on webhook signature format (keep old or adopt new)
    • Back up Redis data
  2. During upgrade:

    • Set webhook signature environment variables if maintaining backward compatibility
    • Run migrations (automatic or manual)
  3. After upgrading:

    • Verify migrations completed: migrate verify
    • For high-volume systems: migrate apply --rerun
    • Test webhook signature verification