Skip to main content

Funnel Config API

The funnelConfig router manages per-tenant funnel stage definitions. Tenants can apply a built-in template, customize individual stages, and map them to Salesforce opportunity stages for sync.

Router namespace: funnelConfig

Source: src/server/trpc/routers/funnel-config.ts

Procedures

ProcedureTypeAccessDescription
getStagesquerytenantGet active funnel stages
applyTemplatemutationadminApply a predefined funnel template
updateStagesmutationadminReplace all funnel stages
suggestSfMappingqueryadminGet suggested Salesforce stage mappings
confirmSfMappingmutationadminSave Salesforce stage mappings

getStages

Returns the active funnel stages for the current tenant, ordered by sortOrder.

funnelConfig.getStages.queryOptions()

Input

None.

Response

[
{ "id": "stg_001", "name": "Awareness", "sortOrder": 1 },
{ "id": "stg_002", "name": "Consideration", "sortOrder": 2 },
{ "id": "stg_003", "name": "Decision", "sortOrder": 3 },
{ "id": "stg_004", "name": "Purchase", "sortOrder": 4 }
]

Example

const trpc = useTRPC();
const { data: stages } = useQuery(
trpc.funnelConfig.getStages.queryOptions()
);

applyTemplate

Replaces the tenant's funnel stages with a predefined template. Existing stages are deactivated.

funnelConfig.applyTemplate.mutationOptions(options)

Access: Admin only

Input

FieldTypeRequiredDescription
template"saas_b2b" | "enterprise" | "plg"YesTemplate to apply

Templates

TemplateStages
saas_b2bAwareness, Interest, Evaluation, Decision, Purchase
enterpriseLead, Discovery, Solution Design, Proposal, Negotiation, Closed
plgSignup, Activation, Engagement, Conversion

Response

{
"success": true,
"stageCount": 5
}

Example

const trpc = useTRPC();
const queryClient = useQueryClient();

const mutation = useMutation(
trpc.funnelConfig.applyTemplate.mutationOptions({
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: trpc.funnelConfig.getStages.queryKey(),
});
},
})
);

mutation.mutate({ template: "saas_b2b" });

updateStages

Replaces all funnel stages with the provided array. Validates that between 2 and 8 stages are provided and that each sortOrder value is unique.

funnelConfig.updateStages.mutationOptions(options)

Access: Admin only

Input

FieldTypeRequiredDescription
stagesFunnelStage[]YesArray of 2--8 stage objects

Each FunnelStage:

FieldTypeRequiredDescription
namestringYesDisplay name
sortOrdernumberYesPosition in funnel (must be unique)

Response

{
"success": true,
"stageCount": 4
}

Example

const trpc = useTRPC();

const mutation = useMutation(
trpc.funnelConfig.updateStages.mutationOptions({})
);

mutation.mutate({
stages: [
{ name: "Awareness", sortOrder: 1 },
{ name: "Evaluation", sortOrder: 2 },
{ name: "Decision", sortOrder: 3 },
{ name: "Closed Won", sortOrder: 4 },
],
});
Validation Rules
  • Minimum 2 stages, maximum 8 stages.
  • Every sortOrder must be unique within the array.
  • Violating either constraint returns a BAD_REQUEST error.

suggestSfMapping

Returns suggested mappings between funnel stages and Salesforce opportunity stages. Matching is based on name similarity.

funnelConfig.suggestSfMapping.queryOptions()

Access: Admin only

Input

None. Requires an active Salesforce connector.

Response

[
{
"funnelStage": "Awareness",
"suggestedSfStage": "Prospecting",
"confidence": 0.72
},
{
"funnelStage": "Decision",
"suggestedSfStage": "Proposal/Price Quote",
"confidence": 0.85
}
]

Example

const trpc = useTRPC();
const { data: suggestions } = useQuery(
trpc.funnelConfig.suggestSfMapping.queryOptions()
);

confirmSfMapping

Persists the Salesforce stage mappings chosen by the admin. These mappings are used during sync to align opportunity stages with funnel stages.

funnelConfig.confirmSfMapping.mutationOptions(options)

Access: Admin only

Input

FieldTypeRequiredDescription
stageMappings{ funnelStage: string, sfStage: string }[]YesArray of stage pairs

Response

{
"success": true,
"mappedCount": 4
}

Example

const trpc = useTRPC();

const mutation = useMutation(
trpc.funnelConfig.confirmSfMapping.mutationOptions({})
);

mutation.mutate({
stageMappings: [
{ funnelStage: "Awareness", sfStage: "Prospecting" },
{ funnelStage: "Decision", sfStage: "Proposal/Price Quote" },
],
});