# 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

| Change | Impact | Action Required |
| --- | --- | --- |
| [API route prefix](#api-route-prefix) | All tenant-scoped endpoints | Update API client paths |
| [Webhook signature defaults](#webhook-signature-defaults) | Signature verification | Update receivers or configure for backward compatibility |
| [List Tenants & Redis migrations](#list-tenants--redis-migrations) | New feature + data format | Run migrations |
| [SDK request body field names](#sdk-request-body-field-names-all-sdks) | All SDK methods | Update method calls to use `params` instead of operation-specific field names |
| [SDK response structure](#sdk-response-structure-all-sdks) | All SDK response access | Update response access from `response.result.data` to `response.data` |
| [SDK pagination field names](#sdk-pagination-field-names) | TypeScript & Go SDKs | Update pagination field access from `nextCursor`/`prevCursor` to `next`/`prev` |

## API Route Prefix

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

| Old Path | New Path |
| --- | --- |
| `PUT /api/v1/:tenant_id` | `PUT /api/v1/tenants/:tenant_id` |
| `GET /api/v1/:tenant_id` | `GET /api/v1/tenants/:tenant_id` |
| `DELETE /api/v1/:tenant_id` | `DELETE /api/v1/tenants/:tenant_id` |
| `GET /api/v1/:tenant_id/destinations` | `GET /api/v1/tenants/:tenant_id/destinations` |
| `POST /api/v1/:tenant_id/destinations` | `POST /api/v1/tenants/:tenant_id/destinations` |
| `GET /api/v1/:tenant_id/events` | `GET /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.

| Setting | Old Default (v0.11) | New Default (v0.12) |
| --- | --- | --- |
| `DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE` | `{{.Timestamp.Unix}}.{{.Body}}` | `{{.Body}}` |
| `DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE` | `t={{.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:

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

```

## 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`.

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

### Before

```typescript
// 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"],
  },
});

```

### After

```typescript
// 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"],
  },
});

```

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.

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

### Before

```typescript
// 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 || [];

```

### After

```typescript
// 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 || [];

```

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.

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

### Before (TypeScript & Go)

```typescript
// 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,
});

```

### After (TypeScript & Go)

```typescript
// 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,
});

```

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.nextCursor` → `response.next`, `response.prevCursor` → `response.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`/`prev` → `next_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.

:::note[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](/docs/outpost/api/tenants#list-tenants) for details.

### Migrations Included

* 002_timestamps: Converts timestamp fields to Unix format for timezone-agnostic sorting
* 003_entity: Adds entity field to tenant and destination records for RediSearch filtering

### Running Migrations

These migrations require a maintenance window and must be run manually before starting Outpost v0.12.

:::note
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](/docs/outpost/self-hosting/guides/migration#configuration) for details.
:::

```bash
# Preview changes
docker run --rm -e REDIS_HOST=... -e REDIS_PASSWORD=... hookdeck/outpost:v0.12.0 migrate plan

# Apply the next pending migration (one at a time)
docker run --rm -it -e REDIS_HOST=... -e REDIS_PASSWORD=... hookdeck/outpost:v0.12.0 migrate apply

# Apply all pending migrations in sequence
docker run --rm -it -e REDIS_HOST=... -e REDIS_PASSWORD=... hookdeck/outpost:v0.12.0 migrate apply --all

# Verify migrations
docker run --rm -e REDIS_HOST=... -e REDIS_PASSWORD=... hookdeck/outpost:v0.12.0 migrate verify

```

:::tip[Migration Tool Reference]
For detailed information on the migration workflow, safety features, and troubleshooting, see the [Schema Migration Guide](/docs/outpost/self-hosting/guides/migration).
:::

## 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`/`prevCursor` → `next`/`prev`)
  * [ ] Decide on webhook signature format (keep old or adopt new)
  * [ ] Back up Redis data
2. During upgrade:
  
  * [ ] Stop Outpost
  * [ ] Run migrations: `migrate apply --all`
  * [ ] Verify migrations completed: `migrate verify`
  * [ ] Set webhook signature environment variables if maintaining backward compatibility
3. After upgrading:
  
  * [ ] Start Outpost v0.12
  * [ ] Test webhook signature verification