Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions docs/apis/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ security:
- AdminApiKey: []
- TenantJwt: []
servers:
- url: https://api.outpost.hookdeck.com/2025-07-01
description: Outpost API (production)
- url: http://localhost:3333/api/v1
description: Local development server base path
components:
Expand Down Expand Up @@ -1763,10 +1765,6 @@ components:
additionalProperties:
type: string
example: { "source": "crm" }
status:
type: string
enum: [success, failed]
example: "success"
data:
type: object
description: Freeform JSON data of the event.
Expand Down Expand Up @@ -2375,12 +2373,6 @@ paths:
schema:
type: string
description: Filter events by tenant ID. If not provided, returns events from all tenants.
- name: destination_id
in: query
required: false
schema:
type: string
description: Filter events by destination ID.
- name: topic
in: query
required: false
Expand Down
61 changes: 61 additions & 0 deletions docs/pages/guides/upgrade-v0.13.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,67 @@ Key differences:
- New `status` field mirrors the HTTP status code
- Validation errors in `data` changed from a `{ field: tag }` object to an array of human-readable messages

## SDK Migration

The official SDKs (TypeScript, Go, Python) are generated from the OpenAPI spec. When you upgrade to SDK versions that target v0.13, the following breaking changes apply. This section shows the migration from the pre–v0.13 SDK API to the v0.13 API.

### List response shape

All list endpoints return `{ models, pagination }` instead of `{ data, next, prev }`.

**Before (v0.12-style SDK):**

```ts
const response = await outpost.events.listByDestination({ tenantId, destinationId });
const events = response.data ?? [];
const nextCursor = response.next;
```

**After (v0.13 SDK):**

```ts
const response = await outpost.events.list({ tenantId });
const events = response.models ?? [];
const nextCursor = response.pagination?.next;
```

Use `response.models` for the array of items and `response.pagination` for `next`, `prev`, `order_by`, `dir`, and `limit`.

### Events API

| Before (v0.12-style) | After (v0.13) |
| --- | --- |
| `sdk.events.listByDestination({ tenantId, destinationId })` | `sdk.events.list({ tenantId, destinationId })` — or list without `destinationId` for all tenant events |
| `sdk.events.getByDestination({ tenantId, destinationId, eventId })` | `sdk.events.get({ eventId })` |
| Tenant-scoped list/get by destination | Use `sdk.events.list({ tenantId })` and filter client-side, or use attempts API for destination-scoped data |

**Note:** `GET /events?destination_id=...` is documented but currently returns 500 in some environments; prefer listing without `destination_id` until that is fixed. See [GitHub issue #688](https://github.com/hookdeck/outpost/issues/688) for details.

### Attempts (formerly deliveries)

| Before (v0.12-style) | After (v0.13) |
| --- | --- |
| Delivery-focused endpoints / types | `sdk.attempts.list()`, `sdk.attempts.get()`, `sdk.attempts.retry()` |
| Destination-scoped deliveries | `sdk.destinations.listAttempts()`, `sdk.destinations.getAttempt()` |
| Retry via event/destination path | `sdk.attempts.retry({ eventId, destinationId })` |

### Schemas and topics

| Before (v0.12-style) | After (v0.13) |
| --- | --- |
| Tenant-scoped destination types / schemas | `sdk.schemas.listDestinationTypes()`, `sdk.schemas.get()` (unscoped) |
| Tenant-scoped topics | `sdk.topics.list()` (unscoped) |

### Summary checklist for SDK users

1. Replace any use of `response.data` with `response.models` and `response.next`/`response.prev` with `response.pagination?.next` / `response.pagination?.prev`.
2. Switch events access to `sdk.events.list()` and `sdk.events.get({ eventId })`; remove use of event-by-destination list/get if present.
3. Switch delivery/retry usage to `sdk.attempts.*` and `sdk.destinations.listAttempts()` / `getAttempt()`.
4. Use `sdk.attempts.retry({ eventId, destinationId })` for retries.
5. Use `sdk.schemas.listDestinationTypes()` and `sdk.topics.list()` without tenant scope.

TypeScript SDK v0.13.0 and later reflect these changes. Go and Python SDKs will align with the same API once regenerated from the v0.13 OpenAPI spec.

## Empty `custom_headers` Rejected

Webhook and standard webhook destinations no longer accept an empty `custom_headers` object. Previously, passing `"custom_headers": {}` was silently accepted. In v0.13, this returns a validation error.
Expand Down
10 changes: 10 additions & 0 deletions docs/zudoku.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,16 @@ const config: ZudokuConfig = {
label: "Schema Migration",
id: "guides/migration",
},
{
type: "doc",
label: "Upgrade to v0.12",
id: "guides/upgrade-v0.12",
},
{
type: "doc",
label: "Upgrade to v0.13",
id: "guides/upgrade-v0.13",
},
],
},
{
Expand Down
17 changes: 2 additions & 15 deletions examples/demos/dashboard-integration/INTEGRATION_DETAILS.md
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,9 @@ export async function getTenantOverview(
});
const recentEvents = eventsResponse.items.map(transformEvent);

