Write a Stratus function for loyalty rule completion
Learn the input/output contract and build a handler that awards points or badges when a loyalty rule is completed.
Overview
Use a Stratus function to decide if a user should be rewarded for a specific loyalty rule and return the reward details. This page explains when your function runs, the required input and output shapes, validation rules, and includes a copy‑paste handler template.
If you're new to Stratus functions, read the Function Syntax first for required export patterns, allowed modules, and validation behavior.
When your function runs
Your function executes during a loyalty rule completion attempt for rules of type stratus_function. The platform calls your function with a structured input object containing the current user, userGroupUsers and the loyaltyRule being completed. Your function must return a parsed output describing the reward to grant.
Input contract
Your handler receives two parameters (input, output) and must accept the following input shape. input may be a stringified JSON; parse it if needed.
{
user: {
id: string,
walletAddress: string,
walletType: string,
},
loyaltyRule: {
id: string,
name: string,
type: string,
amount: number,
metadata: object,
startTime: string,
endTime: string,
interval: string,
rewardType: string,
}
}input is passed exactly as shown above by the completion API for
stratus_function rules.
Output contract
Set the result to an array of one reward object and return output.buildOutput().
- walletAddress: string (required) – Address to reward
- amount: number (required if awarding fixed points) – Points to grant
- idempotencyKey: string (optional) – Only pass if you want to override the idempotency key for the rule that we set for managing how often a user can be rewarded for the same rule.
- data: string (optional) – A JSON.stringify()-ed object with extra context; must be valid JSON and under 1KB
- loyaltyBadgeId: string UUID (optional) – Badge to award instead of points or in addition to range-based rules
- loyaltyMultiplierAmount: number (optional) – Multiplier for range-based rules
For now, only a single reward item is allowed. If you return more than one, validation will fail.
Validation rules enforced by the platform
- Exactly one
handlerexport; must calloutput.setResult(...)and thenreturn output.buildOutput() - Result must be an array with at most one reward object
datamust be stringified JSON and < 1KB- Allowed modules:
axios,lodash,viemandviem/chainsonly (see Function Syntax)
Copy‑paste handler template
Below is a ready‑to‑use template based on the attached snippet. Replace the eligibility logic and values with your own.
module.exports.handler = async (input, output) => {
try {
// Parse input if it was passed as a string
let parsed = typeof input === 'string' ? JSON.parse(input) : input
parsed = typeof parsed === 'string' ? JSON.parse(parsed) : parsed;
parsed = typeof parsed === 'string' ? JSON.parse(parsed) : parsed;
/**
* input = {
* user: { id, walletAddress, walletType },
* userGroupUsers?: { id, walletAddress, walletType }[],
* loyaltyRule: { id, name, type, amount?, ... }
* }
*/
const { user, loyaltyRule } = parsed
// Compute reward details
const amount = 2 // Example fixed points
const idempotencyKey = `rule:${loyaltyRule.id}:user:${user.id}` // Replace with a transaction hash or another unique key
// Optional structured context under 1KB
const data = JSON.stringify({
reason: 'eligible via custom function',
ruleType: loyaltyRule.type,
})
// Set result (single reward item only)
output.setResult([
{
walletAddress: user.walletAddress,
amount,
idempotencyKey,
data,
// loyaltyBadgeId: '00000000-0000-0000-0000-000000000000',
// loyaltyMultiplierAmount: 1.25,
},
])
return output.buildOutput()
} catch (error) {
console.error('Error in user code:', error)
throw error
}
}How to add and test your function
- Go to Admin → Loyalty → Rules
- Click "Create Rule" or edit an existing rule
- Set the rule type to
stratus_function- In the function editor within the rule form, paste the handler template and customize it - Save the rule; no separate Stratus function is required
- From your site or via API, attempt to complete the rule for a user
- The platform invokes your function with the input shown above
- If your function returns a valid reward, the user is queued for fulfillment
Verify that your function run succeeded and a reward was recorded for the user.
Troubleshooting
Return exactly one reward object in the array passed to output.setResult.
Ensure data is produced by JSON.stringify({ ... }) and the string length is under 1024 characters.
Confirm your handler sets a result and returns output.buildOutput() as the
final statement.
Import only axios, lodash, viem, or viem/chains. Remove Node built-ins like fs.
See also
- Function Syntax
- Function Templates
- Loyalty rule API reference for response data:
https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-rules#response-data