Condensed reference for Protocol Guide tRPC API. For complete documentation, see API_DOCUMENTATION.md.
// Add Bearer token to requests
headers: {
Authorization: `Bearer ${supabaseAccessToken}`
}const result = await trpc.router.procedure.query(input);const result = await trpc.router.procedure.mutate(input);try {
const result = await trpc.query.submit.mutate({ ... });
} catch (error) {
if (error.data?.code === "TOO_MANY_REQUESTS") {
// Handle rate limit
}
}| Router | Procedures | Auth | Description |
|---|---|---|---|
| system | 2 | Public/Admin | Health checks, notifications |
| auth | 2 | Public | Login status, logout |
| counties | 2 | Public | County listings |
| user | 11 | Protected | Profile, usage, counties |
| search | 8 | Public | Semantic protocol search |
| query | 6 | Protected | Protocol queries with Claude |
| voice | 2 | Protected | Voice transcription |
| feedback | 2 | Protected | User feedback |
| contact | 1 | Public | Contact form |
| subscription | 4 | Protected | Stripe payments |
| admin | 6 | Admin | Admin operations |
| agencyAdmin | 11 | Agency Admin | B2B agency management |
| integration | 4 | Public/Admin | Partner tracking |
| referral | 9 | Protected/Public | Viral referral system |
const results = await trpc.search.semantic.query({
query: "cardiac arrest epi dose",
countyId: 1,
limit: 10
});const response = await trpc.query.submit.mutate({
countyId: 1,
queryText: "What's the epinephrine dose for cardiac arrest?"
});const user = await trpc.auth.me.query();const usage = await trpc.user.usage.query();
// { count: 5, limit: 10, tier: "free" }const { counties, grouped } = await trpc.counties.list.query();await trpc.user.acknowledgeDisclaimer.mutate();const { url } = await trpc.voice.uploadAudio.mutate({
audioBase64: base64Audio,
mimeType: "audio/webm"
});
const transcript = await trpc.voice.transcribe.mutate({
audioUrl: url
});await trpc.feedback.submit.mutate({
category: "suggestion",
subject: "Feature Request",
message: "Would love to see..."
});const { url } = await trpc.subscription.createCheckout.mutate({
plan: "monthly",
successUrl: "https://app.protocolguide.app/success",
cancelUrl: "https://app.protocolguide.app/pricing"
});
// Redirect to urlconst { code } = await trpc.referral.getMyReferralCode.query();| Type | Requires | Description |
|---|---|---|
| publicProcedure | None | Open to all |
| protectedProcedure | User auth | Logged in users |
| paidProcedure | Pro/Enterprise | Paid subscribers |
| rateLimitedProcedure | User + limits | Free tier query limits |
| adminProcedure | Admin role | Admin users only |
| agencyAdminProcedure | Agency admin | Agency administrators |
| Tier | Daily Queries | Counties | Features |
|---|---|---|---|
| Free | 10 | 1 | Basic search |
| Pro | Unlimited | 5 | History sync, priority support |
| Enterprise | Unlimited | Unlimited | Custom protocols, SSO |
| Code | Description | Action |
|---|---|---|
| UNAUTHORIZED | Not logged in | Redirect to login |
| FORBIDDEN | Insufficient permissions | Show upgrade prompt or error |
| NOT_FOUND | Resource not found | Show error message |
| BAD_REQUEST | Invalid input | Show validation error |
| TOO_MANY_REQUESTS | Rate limit hit | Show upgrade prompt |
| INTERNAL_SERVER_ERROR | Server error | Retry or contact support |
The search automatically normalizes EMS queries:
- Expands abbreviations (CP → chest pain, SOB → shortness of breath)
- Fixes common typos
- Detects query intent (medication dosing, contraindications, etc.)
Queries are routed to appropriate Claude models:
- Simple queries → Haiku (fast, cost-effective)
- Complex/medication queries → Sonnet (higher accuracy)
- Pro users → Always get enhanced accuracy
Search results are cached for 1 hour in Redis for faster responses.
Supported audio formats:
- WebM (recommended for web)
- MP3
- WAV
- M4A
Max file size: 10MB (base64 encoded)
- Upload PDF →
agencyAdmin.uploadProtocol - Check status →
agencyAdmin.getUploadStatus - Update status →
agencyAdmin.updateProtocolStatus(draft → review → approved) - Publish →
agencyAdmin.publishProtocol(makes live in search)
- draft → review, archived
- review → draft, approved, archived
- approved → published, draft
- published → archived
- archived → draft
- Bronze: 0-2 referrals
- Silver: 3-9 referrals
- Gold: 10-24 referrals
- Platinum: 25-49 referrals
- Ambassador: 50+ referrals
- Referrer: 7 days Pro per successful referral
- Referee: 14 days Pro trial (vs standard 7 days)
Supported partners:
- imagetrend
- esos
- zoll
- emscloud
HIPAA Compliance: Integration logging does NOT store PHI (patient age, impression, etc.)
Import types from the AppRouter:
import type { AppRouter } from "../server/routers";
import { inferRouterInputs, inferRouterOutputs } from "@trpc/server";
type RouterInput = inferRouterInputs<AppRouter>;
type RouterOutput = inferRouterOutputs<AppRouter>;
// Example: Get input type for query.submit
type QuerySubmitInput = RouterInput["query"]["submit"];
// Example: Get output type for search.semantic
type SearchSemanticOutput = RouterOutput["search"]["semantic"];# Start server
npm run dev
# tRPC endpoint
http://localhost:3000/trpcSet environment variable:
DEBUG=trpc:* npm run devtRPC automatically batches parallel queries:
const [user, usage, counties] = await Promise.all([
trpc.auth.me.query(),
trpc.user.usage.query(),
trpc.counties.list.query()
]);
// Sent as single HTTP request- Email: support@protocolguide.app
- Full docs: API_DOCUMENTATION.md