// Calculate statistics
// Calculate statistics (events list is seek-paginated with no total count, so we only expose destination count)
const stats = {
totalDestinations: destinations.length,
totalEvents: eventsResponse.totalCount || 0,
};

return {
Expand Down Expand Up @@ -520,13 +519,12 @@ import { Badge } from "@/components/ui/Badge";
interface OverviewStatsProps {
stats: {
totalDestinations: number;
totalEvents: number;
};
}

export default function OverviewStats({ stats }: OverviewStatsProps) {
return (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">
Expand All @@ -541,16 +539,6 @@ export default function OverviewStats({ stats }: OverviewStatsProps) {
</CardContent>
</Card>

<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Events</CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{stats.totalEvents}</div>
<p className="text-xs text-muted-foreground">Events processed</p>
</CardContent>
</Card>

<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">System Status</CardTitle>
Expand Down Expand Up @@ -1175,7 +1163,6 @@ export interface DashboardOverview {
recentEvents: Event[];
stats: {
totalDestinations: number;
totalEvents: number;
};
}

Expand Down
65 changes: 38 additions & 27 deletions examples/demos/dashboard-integration/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion examples/demos/dashboard-integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"dependencies": {
"@auth/pg-adapter": "^1.10.0",
"@hookdeck/outpost-sdk": "^0.3.0",
"@hookdeck/outpost-sdk": "file:../../../sdks/outpost-typescript",
"@types/bcryptjs": "^2.4.6",
"@types/pg": "^8.15.5",
"bcryptjs": "^3.0.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export async function GET(request: NextRequest) {
}

try {
// Fetch topics using the Outpost SDK
const topics = await outpostClient.topics.list({ tenantId });
// Fetch topics using the Outpost SDK (list is instance-wide; no tenant filter in API)
const topics = await outpostClient.topics.list();

logger.info("Topics fetched successfully", {
tenantId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Suspense } from "react";
import LoginForm from "@/components/auth/LoginForm";

export default function LoginPage() {
return <LoginForm />;
return (
<Suspense fallback={<div className="min-h-screen flex items-center justify-center">Loading...</div>}>
<LoginForm />
</Suspense>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import Link from "next/link";
interface OverviewStatsProps {
stats: {
totalDestinations: number;
totalEvents: number;
};
}

export default function OverviewStats({ stats }: OverviewStatsProps) {
return (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">
Expand All @@ -26,16 +25,6 @@ export default function OverviewStats({ stats }: OverviewStatsProps) {
</CardContent>
</Card>

<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Events</CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{stats.totalEvents}</div>
<p className="text-xs text-gray-500 mt-1">Events processed</p>
</CardContent>
</Card>

<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Status</CardTitle>
Expand Down
Loading
Loading