Skip to main content

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, optional userMetadata, 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.
Input shape
{
  user: {
    id: string,
    walletAddress: string,
    walletType: string,
  },
  userMetadata?: {
    userGroupId?: string, // for multi wallet support
  },
  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 handler export; must call output.setResult(...) and then return output.buildOutput()
  • Result must be an array with at most one reward object
  • data must be stringified JSON and < 1KB
  • Allowed modules: axios, lodash, viem and viem/chains only (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.
loyalty-rule.js
module.exports.handler = async (input, output) => {
  try {
    // Parse input if it was passed as a string
    const parsed = typeof input === 'string' ? JSON.parse(input) : input

    /**
     * input = {
     *   user: { id, walletAddress, walletType },
     *   userMetadata?: { userGroupId?: string, ... },
     *   loyaltyRule: { id, name, type, amount?, ... }
     * }
     */
    const { user, userMetadata, loyaltyRule } = parsed

    // TODO: Implement your eligibility check
    // Example: require a linked group or any other condition you track elsewhere
    // if (!userMetadata?.userGroupId) { throw new Error('User not eligible') }

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

1

Open the Loyalty Rule form

  • Go to Admin → Loyalty → Rules
  • Click “Create Rule” or edit an existing rule
2

Choose rule type and add your code

  • 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
3

Trigger a completion attempt

  • 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
I