Skip to content

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

Source: apps/brisket/src/app/api/.

PathMethodAuthPurposeSource
/api/healthGETPublicLiveness probe — returns 200 { status: "ok" }.app/api/health/route.ts
/api/trpc/[trpc]GET, POSTClerk session via tRPC ctxSingle tRPC entrypoint. Uses @trpc/server/adapters/fetch fetchRequestHandler.app/api/trpc/[trpc]/route.ts
/api/webhook/clerkPOSTSvix 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

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

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.

characterapps/brisket/src/server/api/routers/character.ts

Owns character CRUD, dataset uploads, and welcome-media triggers. Calls ctx.api (sirloin SirloinService).

ProcedureTypeInput (Zod)OutputUpstream
getAllCharactersqueryCharacter[]sirloin.listCharacters
getCharacterquery{ character_id }Character | nullsirloin.listCharacters (filtered)
fetchCharacter / fetchCharactersmutation{ character_id }?Character[]sirloin.listCharacters
createCharactermutationname, handles, Gender, CharacterModelType, pack id, is_nsfwCharactersirloin.createCharacter
getUploadRefImageUrl, getUploadImageUrls, getKitsuneUploadUrlsmutationimage metasigned upload URLssirloin.getUpload*
triggerRefImageUploadedmutationupload idsirloin
updateCharacter, deleteCharacter, updateCharacterReferenceDatasetmutationcharacter partialsCharactersirloin.updateCharacter / deleteCharacter
verifyDatasetImage, removeDatasetImagemutationimage idsirloin
generateKitsunePreviewImages, submitKitsuneCharacterForTrainingmutationidsirloin
submitWelcomeMediaReview, triggerWelcomeMediaRegeneration, triggerWelcomeExDevOnlymutationsirloin
scrapeCharacterInstagramHandlemutationhandlemetadatasirloin

kycapps/brisket/src/server/api/routers/kyc.ts

Owns account-level KYC start/reset actions. Calls ctx.api (sirloin SirloinService).

ProcedureTypeInput (Zod)OutputUpstream
startKYCVerificationmutation{ variant: "ri" | "vi" }KYC payloadsirloin.startKYCVerification
resetKYCVerificationmutationempty responsesirloin.resetKYCVerification

mediarouters/media.ts

Image generation and library operations.

ProcedureTypeNotes
createImage, createMultipleImagesmutationenqueue generation in sirloin
getAllMediaquerypaginated library fetch
toggleMediaFavoriteById, toggleMediaArchivedByIdmutationper-media flags
fetchGlobalPendingquerypending generations across user
reportMediaByIdmutationNSFW / abuse report
markMediaDownloadmutationanalytics + watermark
getLastMediaGenerationDatemutationrate-limit / banner data
getFailedMediaByIdsmutationretry/diagnostic

subscriptionrouters/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.

profilerouters/profile.ts

getUserProfile (query), updateUserProfile (mutation, { nsfwEnabled? }). Both call ctx.api.getUserProfile / updateUserProfile on sirloin.

packrouters/pack.ts

Starter packs and example browsing.

getFilteredExamples, getExampleById, getStarterPackList, getMediaTags — all call sirloin pack endpoints.

shoprouters/shop.ts

Virtual influencer shop.

listVIs, getVIdata, reserveCharacter, purchaseShopCharacterWithReservationToken — call sirloin shop endpoints.

intercomrouters/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.

faqrouters/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

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) and BillingService (subscription router). Transport: createGrpcTransport({ baseUrl: env.SIRLOIN_URL, defaultTimeoutMs: 120_000, peerMaxConcurrentStreams: 500 }). Transport refreshed every 30 minutes via setInterval to mitigate stale H2 connections. Headers built by server/api/grpc-headers.ts.
  • brain — no direct calls from brisket (verified — no brain imports or HTTP/gRPC clients under apps/brisket/src). Brain is reached transitively via sirloin.
  • Strapi (chuck) — REST GET /api/checkout-faq-section with bearer token; ISR-cached for 1 hour.
  • Intercom — REST via intercom-client SDK (contacts.search, conversations.create).
  • Clerk — inbound webhook only; outbound auth is handled by @clerk/nextjs middleware.

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}) plus recordTrpcRequest metrics; see operations/observability.