Brisket API Surface
Brisket is the Next.js 16 user-facing frontend. Its public surface is small — most data flow happens through tRPC procedures over POST /api/trpc/[trpc] rather than bespoke REST endpoints. Upstream traffic terminates at sirloin (gRPC via ConnectRPC) plus a handful of third parties (Strapi, Intercom, Clerk).
Route Handlers
Section titled “Route Handlers”Source: apps/brisket/src/app/api/.
| Path | Method | Auth | Purpose | Source |
|---|---|---|---|---|
/api/health |
GET |
Public | Liveness probe — returns 200 { status: "ok" }. |
app/api/health/route.ts |
/api/trpc/[trpc] |
GET, POST |
Clerk session via tRPC ctx | Single tRPC entrypoint. Uses @trpc/server/adapters/fetch fetchRequestHandler. |
app/api/trpc/[trpc]/route.ts |
/api/webhook/clerk |
POST |
Svix HMAC (CLERK_WEBHOOK_SECRET) |
Receives Clerk lifecycle webhooks (user.created, session.created) and emits PostHog events. |
app/api/webhook/clerk/route.ts |
/api/health and /api/webhook/clerk are listed as public routes in apps/brisket/src/middleware.ts (isPublicRoute). All other routes — including the tRPC entrypoint — are gated by Clerk via auth.protect() in the same middleware.
Server Actions
Section titled “Server Actions”Grep for "use server" returns no matches under apps/brisket/src (verified). All mutations go through tRPC. Use grep -rn '"use server"' apps/brisket/src to refresh; add server actions here if introduced.
tRPC Routers
Section titled “tRPC Routers”Root composition: apps/brisket/src/server/api/root.ts. All procedures use protectedProcedure (Clerk-authenticated) unless explicitly marked otherwise. Inputs are validated with Zod; outputs from sirloin are returned as Connect/protobuf message shapes (pkg/sirloin/v5/*_pb). Error formatter (server/api/trpc.ts) attaches zodError to data for client-side field hints.
character — apps/brisket/src/server/api/routers/character.ts
Section titled “character — apps/brisket/src/server/api/routers/character.ts”Owns character CRUD, dataset uploads, and welcome-media triggers. Calls ctx.api (sirloin SirloinService).
| Procedure | Type | Input (Zod) | Output | Upstream |
|---|---|---|---|---|
getAllCharacters |
query | – | Character[] |
sirloin.listCharacters |
getCharacter |
query | { character_id } |
Character | null |
sirloin.listCharacters (filtered) |
fetchCharacter / fetchCharacters |
mutation | { character_id }? |
Character[] |
sirloin.listCharacters |
createCharacter |
mutation | name, handles, Gender, CharacterModelType, pack id, is_nsfw |
Character |
sirloin.createCharacter |
getUploadRefImageUrl, getUploadImageUrls, getKitsuneUploadUrls |
mutation | image meta | signed upload URLs | sirloin.getUpload* |
triggerRefImageUploaded |
mutation | upload id | – | sirloin |
updateCharacter, deleteCharacter, updateCharacterReferenceDataset |
mutation | character partials | Character |
sirloin.updateCharacter / deleteCharacter |
verifyDatasetImage, removeDatasetImage |
mutation | image id | – | sirloin |
generateKitsunePreviewImages, submitKitsuneCharacterForTraining |
mutation | id | – | sirloin |
submitWelcomeMediaReview, triggerWelcomeMediaRegeneration, triggerWelcomeExDevOnly |
mutation | – | – | sirloin |
scrapeCharacterInstagramHandle |
mutation | handle | metadata | sirloin |
kyc — apps/brisket/src/server/api/routers/kyc.ts
Section titled “kyc — apps/brisket/src/server/api/routers/kyc.ts”Owns account-level KYC start/reset actions. Calls ctx.api (sirloin SirloinService).
| Procedure | Type | Input (Zod) | Output | Upstream |
|---|---|---|---|---|
startKYCVerification |
mutation | { variant: "ri" | "vi" } |
KYC payload | sirloin.startKYCVerification |
resetKYCVerification |
mutation | – | empty response | sirloin.resetKYCVerification |
media — routers/media.ts
Section titled “media — routers/media.ts”Image generation and library operations.
| Procedure | Type | Notes |
|---|---|---|
createImage |
mutation | enqueue generation in sirloin |
getAllMedia |
query | paginated library fetch |
toggleMediaFavoriteById, toggleMediaArchivedById |
mutation | per-media flags |
fetchGlobalPending |
query | pending generations across user |
reportMediaById |
mutation | NSFW / abuse report |
markMediaDownload |
mutation | analytics + watermark |
getLastMediaGenerationDate |
mutation | rate-limit / banner data |
getFailedMediaByIds |
mutation | retry/diagnostic |
subscription — routers/subscription.ts
Section titled “subscription — routers/subscription.ts”Billing surface. Uses ctx.billingApi (sirloin BillingService) and validates Cloudflare Turnstile tokens server-side. See brisket-billing-flow.md for the end-to-end sequence.
Procedures: getCurrentUsage, claimOffer, setReferralCode, createPrimerCheckout, submitPaidInvoice, setTokenBillingAddress, createVaultingSession, listProducts, getCountryCode, updateNextBillingDate, getPrimerPaymentMethods, deletePrimerPaymentMethod, setPrimaryPrimerPaymentMethod, validateCouponCode, changePrimerSubscriptionBackToActive, getPrimerSubscriptions, getPrimerTransactions, getPrimerPaymentData, cancelPrimerSubscription, retryDunningPayment, cancelPrimerSubscriptionDowngrade.
profile — routers/profile.ts
Section titled “profile — routers/profile.ts”getUserProfile (query), updateUserProfile (mutation, { nsfwEnabled? }). Both call ctx.api.getUserProfile / updateUserProfile on sirloin.
pack — routers/pack.ts
Section titled “pack — routers/pack.ts”Starter packs and example browsing.
getFilteredExamples, getExampleById, getStarterPackList, getMediaTags — all call sirloin pack endpoints.
shop — routers/shop.ts
Section titled “shop — routers/shop.ts”Virtual influencer shop.
listVIs, getVIdata, reserveCharacter, purchaseShopCharacterWithReservationToken — call sirloin shop endpoints.
intercom — routers/intercom.ts
Section titled “intercom — routers/intercom.ts”createSupportConversation (mutation): looks up the contact in Intercom by primary email and posts a templated support message. Soft-fails (returns undefined) if INTERCOM_API_TOKEN is unset or contact missing.
faq — routers/faq.ts
Section titled “faq — routers/faq.ts”getCheckoutFaqSection (query): fetches ${STRAPI_URL}/api/checkout-faq-section?populate=* with Authorization: Bearer ${STRAPI_TOKEN}. Cached via Next.js next: { revalidate: 3600 }.
Upstream Calls
Section titled “Upstream Calls”flowchart LR Client[Browser] -->|POST /api/trpc/*| Brisket Brisket -->|gRPC ConnectRPC| Sirloin[(sirloin)] Brisket -->|HTTPS| Strapi[(chuck/Strapi)] Brisket -->|HTTPS| Intercom Clerk -->|svix webhook| Brisket
- sirloin — primary upstream. Two clients constructed in
server/api/sirloin-api.ts:SirloinService(general — characters, media, profile, packs, shop) andBillingService(subscription router). Transport:createGrpcTransport({ baseUrl: env.SIRLOIN_URL, defaultTimeoutMs: 120_000, peerMaxConcurrentStreams: 500 }). Transport refreshed every 30 minutes viasetIntervalto mitigate stale H2 connections. Headers built byserver/api/grpc-headers.ts. - brain — no direct calls from brisket (verified — no
brainimports or HTTP/gRPC clients underapps/brisket/src). Brain is reached transitively via sirloin. - Strapi (chuck) — REST
GET /api/checkout-faq-sectionwith bearer token; ISR-cached for 1 hour. - Intercom — REST via
intercom-clientSDK (contacts.search,conversations.create). - Clerk — inbound webhook only; outbound auth is handled by
@clerk/nextjsmiddleware.
Anchor Docs
Section titled “Anchor Docs”- Auth model: see
standards/auth-model. - Security model and Turnstile boundary:
standards/security-model. - Observability — tRPC tracing middleware emits OTel spans (
trpc.${type}.${path}) plusrecordTrpcRequestmetrics; seeoperations/observability.