Brand Studio docs
Engineering manualAPI route source

/api/credits/webhook

Exact current route handler: hosted-app/app/api/credits/webhook/route.js

Methods: POST. Input signals: none detected. Literal response-status signals: none detected.

Source: hosted-app/app/api/credits/webhook/route.js. Imports: ../../../../lib/bounded-http.mjs, ../../../../lib/stripe-credit-checkout.mjs, ../../../../lib/supabase-rest.mjs, next/server. Exact source is shown for inspection; its presence does not prove authentication, validation or live behavior.

All API routes · API and execution contract

import { withinDeadline, readBoundedBytes } from "../../../../lib/bounded-http.mjs";
import { NextResponse } from "next/server";
import { supabaseConfigFromEnv } from "../../../../lib/supabase-rest.mjs";
import { fulfillCreditWebhook } from "../../../../lib/stripe-credit-checkout.mjs";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export async function POST(request) {
  // Preserve the exact signed bytes; never JSON.parse/re-serialize first.
  let payload;
  try {
    payload = await withinDeadline(async signal => (await readBoundedBytes(request, 1024 * 1024, signal)).toString("utf8"), 10000, request.signal);
  } catch (error) {
    return NextResponse.json({ status: "refused", reason: "invalid_webhook_body" }, { status: error.httpStatus === 413 ? 413 : 400 });
  }
  const result = await fulfillCreditWebhook({ payload,
    signature: request.headers.get("stripe-signature"), config: supabaseConfigFromEnv(process.env) });
  const { http, ...body } = result;
  return NextResponse.json(body, { status: http, headers: { "cache-control": "no-store" } });
}