Skip to main content

Quick Start

Install the plugin:
pnpm install @corsair-dev/sentry
Add the Sentry plugin to your Corsair instance:
corsair.ts
import { createCorsair } from "corsair";
import { sentry } from "@corsair-dev/sentry";

export const corsair = createCorsair({
    plugins: [
        sentry(),
    ],
});
Once configured, you can manage Sentry issues and projects:
// List issues for a project
const issues = await corsair.sentry.api.issues.list({
    organizationSlug: "my-org",
    projectSlug: "my-project",
});

Authentication

Supported Auth Types

The Sentry plugin supports:
  • api_key (default) - Use a Sentry auth token

Default Auth Type

If no authType is specified, the plugin defaults to api_key.

Configuring API Key Authentication

Store credentials with the CLI:
pnpm corsair setup --sentry api_key=your-auth-token
For webhook signature verification:
pnpm corsair setup --sentry webhook_signature=your-webhook-secret
Alternatively, provide credentials directly in the config:
corsair.ts
sentry({
    key: process.env.SENTRY_AUTH_TOKEN,
    webhookSecret: process.env.SENTRY_WEBHOOK_SECRET,
})
See Authentication for details on managing credentials.

Options

OptionTypeDescription
authType'api_key'Authentication method (defaults to 'api_key')
keystringAuth token (optional, uses database if not provided)
webhookSecretstringWebhook secret for sentry-hook-signature verification
hooksobjectEndpoint hooks for custom logic
webhookHooksobjectWebhook hooks for event handling
errorHandlersobjectCustom error handlers
permissionsobjectPermission configuration for AI agent access

Hooks

sentry({
    hooks: {
        issues: {
            update: {
                before: async (ctx, input) => {
                    console.log("Updating issue:", input.issueId);
                    return { ctx, input };
                },
            },
        },
    },
})
See Hooks for complete documentation.

Error Handling

The plugin includes built-in error handlers for common scenarios. For complete documentation, see the Error Handlers reference.

Usage

Accessing the API

// Get a specific issue
const issue = await corsair.sentry.api.issues.get({
    organizationSlug: "my-org",
    issueId: "ISSUE123",
});

// Resolve an issue
await corsair.sentry.api.issues.update({
    organizationSlug: "my-org",
    issueId: "ISSUE123",
    status: "resolved",
});

// Create a release
await corsair.sentry.api.releases.create({
    organizationSlug: "my-org",
    version: "v1.2.3",
    projects: ["my-project"],
});

// List teams
const teams = await corsair.sentry.api.teams.list({
    organizationSlug: "my-org",
});
See API Endpoints for the complete reference.

Webhooks

Sentry sends issue and alert events (identified by sentry-hook-signature + sentry-hook-resource headers):
app/api/webhook/route.ts
import { processWebhook } from "corsair";
import { corsair } from "@/server/corsair";

export async function POST(request: Request) {
    const headers = Object.fromEntries(request.headers);
    const body = await request.json();

    const result = await processWebhook(corsair, headers, body);
    return result.response;
}
See Webhooks for all available events.

Database Access

const issues = await corsair.sentry.db.issues.search({
    data: { status: "unresolved" },
});
See Database for the complete schema.

Multi-Tenancy

const tenant = corsair.withTenant("org-123");

const issues = await tenant.sentry.api.issues.list({
    organizationSlug: "my-org",
    projectSlug: "my-project",
    query: "is:unresolved",
});

Examples

Example 1: Auto-create Linear Issue on Sentry Error

corsair.ts
import { inngest } from "./inngest";

export const corsair = createCorsair({
    plugins: [
        sentry({
            webhookHooks: {
                issues: {
                    created: {
                        after: async (ctx, result) => {
                            await inngest.send({ 
                                name: "sentry/issue-created", 
                                data: { 
                                    tenantId: ctx.tenantId, 
                                    issueId: result.data.data?.issue?.id, 
                                    title: result.data.data?.issue?.title, 
                                    url: result.data.data?.issue?.web_url, 
                                }, 
                            }); 
                        },
                    },
                },
            },
        }),
        linear(),
    ],
});
inngest/functions.ts
export const createLinearIssue = inngest.createFunction(
    { id: "create-linear-from-sentry" },
    { event: "sentry/issue-created" },
    async ({ event }) => {
        const tenant = corsair.withTenant(event.data.tenantId);

        await tenant.linear.api.issues.create({
            title: `[Sentry] ${event.data.title}`,
            teamId: process.env.LINEAR_TEAM_ID!,
            description: `Sentry issue: ${event.data.url}`, 
            labelIds: ["bug-label-id"],
        });
    }
);

Example 2: Notify on Metric Alert

corsair.ts
export const corsair = createCorsair({
    plugins: [
        sentry({
            webhookHooks: {
                alerts: {
                    metricAlert: {
                        after: async (ctx, result) => {
                            await inngest.send({
                                name: "sentry/metric-alert",
                                data: {
                                    tenantId: ctx.tenantId,
                                    alertTitle: result.data.data?.metric_alert?.title, 
                                    status: result.data.data?.metric_alert?.status,
                                },
                            });
                        },
                    },
                },
            },
        }),
        slack(),
    ],
});
inngest/functions.ts
export const notifyMetricAlert = inngest.createFunction(
    { id: "notify-sentry-metric-alert" },
    { event: "sentry/metric-alert" },
    async ({ event }) => {
        const tenant = corsair.withTenant(event.data.tenantId);

        if (event.data.status === "critical") {
            await tenant.slack.api.messages.post({
                channel: "C_ALERTS",
                text: `🚨 Sentry metric alert: ${event.data.alertTitle}`, 
            });
        }
    }
);