Corsair
PluginsOura Ring

Oura Ring

Integrate Oura Ring health and sleep tracking data

Quick Start

Install the plugin:

pnpm install @corsair-dev/oura

Add the Oura plugin to your Corsair instance:

corsair.ts
import { createCorsair } from "corsair";
import { oura } from "@corsair-dev/oura";

export const corsair = createCorsair({
    plugins: [
        oura(),
    ],
});

Once configured, you can access Oura health data:

// Get sleep data for a date range
const sleep = await corsair.oura.api.summary.getSleep({
    start_date: "2024-01-01",
    end_date: "2024-01-07",
});

Authentication

Supported Auth Types

The Oura plugin supports:

  • api_key (default) - Use an Oura personal access 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 --oura api_key=your-access-token

For webhook signature verification:

pnpm corsair setup --oura webhook_signature=your-webhook-secret

Alternatively, provide credentials directly in the config:

corsair.ts
oura({
    key: process.env.OURA_ACCESS_TOKEN,
    webhookSecret: process.env.OURA_WEBHOOK_SECRET,
})

See Authentication for details on managing credentials.

Options

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

Hooks

oura({
    hooks: {
        summary: {
            getSleep: {
                before: async (ctx, input) => {
                    console.log("Fetching sleep data:", input.start_date);
                    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 user profile
const profile = await corsair.oura.api.profile.get({});

// Get activity data
const activity = await corsair.oura.api.summary.getActivity({
    start_date: "2024-01-01",
    end_date: "2024-01-07",
});

// Get readiness scores
const readiness = await corsair.oura.api.summary.getReadiness({
    start_date: "2024-01-01",
    end_date: "2024-01-07",
});

See API Endpoints for the complete reference.

Webhooks

Oura sends daily health summary events to your webhook endpoint:

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 sleepData = await corsair.oura.db.dailySleep.search({
    data: { score: { gte: 80 } },
});

See Database for the complete schema.

Multi-Tenancy

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

const sleep = await tenant.oura.api.summary.getSleep({
    start_date: "2024-01-01",
    end_date: "2024-01-07",
});

Examples

Example 1: Daily Health Report

inngest/functions.ts
export const dailyHealthReport = inngest.createFunction(
    { id: "oura-daily-report" },
    { cron: "0 8 * * *" },
    async () => {
        const today = new Date().toISOString().split("T")[0];
        const yesterday = new Date(Date.now() - 86400000).toISOString().split("T")[0];

        const [sleep, readiness, activity] = await Promise.all([
            corsair.oura.api.summary.getSleep({ start_date: yesterday, end_date: today }), 
            corsair.oura.api.summary.getReadiness({ start_date: yesterday, end_date: today }), 
            corsair.oura.api.summary.getActivity({ start_date: yesterday, end_date: today }), 
        ]);

        console.log("Sleep score:", sleep.data[0]?.score);
        console.log("Readiness score:", readiness.data[0]?.score);
        console.log("Activity score:", activity.data[0]?.score);
    }
);

Example 2: Alert on Low Readiness

corsair.ts
export const corsair = createCorsair({
    plugins: [
        oura({
            webhookHooks: {
                summary: {
                    dailyReadiness: {
                        after: async (ctx, result) => {
                            await inngest.send({
                                name: "oura/readiness-updated",
                                data: {
                                    tenantId: ctx.tenantId,
                                    score: result.data.score, 
                                    userId: result.data.user_id,
                                },
                            });
                        },
                    },
                },
            },
        }),
    ],
});
inngest/functions.ts
export const alertOnLowReadiness = inngest.createFunction(
    { id: "alert-low-readiness" },
    { event: "oura/readiness-updated" },
    async ({ event }) => {
        if (event.data.score < 50) {
            // Send notification that user should rest
            console.log(`Low readiness (${event.data.score}) for user ${event.data.userId}`);
        }
    }
);