# Using AI Coding Assistants?
Source: https://docs.snagsolutions.io/ai-coding-assistant
How to use Snag Docs with AI code editors for context-aware coding.
# Use Snag Docs with Your AI Coding Assistant
Supercharge your development workflow by connecting your favorite AI coding assistants—like **Cursor**, **WindSurf**, or **Claude Code**—to Snag Docs. There are two main ways to do this:
## 1. Connect via Model Context Protocol (MCP)
The **Model Context Protocol (MCP)** lets you connect AI tools directly to Snag Docs for real-time, context-aware answers and code suggestions.
Run the following command to generate an MCP server from Snag Docs:
```bash
npx mint-mcp add snag
```
This sets up an MCP server that your AI tools can automatically detect and use.
Once the server is running, open your AI coding assistant. It should automatically detect and integrate with the MCP server for Snag Docs.
You can now ask questions and get context-aware code suggestions powered by your own documentation.
## 2. Index Snag Docs via `llms.txt` or `llms-full.txt`
AI tools can index your documentation for smarter, more relevant answers by using one of two special files:
* **[`llms.txt`](https://docs.snagsolutions.io/llms.txt)** – A machine-readable map of your documentation, optimized for LLMs.
* **`llms-full.txt`** – A single file containing all your documentation content, ideal for bulk ingestion.
Many AI editors allow you to provide a link to documentation for indexing. Use one of the following:
* [https://docs.snagsolutions.io/llms.txt](https://docs.snagsolutions.io/llms.txt)
* [https://docs.snagsolutions.io/llms-full.txt](https://docs.snagsolutions.io/llms-full.txt)
Some editors (like Cursor) automatically index documentation you add in settings. Others may require referencing the docs in the prompt using an **@** symbol or similar. For example:
```
@docs What is the loyalty program setup process?
```
Check your tool’s documentation for exact syntax.
After linking your documentation, your AI assistant will use Snag Docs as a knowledge base for completions, suggestions, and answers.
You’ll get smarter, context-aware help based on the latest Snag Docs content.
***
By connecting your AI coding assistant to Snag Docs, you unlock smarter, faster, and more accurate development support—right where you need it.
# Get Asset upload URL
Source: https://docs.snagsolutions.io/api-reference/asset/get-asset-upload-url
api-reference/openapi.documented.json post /api/assets
This endpoint enables you to upload a file to the resource. Returns a presigned URL and the asset's public URL. Call PUT with the file as the body to upload the asset using the presigned URL.
# Get auction bids
Source: https://docs.snagsolutions.io/api-reference/auction/get-auction-bids
api-reference/openapi.documented.json get /api/auction_bids
Returns a list of auction bids with optional filtering and pagination.
# Get auctions
Source: https://docs.snagsolutions.io/api-reference/auction/get-auctions
api-reference/openapi.documented.json get /api/auctions
Returns a list of auctions with optional filtering and pagination.
# Create new badge
Source: https://docs.snagsolutions.io/api-reference/badge/create-new-badge
api-reference/openapi.documented.json post /api/loyalty/badges
This endpoint allows you to configure a new badge
# Delete badge (by id)
Source: https://docs.snagsolutions.io/api-reference/badge/delete-badge-by-id
api-reference/openapi.documented.json delete /api/loyalty/badges/{id}
This endpoint allows you to delete a badge.
# Get badges (all or by id)
Source: https://docs.snagsolutions.io/api-reference/badge/get-badges-all-or-by-id
api-reference/openapi.documented.json get /api/loyalty/badges
This endpoint allows you to fetch badge(s) data.
# Revoke badge from account
Source: https://docs.snagsolutions.io/api-reference/badge/revoke-badge-from-account
api-reference/openapi.documented.json post /api/loyalty/badges/{id}/revoke
This endpoint allows you to revoke a badge from an account
# Reward badge for account
Source: https://docs.snagsolutions.io/api-reference/badge/reward-badge-for-account
api-reference/openapi.documented.json post /api/loyalty/badges/{id}/reward
This endpoint allows you to reward a badge for an account
# Update badge (by id)
Source: https://docs.snagsolutions.io/api-reference/badge/update-badge-by-id
api-reference/openapi.documented.json post /api/loyalty/badges/{id}
This endpoint allows you to update an existing badge.
# API Deprecation
Source: https://docs.snagsolutions.io/api-reference/deprecation
This is a list of deprecated APIs with a timeline for removal. We support deprecated APIs for 2 months before permanent removal.
## Deprecated API List
# Connect a user to User Group
Source: https://docs.snagsolutions.io/api-reference/identity/connect-a-user-to-user-group
api-reference/openapi.documented.json post /api/users/connect
This endpoint allows you to create a user
# Connect Auth
Source: https://docs.snagsolutions.io/api-reference/identity/connect-auth
api-reference/openapi.documented.json get /api/{authType}/auth
This endpoint allows you to connect your auth account to a Snag account
# Create a new website user attribute
Source: https://docs.snagsolutions.io/api-reference/identity/create-a-new-website-user-attribute
api-reference/openapi.documented.json post /api/website_user_attributes
Create a new website user attribute
# Create a new website user attribute value
Source: https://docs.snagsolutions.io/api-reference/identity/create-a-new-website-user-attribute-value
api-reference/openapi.documented.json post /api/website_user_attributes/values
Create a new website user attribute value
# Create user device
Source: https://docs.snagsolutions.io/api-reference/identity/create-user-device
api-reference/openapi.documented.json post /api/users/devices
This endpoint is used to create user devices for fraud tracking
# Create user metadata
Source: https://docs.snagsolutions.io/api-reference/identity/create-user-metadata
api-reference/openapi.documented.json post /api/users/metadatas
This endpoint is used to create user metadata
# Delete a website user attribute
Source: https://docs.snagsolutions.io/api-reference/identity/delete-a-website-user-attribute
api-reference/openapi.documented.json delete /api/website_user_attributes/{id}
Delete a website user attribute
# Disconnect a user from User Group
Source: https://docs.snagsolutions.io/api-reference/identity/disconnect-a-user-from-user-group
api-reference/openapi.documented.json post /api/users/disconnect
This endpoint allows you to disconnect a user from another user
# Get all website user attribute values
Source: https://docs.snagsolutions.io/api-reference/identity/get-all-website-user-attribute-values
api-reference/openapi.documented.json get /api/website_user_attributes/values
Get all website user attribute values
# Get all website user attributes
Source: https://docs.snagsolutions.io/api-reference/identity/get-all-website-user-attributes
api-reference/openapi.documented.json get /api/website_user_attributes
Get all website user attributes
# Get user metadata
Source: https://docs.snagsolutions.io/api-reference/identity/get-user-metadata
api-reference/openapi.documented.json get /api/users/metadatas
This endpoint is used to get user metadata
# Get users
Source: https://docs.snagsolutions.io/api-reference/identity/get-users
api-reference/openapi.documented.json get /api/users
This endpoint allows you to get users
# Post apiusersverify
Source: https://docs.snagsolutions.io/api-reference/identity/post-apiusersverify
api-reference/openapi.documented.json post /api/users/verify
# User count
Source: https://docs.snagsolutions.io/api-reference/identity/user-count
api-reference/openapi.documented.json get /api/users/count
This endpoint returns the total user count
# Snag API
Source: https://docs.snagsolutions.io/api-reference/introduction
Snag API Documentation

Please only use the endpoints specified in this document. Using any other
endpoints will cause issues with your client.
## What You Need
Retrieve your API Key, Currency ID, and Organization ID from the admin dashboard.
## Authentication
All API endpoints require authentication using an API key, which must be included in the request headers.
Include your API key in the x-api-key header as shown below:
```http
x-api-key:
```
Here’s an example of an HTTP request with the API key:
```http
GET /api/v1/your-endpoint HTTP/1.1
Host: api.snag.com
x-api-key:
Content-Type: application/json
{ /* Request body if applicable */ }
```
# Get page sections
Source: https://docs.snagsolutions.io/api-reference/landing-page/get-page-sections
api-reference/openapi.documented.json get /api/page_sections
This endpoint allows you to fetch page sections
# Complete Loyalty Rule
Source: https://docs.snagsolutions.io/api-reference/loyalty/complete-loyalty-rule
api-reference/openapi.documented.json post /api/loyalty/rules/{id}/complete
Verify a loyalty rule based on user action and reward them if applicable. This endpoint currently only supports following rule types code_entry, text_input, link_click, discord_member, connect_wallet, check_in, external_rule, drip_x_follow, drip_x_new_tweet, drip_x_text_in_bio, drip_x_text_in_name, drip_x_text_in_comment, drip_x_tweet, telegram_join, DiscordMessages, youtube_subscribers, youtube_comment, steam_wishlist
# Create a loyalty currency
Source: https://docs.snagsolutions.io/api-reference/loyalty/create-a-loyalty-currency
api-reference/openapi.documented.json post /api/loyalty/currencies
Create a loyalty currency
# Create Loyalty Multiplier
Source: https://docs.snagsolutions.io/api-reference/loyalty/create-loyalty-multiplier
api-reference/openapi.documented.json post /api/loyalty/multipliers
Create a new loyalty multiplier for a wallet.
# Create Loyalty Rule
Source: https://docs.snagsolutions.io/api-reference/loyalty/create-loyalty-rule
api-reference/openapi.documented.json post /api/loyalty/rules
Create a new Loyalty Rule
# Create Loyalty Rule Groups
Source: https://docs.snagsolutions.io/api-reference/loyalty/create-loyalty-rule-groups
api-reference/openapi.documented.json post /api/loyalty/rule_groups/create
Create a new loyalty rule groups
# Create Loyalty Transaction
Source: https://docs.snagsolutions.io/api-reference/loyalty/create-loyalty-transaction
api-reference/openapi.documented.json post /api/loyalty/transactions
Create a loyalty transaction to update account balances.
# Delete Loyalty Multiplier by External Identifier
Source: https://docs.snagsolutions.io/api-reference/loyalty/delete-loyalty-multiplier-by-external-identifier
api-reference/openapi.documented.json delete /api/loyalty/multipliers
Delete a loyalty multiplier by its external identifier.
# Delete Loyalty Multiplier by ID
Source: https://docs.snagsolutions.io/api-reference/loyalty/delete-loyalty-multiplier-by-id
api-reference/openapi.documented.json delete /api/loyalty/multipliers/{multiplierId}
Delete a loyalty multiplier by its ID.
# Delete Loyalty Rule
Source: https://docs.snagsolutions.io/api-reference/loyalty/delete-loyalty-rule
api-reference/openapi.documented.json delete /api/loyalty/rules/{id}
Delete an existing Loyalty Rule
# Delete Loyalty Rule Group
Source: https://docs.snagsolutions.io/api-reference/loyalty/delete-loyalty-rule-group
api-reference/openapi.documented.json delete /api/loyalty/rule_groups/{id}
Delete loyalty rule group by ID
# Get loyalty account streaks
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-account-streaks
api-reference/openapi.documented.json get /api/loyalty/account_streaks
Get loyalty account streaks
# Get loyalty accounts
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-accounts
api-reference/openapi.documented.json get /api/loyalty/accounts
Get loyalty accounts
# Get loyalty currencies
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-currencies
api-reference/openapi.documented.json get /api/loyalty/currencies
Get loyalty currencies
# Get Loyalty Multipliers
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-multipliers
api-reference/openapi.documented.json get /api/loyalty/multipliers
Get Loyalty Multipliers
# Get Loyalty Rule Chains
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-rule-chains
api-reference/openapi.documented.json get /api/loyalty/rule_chains
Retrieve configured loyalty rule chains
# Get Loyalty Rule Edits
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-rule-edits
api-reference/openapi.documented.json get /api/loyalty/rule_edits
Retrieve configured loyalty rule edits with optional pagination and filters
# Get Loyalty Rule Groups
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-rule-groups
api-reference/openapi.documented.json get /api/loyalty/rule_groups
Retrieve configured loyalty rule groups
# Get Loyalty Rule Statuses
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-rule-statuses
api-reference/openapi.documented.json get /api/loyalty/rule_statuses
Retrieve loyalty rule statuses
# Get Loyalty Rules
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-rules
api-reference/openapi.documented.json get /api/loyalty/rules
Retrieve configured loyalty rules with optional pagination and filters
# Get Loyalty Transaction Entries
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-transaction-entries
api-reference/openapi.documented.json get /api/loyalty/transaction_entries
Fetch loyalty transaction entries for wallets or users, representing account balance changes.
# Get Processing status for a specific user on loyalty rules
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-processing-status-for-a-specific-user-on-loyalty-rules
api-reference/openapi.documented.json get /api/loyalty/rules/status
This will return the processing status of quests for a specific user
# Get the rank of a user based on their loyalty points
Source: https://docs.snagsolutions.io/api-reference/loyalty/get-the-rank-of-a-user-based-on-their-loyalty-points
api-reference/openapi.documented.json get /api/loyalty/accounts/{id}/rank
Returns the user's rank determined by their loyalty points for the specified loyalty currency. This can be a slow operation for large organizations. We recommend caching when possible.
# Restore Loyalty Rule Edit
Source: https://docs.snagsolutions.io/api-reference/loyalty/restore-loyalty-rule-edit
api-reference/openapi.documented.json post /api/loyalty/rule_edits/{id}/restore
Restore a loyalty rule from a rule edit
# Update Loyalty Multiplier
Source: https://docs.snagsolutions.io/api-reference/loyalty/update-loyalty-multiplier
api-reference/openapi.documented.json post /api/loyalty/multipliers/{multiplierId}
Update an existing loyalty multiplier.
# Update Loyalty Rule
Source: https://docs.snagsolutions.io/api-reference/loyalty/update-loyalty-rule
api-reference/openapi.documented.json post /api/loyalty/rules/{id}
Update an existing Loyalty Rule
# Update Loyalty Rule Group
Source: https://docs.snagsolutions.io/api-reference/loyalty/update-loyalty-rule-group
api-reference/openapi.documented.json post /api/loyalty/rule_groups/{id}
Update loyalty rule group by ID
# Update Loyalty Rule Status
Source: https://docs.snagsolutions.io/api-reference/loyalty/update-loyalty-rule-status
api-reference/openapi.documented.json post /api/loyalty/rule_statuses
Update a loyalty rule status
# Get minting assets
Source: https://docs.snagsolutions.io/api-reference/minting/get-minting-assets
api-reference/openapi.documented.json get /api/minting/assets
Returns minting assets and any relevant context
# Create a new question
Source: https://docs.snagsolutions.io/api-reference/question/create-a-new-question
api-reference/openapi.documented.json post /api/loyalty/questions
This endpoint allows you to create a new question.
# Get questions for a loyalty rule
Source: https://docs.snagsolutions.io/api-reference/question/get-questions-for-a-loyalty-rule
api-reference/openapi.documented.json get /api/loyalty/questions
This endpoint allows you to fetch questions for a loyalty rule.
# Get user's question responses
Source: https://docs.snagsolutions.io/api-reference/question/get-users-question-responses
api-reference/openapi.documented.json get /api/loyalty/questions_responses
Retrieve responses submitted by the authenticated user, optionally filtered by question IDs
# Submit a response to a question
Source: https://docs.snagsolutions.io/api-reference/question/submit-a-response-to-a-question
api-reference/openapi.documented.json post /api/loyalty/questions_responses
This endpoint allows you to submit a response to a question.
# Update an existing question
Source: https://docs.snagsolutions.io/api-reference/question/update-an-existing-question
api-reference/openapi.documented.json post /api/loyalty/questions/{id}
This endpoint allows you to update an existing question.
# Rate Limits
Source: https://docs.snagsolutions.io/api-reference/rate-limits
This document outlines the rate limiting policies implemented across our API endpoints to ensure fair usage and system stability.
## Overview
Rate limits are implemented at multiple levels to protect our infrastructure and ensure fair usage:
1. Host-level rate limits
2. API endpoint-specific rate limits
3. User-level rate limits
4. Special rate limits for specific features
## Host-Level Rate Limits
The system implements a base rate limit of 250 requests per second (RPS) per hostname. This is enforced through a combination of:
* In-memory rate limiting
* Distributed rate limiting
Note: To avoid host-level rate limits which are primarily for bot protection, you should not use `admin.snagsolutions.io` as a base URL. Instead, set up your own hostname via our admin panel under the Hostname tab.
## API Endpoint Rate Limits
Different endpoints have specific rate limits:
### Loyalty System Endpoints
* `/api/loyalty/transaction_entries`: 30 RPS
* `/api/loyalty/transaction_entries/count`: 10 RPS
* `/api/loyalty/account_streaks`: 10 RPS
* `/api/loyalty/accounts/[id]/rank`: 1 RPS
* `/api/loyalty/multipliers`: 30 RPS
### Loyalty Rule Completion
The loyalty rule completion endpoint has multiple rate limit layers:
1. User-based rate limit: 5 requests per minute per user
2. Rule-based rate limit: 1 request per minute per user per rule
3. Website-level rate limit: 10 requests per second per rule
For external rules, these limits are multiplied by a factor of 5.
## Rate Limit Responses
When you hit a rate limit, the API will respond with a 429 status code and a message indicating that you've exceeded the rate limit. The response will include:
```json
{
"message": "Too many requests, please try again later."
}
```
## Best Practices
1. Implement exponential backoff when you receive 429 responses
2. Cache responses when possible to reduce API calls
3. Use appropriate hostnames for your integration
4. Monitor your API usage to stay within limits
5. Consider implementing client-side rate limiting for high-volume applications
## Avoiding Rate Limits
Here are several strategies to effectively work with rate limits:
### 1. Implement Caching
* Cache frequently accessed data on your end
* Use appropriate cache TTLs based on data freshness requirements
* Consider implementing a distributed cache for high-traffic applications
### 2. Batch Requests
* Combine multiple requests into a single batch request where possible
* Use bulk endpoints instead of individual requests
* Implement request queuing for non-time-sensitive operations
### 3. Optimize API Usage
* Only request data that you actually need
* Use pagination to limit response sizes
* Implement proper error handling and retry logic
### 4. Implement Client-Side Rate Limiting
* Add rate limiting logic in your application
* Use token bucket or leaky bucket algorithms
* Distribute requests evenly across time windows
### 5. Monitor and Adjust
* Keep track of your API usage patterns
* Adjust your implementation based on rate limit responses
* Implement proper logging to identify rate limit issues early
# Create referral code
Source: https://docs.snagsolutions.io/api-reference/referrals/create-referral-code
api-reference/openapi.documented.json post /api/referral/codes
This endpoint allows you to create a referral code
# Create referral user
Source: https://docs.snagsolutions.io/api-reference/referrals/create-referral-user
api-reference/openapi.documented.json post /api/referral/users
This endpoint allows you to create a referral user
# Get referrals
Source: https://docs.snagsolutions.io/api-reference/referrals/get-referrals
api-reference/openapi.documented.json get /api/referral/users
This endpoint allows you to get referrals
# Snag SDK
Source: https://docs.snagsolutions.io/api-reference/sdk
# Introduction
This library provides convenient access to the Snag Solutions REST API from server-side TypeScript or JavaScript.
The REST API documentation can be found on [docs.snagsolutions.io](https://docs.snagsolutions.io). The full API of this library can be found in [https://docs.snagsolutions.io/api-reference/introduction](https://docs.snagsolutions.io/api-reference/introduction).
## Installation
```sh
npm install @snagsolutions/sdk
```
## Usage
The full API of this library can be found in [https://docs.snagsolutions.io/api-reference/introduction](https://docs.snagsolutions.io/api-reference/introduction).
```js
import SnagSolutions from '@snagsolutions/sdk';
const client = new SnagSolutions({apiKey: });
async function main() {
const asset = await client.assets.create({ fileName: 'REPLACE_ME' });
console.log(asset.signedUrl);
}
main();
```
### Request & Response types
This library includes TypeScript definitions for all request params and response fields. You may import and use them like so:
```ts
import SnagSolutions from '@snagsolutions/sdk'
const client = new SnagSolutions()
async function main() {
const params: SnagSolutions.AssetCreateParams = { fileName: 'REPLACE_ME' }
const asset: SnagSolutions.AssetCreateResponse =
await client.assets.create(params)
}
main()
```
Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.
## Handling errors
When the library is unable to connect to the API,
or if the API returns a non-success status code (i.e., 4xx or 5xx response),
a subclass of `APIError` will be thrown:
```ts
async function main() {
const asset = await client.assets
.create({ fileName: 'REPLACE_ME' })
.catch(async (err) => {
if (err instanceof SnagSolutions.APIError) {
console.log(err.status) // 400
console.log(err.name) // BadRequestError
console.log(err.headers) // {server: 'nginx', ...}
} else {
throw err
}
})
}
main()
```
\#Error codes are as followed:
| Status Code | Error Type |
| ----------- | -------------------------- |
| 400 | `BadRequestError` |
| 401 | `AuthenticationError` |
| 403 | `PermissionDeniedError` |
| 404 | `NotFoundError` |
| 422 | `UnprocessableEntityError` |
| 429 | `RateLimitError` |
| >=500 | `InternalServerError` |
| N/A | `APIConnectionError` |
### Retries
Certain errors will be automatically retried 2 times by default, with a short exponential backoff.
Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,
429 Rate Limit, and >=500 Internal errors will all be retried by default.
You can use the `maxRetries` option to configure or disable this:
```js
// Configure the default for all requests:
const client = new SnagSolutions({
maxRetries: 0, // default is 2
})
// Or, configure per-request:
await client.assets.create(
{ fileName: 'REPLACE_ME' },
{
maxRetries: 5,
}
)
```
### Timeouts
Requests time out after 1 minute by default. You can configure this with a `timeout` option:
```ts
// Configure the default for all requests:
const client = new SnagSolutions({
timeout: 20 * 1000, // 20 seconds (default is 1 minute)
})
// Override per-request:
await client.assets.create(
{ fileName: 'REPLACE_ME' },
{
timeout: 5 * 1000,
}
)
```
On timeout, an `APIConnectionTimeoutError` is thrown.
Note that requests which time out will be [retried twice by default](#retries).
## Advanced Usage
### Accessing raw Response data (e.g., headers)
The "raw" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.
You can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.
```ts
const client = new SnagSolutions()
const response = await client.assets
.create({ fileName: 'REPLACE_ME' })
.asResponse()
console.log(response.headers.get('X-My-Header'))
console.log(response.statusText) // access the underlying Response object
const { data: asset, response: raw } = await client.assets
.create({ fileName: 'REPLACE_ME' })
.withResponse()
console.log(raw.headers.get('X-My-Header'))
console.log(asset.signedUrl)
```
### Making custom/undocumented requests
This library is typed for convenient access to the documented API. If you need to access undocumented
endpoints, params, or response properties, the library can still be used.
#### Undocumented endpoints
To make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.
Options on the client, such as retries, will be respected when making these requests.
```ts
await client.post('/some/path', {
body: { some_prop: 'foo' },
query: { some_query_arg: 'bar' },
})
```
#### Undocumented request params
To make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented
parameter. This library doesn't validate at runtime that the request matches the type, so any extra values you
send will be sent as-is.
```ts
client.foo.create({
foo: 'my_param',
bar: 12,
// @ts-expect-error baz is not yet public
baz: 'undocumented option',
})
```
For requests with the `GET` verb, any extra params will be in the query, all other requests will send the
extra param in the body.
If you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request
options.
#### Undocumented response properties
To access undocumented response properties, you may access the response object with `// @ts-expect-error` on
the response object, or cast the response object to the requisite type. Like the request params, we do not
validate or strip extra properties from the response from the API.
### Customizing the fetch client
By default, this library uses `node-fetch` in Node, and expects a global `fetch` function in other environments.
If you would prefer to use a global, web-standards-compliant `fetch` function even in a Node environment,
(for example, if you are running Node with `--experimental-fetch` or using NextJS which polyfills with `undici`),
add the following import before your first import `from "SnagSolutions"`:
```ts
// Tell TypeScript and the package to use the global web fetch instead of node-fetch.
// Note, despite the name, this does not add any polyfills, but expects them to be provided if needed.
import '@snagsolutions/sdk/shims/web'
import SnagSolutions from '@snagsolutions/sdk'
```
To do the inverse, add `import "@snagsolutions/sdk/shims/node"` (which does import polyfills).
This can also be useful if you are getting the wrong TypeScript types for `Response` ([more details](https://github.com/Snag-Solutions/node-sdk/tree/main/src/_shims#readme)).
### Logging and middleware
You may also provide a custom `fetch` function when instantiating the client,
which can be used to inspect or alter the `Request` or `Response` before/after each request:
```ts
import { fetch } from 'undici' // as one example
import SnagSolutions from '@snagsolutions/sdk'
const client = new SnagSolutions({
fetch: async (url: RequestInfo, init?: RequestInit): Promise => {
console.log('About to make a request', url, init)
const response = await fetch(url, init)
console.log('Got response', response)
return response
},
})
```
Note that if given a `DEBUG=true` environment variable, this library will log all requests and responses automatically.
This is intended for debugging purposes only and may change in the future without notice.
### Configuring an HTTP(S) Agent (e.g., for proxies)
By default, this library uses a stable agent for all http/https requests to reuse TCP connections, eliminating many TCP & TLS handshakes and shaving around 100ms off most requests.
If you would like to disable or customize this behavior, for example to use the API behind a proxy, you can pass an `httpAgent` which is used for all requests (be they http or https), for example:
```ts
import http from 'http'
import { HttpsProxyAgent } from 'https-proxy-agent'
// Configure the default for all requests:
const client = new SnagSolutions({
httpAgent: new HttpsProxyAgent(process.env.PROXY_URL),
})
// Override per-request:
await client.assets.create(
{ fileName: 'REPLACE_ME' },
{
httpAgent: new http.Agent({ keepAlive: false }),
}
)
```
## Semantic versioning
This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
1. Changes that only affect static types, without breaking runtime behavior.
2. Changes to library internals which are technically public but not intended or documented for external use. (Please open a GitHub issue to let us know if you are relying on such internals)\_.
3. Changes that we do not expect to impact the vast majority of users in practice.
We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
We are keen for your feedback; please open an [issue](https://www.github.com/Snag-Solutions/node-sdk/issues) with questions, bugs, or suggestions.
## Requirements
TypeScript >= 4.5 is supported.
The following runtimes are supported:
* Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more)
* Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.
* Deno v1.28.0 or higher.
* Bun 1.0 or later.
* Cloudflare Workers.
* Vercel Edge Runtime.
* Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time).
* Nitro v2.6 or greater.
Note that React Native is not supported at this time.
If you are interested in other runtime environments, please open or upvote an issue on GitHub.
# Assign roles to users for a website
Source: https://docs.snagsolutions.io/api-reference/website/assign-roles-to-users-for-a-website
api-reference/openapi.documented.json post /api/website_user_roles
Assign roles to users for a specific website
# Create website
Source: https://docs.snagsolutions.io/api-reference/website/create-website
api-reference/openapi.documented.json post /api/websites
Creates a new website
# Create Website Collection
Source: https://docs.snagsolutions.io/api-reference/website/create-website-collection
api-reference/openapi.documented.json post /api/website_collections
Creates a new collection under a website
# Get roles of users for a website
Source: https://docs.snagsolutions.io/api-reference/website/get-roles-of-users-for-a-website
api-reference/openapi.documented.json get /api/website_user_roles
Retrieves roles of users for a specific website. If userId is provided, retrieves the role of that specific user for the website.
# Get Website Collections
Source: https://docs.snagsolutions.io/api-reference/website/get-website-collections
api-reference/openapi.documented.json get /api/website_collections
Retrieves collections for a specific website.
# Get websites
Source: https://docs.snagsolutions.io/api-reference/website/get-websites
api-reference/openapi.documented.json get /api/websites
Returns a list of websites. Includes optional query parameters for filtering and pagination.
# Badges
Source: https://docs.snagsolutions.io/create/badges
This recipe explains how to create and manage badges in Snag Loyalty.
## Overview
The Badges feature in Snag Admin allows you to create and manage badges that users can earn by fulfilling specific condtions. These badges are displated on user profiles along with their progress towward unlocking them.

Users can earn badges by:
* Completing specific rules or set of rules
* Achieving a certain amount of loyalty points
* Unlocking another badge or set of badges
* Meeting any other custom conditions
Each badge displays a list of conditions and tracks user progress toward achieving them. The API provides real-time updates on user completion status, allowing users to see how close they are to earning a badge.

***
## Creating and Managing Badges
This recipe explains how to manage badges using the Snag API, including creating, updating and deleting badges but also assigning badges to users and revoking them.
### Fetching Badges
The [`GET /api/loyalty/badges`](https://docs.snagsolutions.io/api-reference/badge/get-badges-all-or-by-id) endpoint allows for fetching of loyalty badges created on your Snag account. This endpoint provides various filters to allow pagination. Badges are sorted by their creation date in descending order.
#### Example Request
Request
```
{
"organizationId": "your-organization-id",
"websiteId": "your-website-id",
"limit": 10
}
```
* Note: for paginated requests be sure to add the `startingAfter` property to subsequent requests.
#### Example Response
```
{
"data": [
{
"id": "b1b1b1b1-b1b1-b1b1-b1b1-b1b1b1b1b1b1",
"name": "Example Badge",
"description": "This is an example badge",
"imageUrl": "https://example.com/image.png",
"loyaltyConditions": [
{
"id": "c1c1c1c1-c1c1-c1c1-c1c1-c1c1c1c1c1c1",
"type": "rule",
"description": "Rule completion: Link Click",
"amount": null,
"repeatCount": null,
"requiredCount": null,
"loyaltyRuleGroupId": null,
"association": [
{
"loyaltyRule": {
"id": "r1r1r1r1-r1r1-r1r1-r1r1-r1r1r1r1r1r1",
"name": "Link Click"
},
"loyaltyBadge": null,
"loyaltyRuleGroup": null,
"loyaltyCurrency": null,
"loyaltyLeaderboardView": null
}
],
"loyaltyCurrencyId": null,
"csvUrl": null
}
]
}
],
"hasNextPage": "false"
}
```
### Creating a Badge
The [`POST /api/loyalty/badges`](https://docs.snagsolutions.io/api-reference/badge/create-new-badge) endpoint allows for creating a new badge on your Snag account. This endpoint requires the following parameters:
* `organizationId`: Your organization ID
* `websiteId`: Your website ID
* `name`: The name of the badge
* `description`: A description of the badge
* `imageUrl`: The URL of the badge image
* `rules`: An array of conditions that must be met to earn the badge
### Updating a Badge
The [`POST /api/loyalty/badges/{id}`](https://docs.snagsolutions.io/api-reference/badge/update-badge-by-id) endpoint allows for updating an existing badge on your Snag account.
The `id` parameter is required to identify the badge to update. We only allow updating the `name`, `description`, and `imageUrl` of the badge. The reason for this is to prevent any changes that could affect the badge's conditions and user progress.
### Deleting a Badge
The [`DELETE /api/loyalty/badges/{id}`](https://docs.snagsolutions.io/api-reference/badge/delete-badge-by-id) endpoint allows for deleting an existing badge on your Snag account.
The `id` parameter is required to identify the badge to delete.
### Rewarding User with a Badge
The [`POST /api/loyalty/badges/{id}/reward`](https://docs.snagsolutions.io/api-reference/badge/reward-badge-for-account) endpoint allows for rewarding a user with a badge on your Snag account.
The `id` parameter is required to identify the badge to reward, and either `userId` or `walletAddress` is required to identify the user to reward.
### Revoking a Badge from a User
The [`POST /api/loyalty/badges/{id}/revoke`](https://docs.snagsolutions.io/api-reference/badge/revoke-badge-from-account) endpoint allows to revoke a badge from a user on your Snag account.
The `id` parameter is required to identify the badge to revoke, and either `userId` or `walletAddress` is required to identify the user to revoke.
***
## Assigning Badges via CSV
For manual badge assignment, upload a CSV file containing wallet addresses of users who should receive a specific badge. The uploaded file should follow this format:
```
walletAddress
0x1...abc
0x2...def
```
After upload, the system will process the file and assign the badge to the listed users.
## Important Notes
This system provides a flexible way to reward user engagement and encourage participation through achievements. The Badge feature is only available to websites with active loyalty programs.
# Banners
Source: https://docs.snagsolutions.io/create/banners
The following will walk you through how to set up a banner.
### Overview
Banners allow you to leverage marketplace real-estate to promote or highlight anything (i.e., new mints, project announcements). We allow for complete customization of banners, and make it super easy for you to set up + manage this tool.
### Set up
Navigate to your admin dashboard at admin.snagsolutions.io and on the home page click on 'Add Banner'

**You can also access & manage active banners via the 'Announcements' tab under 'Content Management'**
### Setting Up Your First Banner
After clicking 'Add Banner' you'll be able to customize your banner elements such as: the title, custom link, link button text, banner duration, choose a banner template, and even upload your own banner image!

*You can test different color schemes and variations with our marketplace viewer before you post anything!*
For the Custom Image Tab we recommend uploading the following file sizes to completely customize the UX:
**Marketplace banner:**
* 9:1 ratio, recommended at least 1800x200px
**Feed banner:**
* 4:1 ratio, recommended at least 800x200px
**Mobile banner:**
* 3:1 ratio, recommended at least 600x200px
### Launch Your Banner
Once you hit publish your banner will be visible across the marketplace.

# Page builder
Source: https://docs.snagsolutions.io/create/page-builder
The following is a quick guide to creating landing and ecosystem app pages.
## Overview
The page builder has multiple different section types that can be customized individually. Depending on the type of page you are trying to build, different section types will be available.
### 
### Section types
1. Carousel
2. Strip
3. Featured
4. All items
5. List
6. Image
7. Text
8. Code
9. Featured apps
10. Apps grid
## Carousel
You have the ability to choose from 3 sizes of carousel:
* Small (small-sized cards)
* Medium (medium-sized cards)
* Large (full size)
You can align the text (title and description) left or to the center.
Then choose between showing multiple collections or items within a specific collection.

If you selected the large carousel you have to individually define the title, description and background for each collection. This gives you more customization options to better highlight individual collections.

Examples:
## 


## Strip
The strip is a banner-type section made out of an image, title, description and button. You can choose what combination of the four you wish to have. You can align the content to the bottom middle or left side, this also impacts the overlay type.
* Bottom - Black overlay gradient from the bottom
* Middle - Full 50% black overlay
* Left - Black overlay gradient from the left side

If you wish, you can also toggle on the custom mobile design under the advanced options to upload a different image that is better suited for mobile devices. This images doesn’t have an overlay since the title, description and button are positioned outside of the image. You have the option to position the text either above or below the image.

Examples:



Custom mobile image:
## 
## Featured
The featured section allows you to highlight a specific collection or item. You can align the main image to the left or right and add a custom title, and description.

Examples:
## 

## All items
The all-items section is a grid of 8 items from selected collections. You can also choose to show items from all collections.

Examples:
## 
## List
List all your collections and choose how to sort them. You can sort by:
* Latest sales
* Recently created
* Floor price
* 24h volume
* Unique holders

Examples:
## 
## Image
You can add an image with a custom aspect ratio. The image will always be stretched to the full width of the screen and the height will adapt based on the aspect ratio of the image.
If you wish, you can also upload a different image that is better suited for mobile devices
The image can also have a link attached to it which makes the entire image clickable.

Examples:
## 
## Text
The text section allows you to add rich text with headlines, bullet points and other customization options.

Examples:
## 
## Code
The code section gives you endless possibilities to insert custom code on your page.
Custom code is not validated. Incorrect code may cause issues.

Examples:
## 
## Featured app
The featured app highlights a single app of your choice. You can add a call-to-action button that links to a specific loyalty section or an external page.
This section can also be used as a hero element for your Apps Hub. Instead of featuring a specific app, you can introduce your ecosystem or highlight any key content.
**Media:**
* Tile media is shown on the Apps Hub.
* Page media serves as the banner on the linked loyalty page.
**Layout:**
* Container Style - Displays the featured app in a large tile, keeping it visually aligned with the Apps Grid while making it still prominent.
* Full-width Hero - Expands the featured app into a large banner, ideal for a general hero section introducing your loyalty program.
## 
Examples:
## 

## Apps grid
The apps grid allows you to showcase multiple apps in a structured, visually engaging way. Use it to create a hub for different app experiences within your loyalty ecosystem. Each app can have its own media, text, button, and links.
Apps can be reordered within the grid, and you can choose whether to display or hide quest and points information.
**Media:**
* Tile media is shown on the apps hub.
* Page media serves as the banner on the linked loyalty page.

Examples:

# Rewards Shop
Source: https://docs.snagsolutions.io/create/rewards-shop
The following is a quickstart guide to creating contracts, minting assets, and listing assets on your marketplace frontend as a mint or auction.
## Overview
[Our asset creation tab in the admin tool](https://admin.snagsolutions.io/) consists of three separate flows that comprise the entire contract set and minting & auction page creation process:
1. Contract set up
2. Metadata configuration / asset creation
3. Listing or auction creation
## Step by step
### Contract set up:
1. Access the Asset Creation tab in the menu on the left and hit the create new contract button in the top right.

1. Hit the 'Create New Contract' button on the next modal to confirm you'll be the owner on the contract. On the next tab you'll:
1. Input the collection name, symbol, and image along with optional description and external link.
2. Choose the token type. Only one token type can exist on the NFT smart contract.
3. Choose chain
4. *Optional:* enable meta transaction if you plan to enable gasless transactions in the future via Stratus relayers
.
5. Choose the wallet address for mint and royalty payouts


### Add Assets to Contract
1. The next step is to configure metadata to the contract as individual assets. We support individual asset creation to start, with .CSV upload and other multi-asset upload capabilities coming soon.
1. Add asset name, description, info about the artist, media, and optional trait info
2. Optional fields
1. *Add quantity limit*: maximum amount mintable/wallet
2. *Add minimum*: minimum amount to mint/transaction
3. *Burn to redeem*: if you want users to burn the NFT to redeem it. You can add a field they need to fill in, show a blank text or collect shipping details(needs API integration).
3. Click 'Finish' when you're done or 'Duplicate' / 'New Asset' to add more


### Listing
1. You can now hit 'List Assets' on the contract modal in the assets creation tab when ready to either list, create an auction or create a sweepstakes.


#### List assets for purchase
1. Choose the currency you'd like to list in (native currency or loyalty points if enabled)
2. Choose the price and the assets you'd like to list - to see which assets remain unlisted toggle over the 'Unlisted Assets' text in the modal's topline.
1. Note: you can either set the assets you want by asset ID either by comma separation or - (ie. 1,2,3,4 and 1-4 do the same thing)
3. Choose listing duration start and (optional) end time

#### List assets for auction
1. Add an auction name, description, duration, and currency
2. **Note:** Auctions can be tied to one or more than one onchain asset, so please add sufficient description to explain to the user what they're bidding on
3. Choose your auction mechanics:
1. Minimum Bid: The minimum amount any bidder can start the auction with
2. Minimum Bid Increment: The minimum increase on any bid from the previous highest bid
3. Reserve Price: The minimum bid that is valid to win the auction, this is the most important of these three inputs
4. **Multi-Winner Auctions Only:** By default, multi-winner auctions charge each bidder the amount they bid, if 'Reverse Dutch Auction' is toggled we'll instead refund all winners the difference of their bid and the lowest price winning bid
5. **Blind Auctions Only:** If toggled on, users can only see their own bids. All other bids are hidden
6. Choose the prize!


#### List assets for sweepstakes
1. Add the sweepstakes name, description, duration, and entry token purchase currency
2. Choose the entry ticket and specify the total number of available tickets.
3. Choose the prize(s).


1. You're live! View these listings as part of your marketplace!
# Available loyalty rules
Source: https://docs.snagsolutions.io/loyalty/available-loyalty-rules

## Overview
Snag loyalty supports a wide variety of platforms and user actions both on & offchain. With your Snag Loyalty Program you can track, evaluate, and reward user contributions across social (X, Discord, Telegram, and others) as well as anything onchain (bridge funds, hold token, connect wallet, and more). Using Snag's REST API you can also integrate contributions from an external application like a game or offchain social app.
## User onboarding rules
Reward users for completing their profile by filling out required details such
as bio, social links and other personal information. When setting up this
rule, you can define which fields must be completed to qualify for the reward.
[View more details](/loyalty/rules/complete-profile)
Reward users for referring friends with customizable fixed or percentage rewards.
[View more details](/loyalty/rules/refer-friends)
Reward users for checking in on a link of your choice.
[View more details](/loyalty/rules/check-in)
## Connect accounts rules
Reward users for connecting their email address.
[View more details](/loyalty/rules/connect-email)
Reward users for connecting their X (Twitter) account.
[View more details](/loyalty/rules/connect-twitter)
Reward users for connecting their Discord account.
[View more details](/loyalty/rules/connect-discord)
Reward users for connecting their Telegram account.
[View more details](/loyalty/rules/connect-telegram)
Reward users for connecting their Steam account.
[View more details](/loyalty/rules/connect-steam)
Reward users for connecting their Epic account.
[View more details](/loyalty/rules/connect-epic)
Reward users for connecting their wallet.
**Supported wallets:** EVM, Solana, IMX, SUI, and TON.
[View more details](/loyalty/rules/connect-wallet)
## Social quests
Reward users based on the number of their X (Twitter) followers.
[View more details](/loyalty/rules/x-followers)
Reward users for having a specific role in your Discord server.
**Set up steps:**
Invite the bot to your server using \[link] to enable role tracking.
Enter the Discord role ID or channel ID in the rule setup to track users with the specified role.
[View more details](/loyalty/rules/discord-member-role)
Reward users for sending messages in your Discord server.
[View more details](/loyalty/rules/discord-messages)
Reward users for joining your Telegram group.
[View more details](/loyalty/rules/telegram-join)
Reward users for sending messages in your Telegram group.
[View more details](/loyalty/rules/telegram-messages)
Reward users based on their Steam wishlist.
[View more details](/loyalty/rules/steam-wishlist)
Reward users for commenting on a YouTube video.
[View more details](/loyalty/rules/youtube-comment)
Reward users for subscribing to a YouTube channel.
[View more details](/loyalty/rules/youtube-subscriber)
Reward users for following a specific account on X (Twitter).
{' '}
Please contact a Snag admin to whitelist your domain for social verification.
[View more details](/loyalty/rules/follow-x-account)
Reward users for creating a new post on X (Twitter).
{' '}
Please contact a Snag admin to whitelist your domain for social verification.
[View more details](/loyalty/rules/x-post)
Reward users for creating a new post on X (Twitter) with a specific hashtag.
{' '}
Please contact a Snag admin to whitelist your domain for social verification.
[View more details](/loyalty/rules/x-new-tweet)
Reward users for adding specific text to their X (Twitter) bio.
{' '}
Please contact a Snag admin to whitelist your domain for social verification.
[View more details](/loyalty/rules/x-text-in-bio)
Reward users for adding specific text to their X (Twitter) comment.
{' '}
Please contact a Snag admin to whitelist your domain for social verification.
[View more details](/loyalty/rules/x-text-in-comment)
Reward users for adding specific text to their X (Twitter) username.
{' '}
Please contact a Snag admin to whitelist your domain for social verification.
[View more details](/loyalty/rules/x-text-in-username)
Reward users for reacting to a post on X (Twitter).
{' '}
Please contact a Snag admin to whitelist your domain for social verification.
[View more details](/loyalty/rules/x-post-reaction)
Reward users for reposting a post on X (Twitter). You can add a multiplier for verified X accounts.
This rule require X pro.
Reward users for liking a post on X (Twitter). You can add a multiplier for verified X accounts.
This rule require X pro.
Reward users for commenting on a post on X (Twitter).
This rule require X pro.
Reward users for getting a like on their X (Twitter) posts from your project.
This rule require X pro.
## Token activity rules
Reward users for minting a token.
[View more details](/loyalty/rules/token-mint)
Reward users for purchasing a token.
[View more details](/loyalty/rules/token-purchase)
Reward users for holding specific NFTs.
[View more details](/loyalty/rules/token-hold)
Reward users for selling a token.
[View more details](/loyalty/rules/token-sale)
Reward users for holding a specific amount of ERC-20 tokens.
[View more details](/loyalty/rules/token-hold-erc20)
## Smart contract rules
Reward users for interacting with a specific smart contract.
{' '}
Reach out to Snag to learn more about how this works.
This allows you to track events on any EVM smart contract & use that data to
create rules.
**Rule set up:**
* You provide your smart contract address, the chain/network on which it is deployed, and a full/partial ABI containing the event you want to track.
* This populates an event dropdown from which you can select the relevant event.
* You can add additional evaluation logic on the parameters emitted in the event (e.g. only reward if `sender` = "0x123…").
**Examples:**
* Tracking trading activity (e.g. rewarding users based on the number of trades).
* Token transfers (e.g. matching specific token ids or amounts).
* Tracking staking activities.
[View more details](/loyalty/rules/contract-event)
## Other rules
Reward users for submitting custom input requested by your project.
[View more details](/loyalty/rules/text-input)
Reward users for entering a specific code provided by your project.
[View more details](/loyalty/rules/code-entry)
Reward users for clicking on a link.
[View more details](/loyalty/rules/link-click)
Reward users for selecting the correct answer in a quiz.
[View more details](/loyalty/rules/quiz)
Reward users for answering a poll.
[View more details](/loyalty/rules/poll)
Reward users for participating in governance votes.
[View more details](/loyalty/rules/snapshot-governance)
Reward users for creating an account with your partner.
[View more details](/loyalty/rules/create-partner-account)
Manual point creation via API. Reward users for any other contribution with a
set amount of points via our POST `api/loyalty/transactions` endpoint.
[View more details](/loyalty/external-rules)
# Blocking users
Source: https://docs.snagsolutions.io/loyalty/blocking-users
The blocked users feature allows you to exclude specific wallet addresses from earning rewards through any loyalty rules. This is useful for blocking known bots, suspicious accounts or specific users.
## How it works
Blocked users will not be able to earn points from any rule, regardless of the trigger or reward conditions. You can manage blocked addresses by uploading a CSV file directly in the dashboard.
## Where to find it

1. Go to **Loyalty Program** in the sidebar.
2. On the **right-hand settings panel**, scroll down and click **Blocked users** (see highlighted area in the screenshot above).
## How to block wallets

Once inside the blocked users modal, follow these steps:
This will provide the structure needed to add wallet addresses. You can also download the current blocklist to review or edit previously submitted files.
# Create your first rule
Source: https://docs.snagsolutions.io/loyalty/create-your-first-rule
### Set up instructions
1. Go to admin dashboard: [https://admin.snagsolutions.io](https://admin.snagsolutions.io).
2. Go to the `Loyalty Program` tab (in the left-side navigation options).
3. Click `Add new rule` (this opens the rule creation menu).
4. Select a rule type (from the `Type` options). Based on the type selected, various form fields will render which allow you to configure the data source (if relevant), rule evaluation properties (e.g. which twitter account or smart contract to track) and the reward configuration.
5. Based on the type, fill in the rest of the parameters (for further help please contact us at [support@snagsolutions.io](support@snagsolutions.io)).
6. Click `Add` to create the rule (this will close the rule creation page and show you the rule that was just created (refresh the page if this does not appear immediately)).
### 🎉 Your first loyalty rule is now live!
# External rule
Source: https://docs.snagsolutions.io/loyalty/external-rules
This recipe explains the concept of an external rule, how to configure it with Snag and how to issue rewards to your users.
## What is an external loyalty rule?
You may wish to track user behaviour in contexts that Snag is unable to obtain a data source for (e.g. in a non-web/blockchain based game). For this and similar cases, Snag provides the concept of external rules.
An external rule is mostly the same as a standard loyalty rule and differs only in that it contains no built-in execution and evaluation logic.
Instead, this is done application-side (e.g. in-game) and, when a rewardable action is identified, Snag's [`POST /api/loyalty/rules/{id}/complete`](https://docs.snagsolutions.io/api-reference/loyalty/complete-loyalty-rule) endpoint can be hit.
This tells Snag that a given rule was completed by the given user(s) and issues the associated reward.
You can get more details on how to complete a rule in the [Submit and verify loyalty rule completion](/loyalty/verifying-rule-completion) recipe.
The id returned in the response will be used to complete the rule when a user performs the required action.
## Evaluating external rules
Unlike built-in rules, the evaluation of external rules happens within your own system. This means you must track the user behavior (e.g., game milestones or external API interactions) and determine when a rule is completed.
Once a rewardable action is identified, you can programmatically notify Snag by completing the external rule using the API (see next step).
## How to issue points for users who complete an external rule
To issue points for a user who completes an external rule, use the [`POST /api/loyalty/rules/{id}/complete`](https://docs.snagsolutions.io/api-reference/loyalty/complete-loyalty-rule) endpoint. This endpoint informs Snag that the rule has been satisfied for a specific user and triggers the reward.
You can get more details on how to complete a rule in the [Submit and verify loyalty rule completion](/loyalty/verifying-rule-completion) recipe.
Once the request is processed, Snag will issue the reward to the user based on the rule’s configuration.
## Summary Workflow
1. Create the External Rule: Use our admin dashboard to create the rule.
2. Track Behavior: Use your application to monitor user actions that meet the rule’s criteria.
3. Complete the Rule: When a user completes the action, submit the rule completion to Snag using the API, more details can be found in the [Submit and verify loyalty rule completion](/loyalty/verifying-rule-completion) recipe.
# Internal currency integration
Source: https://docs.snagsolutions.io/loyalty/internal-currency-integration
### Overview
If you have an existing loyalty system, or want to interact with an off-chain points system we allow partners to integrate existing loyalty points to be distributed as a part of the Snag Loyalty Program to be used as your all-in-one destination for points & points management moving forward.
### Configuration
In our self-serve dashboard we will ask for the following:
* Get balance URL
* Update balance URL
* API key
### Authentication
Please include API key authentication on your server. Allow us to pass in the API key as a header
```sql
# we will send the following header on all relevant requests
x-api-key: YOUR_API_KEY
```
### Get loyalty point balance
* This endpoint will be called many times from our frontend, please ensure it is performant
* If we query for a wallet address which is not present in your system then please either don't include that wallet in the response array or ensure the balance value is set to `0`.
* For multi-currency setups, please include separate account balance objects in the array for each currency, and map your currency to the loyaltyCurrencyId provided in the snag admin.
```jsx
GET
Query parameters:
{
walletAddress: string | string[], // case-insensitive
startingAfter?: string // optional, only if pagination is required.
}
// no pagination
Status code: 2**
Response body:
{
"data": [{
"id": string // optional, only if pagination is required
walletAddress: string
amount: string // important: amount must be a string
loyaltyCurrencyId: string
}],
hasNextPage: boolean // if pagination is required
}
```
### Update loyalty point balance
* This endpoint should process all updates transactionally (all succeed, or all fail), or return a 400 error.
* It is the APIs responsibility to balance check prior to executing the balance updates.
* For multi-currency setups please specify a separate path for each currency.
* Example: if one wallet has insufficient balance, then return a 400 and a proper error message. We will surface the error message to the frontend.
```jsx
POST
Body parameters:
{
entries: [
{
walletAddress: string // case-insensitive
direction: 'debit' | 'credit'
amount: string // important: amount must be string.
idempotencyKey: string | undefined // external client responsible for saving only once
metadata: Json | undefined
}
],
description: "description of event",
loyaltyRuleId: uuid | undefined
}
Response:
Success:
Status code: 2**
Failure:
Satus code: 4** or 5**
Response body:
{
message: string
}
```
### Get loyalty account history
* Returns the list of balance changes for a wallet address
* This endpoint will be called many times from our frontend, so make sure it is performant and can handle the load
```jsx
GET
Query parameters:
{
walletAddress: string, // case-insensitive
// If passed in then filter by this value
// return only the most recent per each rule.
userCompletedLoyaltyRuleId: string | string[],
// id from previous request, optional, if pagination is required.
startingAfter?: string
// number of elements to return
limit?: int
}
// sorted by createdAt desc
Status code: 2**
Response body:
{
"data": [{
"id": string // optional, only if pagination is required
walletAddress: string
direction: 'debit' | 'credit'
// we need this to determine if rule was completed
idempotencyKey: string | undefined
metadata: Json | undefined
loyaltyRuleId: string | undefined
amount: string // important: amount must be a string
loyaltyCurrencyId: string
description: string
createdAt: datetime
}],
hasNextPage: boolean // if pagination is required
}
```
### API Structure & Guidelines for Loyalty Rules
We expect specific standards for an API endpoint that our loyalty rules interact with (e.g. to get off-chain data from your system that somehow impacts rule evaluation and/or rewards).
### Configuration
For our system to be able to call your endpoint(s) during rule execution we ask for the following:
* Endpoint URL
* API key
* Standard pagination & sorting parameters
# Leaderboards
Source: https://docs.snagsolutions.io/loyalty/leaderboards
This recipe explains how to leverage the Snag API to fetch loyalty points balances for your users, which can be used to build features like a leaderboard in your application.
## Overview
The [`GET /api/loyalty/accounts`](https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-accounts) endpoint enables you to fetch loyalty points balances for your users, which can be used to build features like a leaderboard in your application. With sorting and pagination options, the endpoint allows you to manage large datasets and customize the display order, making it easy to highlight the top users based on their points. Below is an example and detailed instructions for constructing a leaderboard.
## Steps to Build a Leaderboard
### Fetching the data
The [`GET /api/loyalty/accounts`](https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-accounts) endpoint allows for fetching of loyalty points balances for your users.
This endpoints provides various filters to allow sorting, pagination and other filters.
* Note: if your loyalty program contains multiple loyalty currencies then use the `loyaltyCurrencyId` filter to query for the specific currency you wish to target.
### Sorting & pagination
The [`GET /api/loyalty/accounts`](https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-accounts) endpoint supports various query parameters that allow you to retrieve and manage data efficiently:
1. Sorting: Use the orderBy filter to sort users by their points. For example, setting orderBy\[amount]=desc ensures users with the highest point balances appear at the top of your leaderboard.
2. Pagination:
* The limit filter determines how many entries are fetched per request. The default value is 10, but it supports up to 1,000 entries per call.
* If your dataset contains more than the specified limit (e.g., over 1,000 users), the API response will include a hasNextPage boolean property. When this is true, you’ll need to fetch additional pages.
* To fetch the next set of data, take the id of the last entry in your previous result and pass it to the startingAfter query filter in your next request.
### Example Request
Request
```
{
"organizationId": "your-organization-id",
"websiteId": "your-website-id",
"loyaltyCurrencyId": "your-loyalty-currency-id",
"sortDir": "desc",
"limit": 1000
}
```
* Note: for paginated requests be sure to add the `startingAfter` property to subsequent requests.
### Example Response
```
{
"data": [
{
"id": "0abcd123-abcd-1234-5678-abcd12345678",
"userId": "01234abc-abcd-1234-5678-abcd12345678",
"loyaltyCurrencyId": "your-loyalty-currency-id",
"amount": "1500",
"lockVersion": "10",
"organizationId": "your-organization-id",
"websiteId": "your-website-id",
"createdAt": "2024-11-26T17:21:29.688Z",
"updatedAt": "2024-11-27T17:44:35.881Z",
"user": {
"id": "01234abc-abcd-1234-5678-abcd12345678",
"walletAddress": "0x1...abc",
"userMetadata": [
{
"walletGroupIdentifier": null,
"twitterUser": "user1",
"discordUser": "user1",
"logoUrl": "https://...png",
"displayName": "user1"
}
]
}
},
{
"id": "abcd1234-abcd-1234-5678-abcd12345678",
"userId": "abcd1234-abcd-1234-5678-abcd12345678",
"loyaltyCurrencyId": "your-loyalty-currency-id",
"amount": "1250",
"lockVersion": "10",
"organizationId": "your-organization-id",
"websiteId": "your-website-id",
"createdAt": "2024-11-26T17:21:29.688Z",
"updatedAt": "2024-11-27T17:44:35.881Z",
"user": {
"id": "abcd1234-abcd-1234-5678-abcd12345678",
"walletAddress": "0x2...abc",
"userMetadata": [
{
"walletGroupIdentifier": null,
"twitterUser": "user2",
"discordUser": "user2",
"logoUrl": "https://...png",
"displayName": "user2"
}
]
}
}],
"hasNextPage": "false"
}
```
### Example Usage
With the above data, you can construct a leaderboard that highlights your top users. The amount field provides the points total, while the userMetadata object contains user details like their display name, social media profiles, and profile picture. Displaying these details can make the leaderboard more engaging and personalized.
## Summary
By leveraging the /api/loyalty/accounts endpoint, you can create a dynamic points leaderboard for your application. Sorting and pagination options ensure scalability, even with large datasets, while additional user metadata allows you to create a rich and engaging user experience.
# Loyalty overview
Source: https://docs.snagsolutions.io/loyalty/loyalty-overview
This recipe is a quickstart guide to setting up your Snag Loyalty program, covering the loyalty currency configuration and initial rules set up.

## What is Snag loyalty?
Snag loyalty is a white-label loyalty solution which allows you to track, evaluate and reward user behaviour across on- and off-chain platforms (e.g. social media, holding tokens, custom smart contract interactions, etc).
This comes with an admin dashboard for configuration of your loyalty program, a REST API for integration with your existing system(s) and a no-code white-label Loyalty UI for your end users.
## Core concepts
* **Accounts:** A loyalty account represents one end-user identified by their wallet address.
* **Currencies:** A loyalty currency will be used to track loyalty points and rewards.
* **Rules:** A loyalty rule allows you to track a specific user behaviour and issue a reward in loyalty points.
* **Ledger:** The loyalty ledger is a chronological account of all loyalty points distribution and spending activity across your loyalty program.
## Admin dashboard
The admin dashboard is a web interface which allows for configuration of your loyalty program, management of loyalty rules and the end-user loyalty UI. We use wallet authentication for this dashboard and allow permissions to be issued to your team wallets (for collaborative management of your loyalty program).
* Access dashboard here: [https://admin.snagsolutions.io](https://admin.snagsolutions.io)
## Loyalty Program
To get started with your loyalty program, please contact us at [support@snagsolutions.io](mailto:support@snagsolutions.io).
# Loyalty Rule Progress Tracking
Source: https://docs.snagsolutions.io/loyalty/loyalty-rule-progress
Learn how to create external loyalty rules with progress tracking and multiple reward tiers
# Loyalty Rule Progress Tracking
External loyalty rules can be configured to track user progress and only allow completion when the progress reaches 100%. This feature enables you to create multi-step challenges or activities that users must complete incrementally.
## Overview
When you enable progress tracking on an external loyalty rule:
* Users can only claim the rule when their progress reaches 100%
* You can define multiple reward tiers at different progress levels
* Progress updates are submitted via the API
* The claim button only appears when progress is 100%
## Creating an External Rule with Progress Tracking
### Step 1: Enable Progress Tracking
When creating an external loyalty rule, you need to enable the **Track Progress** option:
1. Navigate to your loyalty rules section
2. Create a new external rule
3. Check the **Track Progress** checkbox
4. Configure your rule settings as needed
### Step 2: Configure Multiple Reward Tiers
With progress tracking enabled, you can define multiple reward ranges that trigger at different progress levels:
#### Reward Options
For each progress range, you can configure:
* **Points**: Award loyalty points at each milestone
* **Badges**: Enable the "Reward badge per range" toggle to award badges along with points
When "Reward badge per range" is enabled, users will receive both points and badges at each progress milestone they reach.
#### Example Reward Configuration
You can set up reward ranges like this:
* **10-10**: 20 points + badge (awarded at 10% progress)
* **20-20**: 20 points + badge (awarded at 20% progress)
* **50-90**: 20 points + badge (awarded when progress is between 50-90%)
* **100-100**: 20 points + badge (awarded at 100% progress)
This means users can earn up to 4 separate rewards (points + badges) as they progress through the activity.
## Updating User Progress
### API Integration
To update a user's progress, use the [Update Loyalty Rule Status](/api-reference/loyalty/update-loyalty-rule-status) endpoint:
[Update Loyalty Rule Status API Documentation](/api-reference/loyalty/update-loyalty-rule-status)
### Progress Values
* Progress values should be integers between 0-100
* When progress reaches 100%, the rule becomes claimable
* **Important**: Updating progress does not automatically reward users
* Users must go through the claim flow to receive rewards
## User Experience
### Progress Display
Users will see their current progress on the loyalty rule:
## Multiple Reward Tiers
### How Rewards Work
When you configure multiple progress ranges, users can earn rewards at different milestones:
1. **10% Progress**: First reward (20 points) - available for claim
2. **20% Progress**: Second reward (20 points) - available for claim
3. **50-90% Range**: Third reward (20 points) - available for claim when progress enters this range
4. **100% Progress**: Final reward (20 points) + rule completion - available for claim
**Note**: Progress updates only make rewards available for claiming. Users must actively claim their rewards through the [verification flow](/loyalty/verifying-rule-completion) to receive them.
### Best Practices
* **Clear Milestones**: Use round numbers (10, 25, 50, 75, 100) for better user understanding
* **Meaningful Rewards**: Ensure each milestone provides value to encourage continued participation
* **Progress Feedback**: Provide clear feedback when users reach new milestones
* **Range Planning**: Consider user behavior when setting ranges (e.g., 50-90 allows for flexible completion)
## Implementation Steps
1. **Create External Rule**: Use the admin interface to create an external loyalty rule with progress tracking enabled
2. **Update Progress**: Use the [Update Loyalty Rule Status API](/api-reference/loyalty/update-loyalty-rule-status) to update user progress as they complete activities
3. **Enable Claiming**: When progress reaches 100%, users can claim the rule through the [verification flow](/loyalty/verifying-rule-completion)
## Troubleshooting
### Common Issues
1. **Progress not updating**: Ensure you're using the correct `loyaltyRuleId`
2. **Rewards not triggering**: Check that your progress ranges are correctly configured
3. **Claim button not appearing**: Verify progress has reached exactly 100%
### API Response
The update endpoint returns the current rule status:
```json
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"websiteId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"organizationId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"loyaltyRuleId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"progress": 100,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z"
}
```
# Managing social accounts
Source: https://docs.snagsolutions.io/loyalty/managing-social-accounts
This recipe explains how to use Snag social integration API to let your users connect their social accounts to their Snag profile.
## Overview
This guide explains how to use Snag's social integration API to let your users connect their social accounts to their Snag profile. After creating a user in Snag (as explained in [Managing User Accounts](/loyalty/managing-user-accounts)), you can use the social authentication endpoints to connect various social platforms to that user's profile.
## Supported Social Platforms
Snag supports connecting the following social platforms:
* Twitter
* Discord
* Telegram
* Epic Games
* Steam
## Connecting a Social Account
### Endpoint
```web/apps/docs/loyalty/managing-social-accounts.mdx
GET /api/{authType}/auth
```
Where `{authType}` is one of: `twitter`, `discord`, `telegram`, `epic`, or `steam`.
### Query Parameters
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ----------------------------------------------------------------------------- |
| userId | UUID | Yes | The ID of the user received from the user creation endpoint |
| websiteId | UUID | No | The ID of the website (if applicable) |
| redirect | String | Yes | The URL where the user will be redirected after completing authentication |
| responseType | String | No | The type of response to return (`redirect` or `json`). Defaults to `redirect` |
### Example Request
```
GET /api/twitter/auth?userId=123e4567-e89b-12d3-a456-426614174001&redirect=https://your-app.com/auth-callback
```
### Authentication Flow
1. Call the `/api/{authType}/auth` endpoint with the required parameters
2. The API will return a URL that you should redirect your user to
3. The user will authenticate with the social platform and grant permissions
4. After successful authentication, the user will be redirected to the URL specified in the `redirect` parameter
5. The social account is now connected to the user's Snag profile
### Handling Social Account Conflicts
If the social account is already associated with a different user, the redirect URL will include two query parameters:
1. `error = 'MAXIMUM_ACCOUNT_LINKED'` - Indicates that the account is already linked to another user
2. `accountLinkData` - A JWT verification token that contains the necessary information to process the account transfer
In this case, you should:
1. Display a confirmation prompt to the user asking if they want to disconnect the account from the other user and link it to their current profile
2. If the user confirms, make a POST request to `/api/users/verify` with the following payload:
```json
{
"accountLinkData": "jwt_verification_token",
"userId": "current_user_id"
}
```
This will:
* Disconnect the social account from the previous user
* Connect it to the current user's profile
### Example Implementation with Conflict Handling
```javascript
// Server-side implementation (e.g., in Node.js/Express)
app.get('/auth-callback', async (req, res) => {
const { error, accountLinkData } = req.query
const userId = req.session.userId // Get from authenticated session
if (error === 'MAXIMUM_ACCOUNT_LINKED') {
// Render a confirmation page or return JSON response
return res.json({
requiresConfirmation: true,
accountLinkData,
})
}
// Handle successful connection
res.redirect('/profile')
})
// Handle confirmation
app.post('/confirm-account-transfer', async (req, res) => {
const { accountLinkData, userId } = req.body
try {
const response = await fetch(
'https://api.snagsolutions.io/api/users/verify',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.SNAG_API_KEY}`,
},
body: JSON.stringify({
accountLinkData,
userId,
}),
}
)
if (response.ok) {
res.redirect('/profile')
} else {
throw new Error('Failed to transfer account')
}
} catch (error) {
console.error('Error transferring account:', error)
res.status(500).send('Error transferring account')
}
})
```
### Example Implementation
```javascript
// Server-side implementation (e.g., in Node.js/Express)
app.get('/connect-twitter', async (req, res) => {
const userId = req.query.userId // Get from authenticated session
try {
const response = await fetch(
`https://api.snagsolutions.io/api/twitter/auth?userId=${userId}&redirect=https://your-app.com/auth-callback`,
{
headers: {
Authorization: `Bearer ${process.env.SNAG_API_KEY}`, // API key stored securely on server
},
}
)
const data = await response.json()
// Redirect the user to the authentication URL
res.redirect(data.url)
} catch (error) {
console.error('Error connecting Twitter account:', error)
res.status(500).send('Error connecting Twitter account')
}
})
// Client-side code to initiate the flow
function connectTwitterAccount(userId) {
// Redirect to your server endpoint
window.location.href = `/connect-twitter?userId=${userId}`
}
```
## Response Handling
### Success Response (200 OK)
```json
{
"url": "https://auth-provider.com/oauth/authorize?client_id=xxx&redirect_uri=xxx&state=xxx"
}
```
The `url` property contains the authentication URL that you should redirect your user to.
## Custom OAuth Applications
Snag allows you to use your own OAuth applications for **Twitter**, **Discord**, **Epic Games**, and **Steam** integrations. This enables you to maintain your brand identity throughout the authentication flow and have more control over the user experience.
If you would like to use your own client ID and client secret for any of these platforms, please contact the Snag team for integration support. We'll guide you through the process of setting up and configuring your custom OAuth applications with our system.
You will also need to add the following redirect URLs to your OAuth application:
* `https://snag-render.com/api/twitter/auth/callback`
* `https://snag-render.com/api/discord/auth/callback`
* `https://snag-render.com/api/epic/auth/callback`
* `https://snag-render.com/api/steam/auth/callback`
## Next Steps
After connecting social accounts, you can use this information to enhance the user experience in your application and leverage it for loyalty program features.
# Managing user accounts
Source: https://docs.snagsolutions.io/loyalty/managing-user-accounts
This recipe explains how to create or update user accounts via the Snag API.
## Overview
The [`POST /api/users/metadatas`](https://docs.snagsolutions.io/api-reference/identity/create-user-metadata) allows you to create or update user objects in Snag's system which can then be used to migrate users from your existing system. This also allows you to attach useful metadata to new and existing users, such as their social network handle, which can be used for a more seamless user experience in-app and for use in the loyalty program.
## Steps to create or update a user
### Example use-case
For the case where you are migrating your users from an existing system to Snag, you would loop over each of your users and, for each, hit the [`POST /api/users/metadatas`](https://docs.snagsolutions.io/api-reference/identity/create-user-metadata) endpoint with their wallet address and any metadata you wish to attach. Below is an example request which creates a user account for the given wallet address and attaches various social network handles.
### Example Request
```
{
"walletAddress": "0x1...",
"discordUser": "discord-user",
"twitterUser": "twitter-user",
"emailAddress": "email-address",
"telegramUsername": "telegram-user",
"displayName": "profile-name",
"logoUrl": "https://...png"
}
```
* Note: only the `walletAddress` property is required as this is the identifier for the user being created.
### Example Response
```
{
"id": "your-user-id",
"walletAddress": "0x1...",
"discordUser": "discord-user",
"twitterUser": "twitter-user",
"emailAddress": "email-address",
"telegramUsername": "telegram-user",
"displayName": "profile-name",
"logoUrl": "https://...png"
}
```
# Multi-wallet Support
Source: https://docs.snagsolutions.io/loyalty/multi-wallet-support
Connect multiple wallets to aggregate points, earnings, and holdings to enhance your loyalty experience.
## Overview
In blockchain-based loyalty programs, users often have multiple wallet addresses across different networks. Snag's multi-wallet support allows users to connect multiple wallets to a single user group, enabling:
* **Aggregated points display** - See combined point balances across all connected wallets
* **Group-based spending** - Spend points from the collective balance of all linked wallets
* **Pooled token holdings** - Combine NFT/token holdings for higher-tier multiplier qualification
* **Shared multiplier benefits** - Access the best multipliers earned by any wallet in the group
This feature creates a seamless experience for users with multiple wallets while maintaining individual tracking for each wallet address.
## How User Groups Work
### Points Aggregation
While Snag treats each wallet address as a separate user, connecting wallets through a user group enables points aggregation across all wallets in that group:
**Example:**
* User A has 100 points in their primary wallet
* User B has 300 points in their secondary wallet
* When connected in the same user group, both users will see a total of 400 points
### Shared Points Spending
All wallets in a user group share access to the combined point balance when redeeming rewards:
**Example:**
* User A (100 points) wants to redeem a reward costing 350 points
* Since User A's wallet is connected to User B's wallet (300 points) in a group
* User A can spend 350 points from the combined 400-point balance
* After redemption, the system intelligently deducts points from both wallets:
* User A's wallet: 0 points (depleted its 100 points)
* User B's wallet: 50 points (depleted 250 of its 300 points)
### Token Holdings Pooling for Multipliers
For multiplier rules based on token holdings, assets across all connected wallets are pooled to determine qualification level:
**Example:**
* A multiplier rule gives:
* 1.5x multiplier for holding 10-14 NFTs
* 2x multiplier for holding 15+ NFTs
* User A holds 10 NFTs and User B holds 5 NFTs
* When connected in the same group:
* Their combined holdings (15 NFTs) qualify for the 2x multiplier
* Both users receive the 2x multiplier benefit
**Important:** Token pooling only applies to multiplier-type rules, not to points-based token holding rules.
### Multiplier Selection Logic
When multiple wallets in a group earn different multipliers for the same rule type:
* The system selects the highest multiplier of each type
* Multipliers are not stacked within the same multiplier type
* Each multiplier type is counted once with the highest value available in the group
**Example:**
* User A has a 1.5x multiplier for completing Discord quests
* User B has a 2x multiplier for the same Discord quest type
* Both users will benefit from the 2x multiplier (the highest in the group)
## Setting Up Multi-wallet Support
### Technical Implementation
The multi-wallet functionality works through a `userGroupId` property in the user's account metadata, which connects different wallets to the same group.
### Enabling Multi-wallet Connections
To use multi-wallet functionality:
1. **Contact Support:** Multi-wallet support must be enabled by our team for your project
2. **Connection Limits:** Projects can be configured to allow:
* One additional wallet (total of 2 wallets in a group)
* Up to 3 additional wallets (total of 4 wallets in a group)
### User Experience
Once enabled, users can connect additional wallets to their account through the profile settings:
1. User signs in with their primary wallet
2. From the profile page, they select "Connect Additional Wallet"
3. User connects their additional wallet using standard wallet connection flow
4. The system verifies ownership and adds the wallet to the user group
5. Points and holdings are immediately aggregated across all wallets in the group
6. Each user in the group maintains their own User metadata that can be updated and tracked individually
## API Endpoints for Multi-wallet Support
### Updating User Metadata
Use the [`POST /api/users/metadatas`](https://docs.snagsolutions.io/api-reference/identity/create-user-metadata) endpoint to set or update user group connections. You can use either:
* `userGroupId` - Snag's internal identifier for the user group
* `userGroupExternalIdentifier` - Your custom external identifier for the group
Using `userGroupExternalIdentifier` allows you to maintain your own mapping between user groups and your external systems:
```json
{
"walletAddress": "0x123...",
"userGroupExternalIdentifier": "YOUR_SYSTEM_GROUP_ID_12345"
}
```
**Note:** When using `userGroupExternalIdentifier`, Snag will create a `userGroupId` internally and associate this external identifier with it. This allows you to reference user groups using your own identifiers in subsequent API calls.
### Fetching User Group Data
The [`GET /api/loyalty/accounts`](https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-accounts) endpoint allows you to fetch points balances and other data for all wallets in a group by providing either:
* `userGroupId` parameter for Snag's internal group ID
* `userGroupExternalIdentifier` parameter for your custom external identifier
## Best Practices
1. **Authenticate Wallet Ownership:** Always verify that a user owns all wallets they attempt to connect
2. **Clear User Communication:** Explain to users how points aggregation works across their connected wallets
3. **Visual Indicators:** Consider showing which wallet contributed what portion of the total points balance
## Limitations
* Maximum of 4 wallets per user group (your specific limit may be lower based on configuration)
* Token holding pooling only applies to multiplier rules, not to points-based token holding rules
* **Leaderboard Display:** Currently, leaderboards show each individual wallet as a separate entry.
# Multipliers
Source: https://docs.snagsolutions.io/loyalty/multipliers
## Overview
Multipliers are a powerful feature in the loyalty system that allow you to amplify the points users earn. Unlike standard point rewards that grant a fixed number of points, multipliers increase the value of all point-based rewards a user receives, creating opportunities for enhanced engagement and more valuable rewards.
## Multipliers vs. Points
The loyalty system supports two primary reward types:
* **Points**: A straightforward reward where users receive a specific number of points in the designated currency upon completing a rule.
* **Multipliers**: A reward that increases the value of all point-based rewards a user receives.

## How Multipliers Work
When a user completes a rule configured with a multiplier reward, they receive a multiplier value (e.g., 2x, 3x, 4x) that will be applied to their future point earnings. Multipliers effectively act as point amplifiers, allowing users to earn points at an accelerated rate.
### Example
If a user has a 3x multiplier and completes an action worth 10 points, they will receive 30 points (10 × 3) instead of the base 10 points.
### Retroactive Multiplier Application
The loyalty system includes a flag that allows multipliers to be applied retroactively to a user's existing point balance. When you activate this toggle, please note that the selected multiplier will be applied retroactively to the user's existing balance. This means that the multiplier will increase the current balance by the specified factor, effectively multiplying the user's total rewards from previous wins. Ensure that this retroactive adjustment is communicated clearly to users.
For example, if a user has 500 points and earns a 2x multiplier with retroactive application enabled, their balance would immediately increase to 1,000 points.

### Excluding Rules from Multiplier Effects
For certain point-based rules, you can enable the "Skip Multiplier" flag. When this flag is turned on, points earned from that specific rule will not be multiplied by the user's multiplier value. This allows you to create baseline rewards that are always awarded at their face value, regardless of a user's accumulated multipliers.

## Multiplier Balance Logic
Users can accumulate multiple multipliers from different rules. When a user has multiple multipliers, they stack according to a specific balance logic:
1. The first multiplier is applied at full value
2. Each additional multiplier is reduced by 1 before being added to the total
### Formula
Total Multiplier = First Multiplier + Sum of (Additional Multipliers - 1)
### Example
If a user has the following multipliers:
* Hold BAYC NFT: 4x
* Hold PENGU NFT: 3x
* Hold ETH: 3x
* Have Discord Role Moderator: 2x
The total multiplier would be calculated as:
* First multiplier (4x) + (3x - 1) + (3x - 1) + (2x - 1)
* 4x + 2x + 2x + 1x = 9x
This means all point rewards for this user would be multiplied by 9.
## Multipliers and User Groups
When users connect multiple wallets through a user group, the system applies special logic for handling multipliers across the group. This ensures that all wallets in the group benefit from the highest available multipliers while maintaining a balanced reward economy.
### Multiplier Selection in User Groups
For each loyalty rule type, the system will:
1. Identify all multipliers earned by wallets in the same user group
2. Select the highest multiplier value for each rule type
3. Apply this highest multiplier to all wallets in the group
### Example
Consider a user group with two connected wallets:
* **Wallet A** has earned:
* 3x multiplier for holding BAYC NFT
* 2x multiplier for Discord role "Moderator"
* 1.5x multiplier for completing daily quests
* **Wallet B** has earned:
* 4x multiplier for holding BAYC NFT
* 1.5x multiplier for Discord role "Moderator"
* 2x multiplier for completing daily quests
The system will select the highest multiplier for each rule type:
* BAYC NFT holding: 4x (from Wallet B)
* Discord role "Moderator": 2x (from Wallet A)
* Daily quests: 2x (from Wallet B)
Both Wallet A and Wallet B will benefit from these highest multipliers, effectively:
* Both wallets get 4x multiplier for BAYC NFT holdings
* Both wallets get 2x multiplier for Discord role "Moderator"
* Both wallets get 2x multiplier for daily quests
Using the multiplier balance logic formula (First Multiplier + Sum of (Additional Multipliers - 1)):
* First multiplier (4x) + (2x - 1) + (2x - 1)
* 4x + 1x + 1x = 6x total multiplier
This means all point rewards for both wallets in the group would be multiplied by 6, unless the "Skip Multiplier" flag is enabled for specific rules.
### Important Notes
1. **No Stacking Within Groups**: Multipliers from different wallets in the same group do not stack. Only the highest multiplier for each rule type is applied.
2. **Individual Multiplier Tracking**: While the highest multiplier is applied to all wallets in the group, the system still tracks individual multiplier achievements for each wallet.
3. **Group Benefits**: This system ensures that all wallets in a group benefit from the best multipliers earned by any member, creating an incentive for users to maintain their connections within the group.
## Setting Up Multiplier Rewards
When creating a loyalty rule, you can select "Multiplier" as the reward type instead of "Points." You'll then need to specify the multiplier value (e.g., 2x, 3x, 4x) that users will receive upon completing the rule.
### Currency Selection for Multipliers

The loyalty system allows you to specify which currencies your multipliers will affect. Using a dropdown menu, you can select one or more currencies to which the multiplier will be applied. This gives you fine-grained control over your reward economy, as rules can be configured to reward points in different currencies, and multipliers can be targeted to specific currencies.
For example, you might create a multiplier that only applies to your "Premium Points" currency but not to your "Standard Points" currency, allowing for strategic differentiation in how users can accelerate their earnings across different point types.
### Rule Type Limitations
Note that multiplier rewards are not supported for all rule types. Specifically:
* Referral rules
* Smart contract event rules
These rule types only support point-based rewards.
## Strategic Uses for Multipliers
Multipliers can be strategically implemented to:
1. **Reward high-value actions**: Assign higher multipliers to actions that are more valuable to your platform
2. **Encourage collection ownership**: Reward users who hold specific NFTs or tokens with multipliers
3. **Create tiered loyalty systems**: Design a system where users can progressively increase their earning potential
4. **Drive engagement with key features**: Incentivize users to engage with important platform features
## Strategic Considerations
* Use multipliers sparingly for high-value actions to maintain their perceived value
* Clearly communicate to users how multipliers work and how they stack
* Balance your multiplier values to ensure the reward economy remains sustainable
## Direct Multiplier Rewards via API
In addition to rule-based multiplier rewards, you can also directly assign multipliers to specific users through the Create Loyalty Multiplier API. This allows for programmatic control over multiplier distribution from your own server, enabling custom reward logic or manual multiplier assignments.
To implement direct multiplier rewards, use the API endpoint documented at [Multiplier API Reference](/api-reference/loyalty/create-loyalty-multiplier).
This approach is particularly useful for:
* Custom reward campaigns not covered by standard rules
* Manual multiplier adjustments for specific users
* Integration with external systems or events
* Bulk multiplier assignments based on your own business logic
# Snag template app
Source: https://docs.snagsolutions.io/loyalty/nextjs-template
A production-ready Next.js + Tailwind Web3 starter template with loyalty program and user profiles designed for Web3 projects
Whether you're building a community rewards program, a gated Web3 experience, or a gamified platform, this template will get you up and running fast — fully integrated with the **Snag Solutions SDK**.
The starter kit is built with:
* **Next.js (App Router)** for modern, file-based routing
* **Tailwind CSS** for rapid styling
* **Snag Solutions SDK** for plug-and-play Web3 features
## What’s Included
This template showcases a simple Web3 application with:
* **Web3 Authentication** (wallet-based login)
* **Loyalty Program & Leaderboard**
* **User Profile Page** with wallet info and loyalty point history
## Getting Started
### Prerequisites
Before you start, make sure you have:
* [Node.js](https://nodejs.org/)
* [PNPM](https://pnpm.io/)
### Installation
Clone this repository and install the dependencies:
```bash
pnpm install
```
### Environment Setup
Create a `.env` file in the project root with the following variables:
```env
NEXT_PUBLIC_API_KEY=your_api_key
NEXT_PUBLIC_WEBSITE_ID=your_website_uuid
NEXT_PUBLIC_ORGANIZATION_ID=your_organization_uuid
LOYALTY_CURRENCY_ID=your_loyalty_currency_id
ENABLE_TWITTER_RULES=boolean # Optional
ENABLE_TELEGRAM_RULES=boolean # Optional
RULES_COLLECTIONS='[{"address":"0x123","network":"mainnet"}]' # Optional
```
You can find or generate your API key and UUIDs via the [**Admin Dashboard**](https://admin.snagsolutions.io).
## Development
To start the development server:
```bash
pnpm dev
```
Visit [http://localhost:3000](http://localhost:3000) to see the app in action.
## Setup Scripts
### Add Initial Loyalty Rules
This sets up a base rule set for your website:
```bash
pnpm rules:create
```
> Tip: Make sure your loyalty currency is created first.
### Remove All Loyalty Rules
To clear all existing rules:
```bash
pnpm rules:remove
```
## Fork This Template
Want to create your own version of this template?
➡️ Fork it here: [Next.js Template App](https://github.com/Snag-Solutions/nextjs-template)
Then follow the [Getting Started](#getting-started) section above.
## Project Structure
```bash
.
├── app/ # App Router pages
├── components/ # Reusable UI components
├── lib/ # Utility functions and SDK integrations
├── public/ # Static assets
├── scripts/ # Loyalty setup/teardown scripts
└── .env.example # Environment variable template
```
## Related Docs
* [Next.js App Router Docs](https://nextjs.org/docs/app/building-your-application/routing)
* [Tailwind CSS Docs](https://tailwindcss.com/docs)
# Program settings
Source: https://docs.snagsolutions.io/loyalty/program-settings
The Loyalty Builder tab in Snag’s admin tool allows you to customize your loyalty program page, manage currencies and balances and configure advanced leaderboard settings. Use this tool to tailor your loyalty experience and drive deeper engagement with your community.
This page contains three sections:
1. **Page Settings** - Customize the look and feel of your loyalty program.
2. **Currencies & Balances** - Manage loyalty program currencies and user balances.
3. **Advanced Settings** - Configure leaderboards and visibility options.
## Page Settings
This section lets you customize how your loyalty program appears to users.

* **Page Title & Description** - Set a name and short description for your loyalty program.
* **Page Background** - Upload a banner image to personalize the page.
* **Enable Loyalty First View** - Toggle this on to make the loyalty program the default landing page instead of the marketplace.
***
## Currencies & Balances
Manage the different currencies used in your loyalty program.

* **Add a New Currency** - Define custom reward types. You can hide, reorder, or remove currencies at any time.
* **Set Currency Symbols** - Assign unique identifiers for each currency.
* **Show in Header** - Choose up to 3 currencies to display at the top of your platform, appearing across all pages.
* **Reorder Currencies** - The top currency in the list is the primary leaderboard metric.
* **Update User Balances** - Manually adjust point distributions for individual users by uploading a CSV file.
Learn more in [Updating Balances](/loyalty/available-loyalty-rules).
***
## Advanced Settings
Expand your loyalty program with additional customization and control options.

* **Hide Social Links** - Toggle this to remove users' social links from the leaderboard page.
* **Leaderboard Views** - Create multiple leaderboard variations with custom filters.
* **Conditions** - Define rules for leaderboard inclusion.
# Rules configuration
Source: https://docs.snagsolutions.io/loyalty/rules-configuration
These fields are common across all loyalty rules and define the general properties of a rule.

## Basic Details
* **Name & description**: Enter a unique name and a brief description for the rule.
* **Section**: Select where this rule will appear on the loyalty page.
* **Start & end time**: Select when the rule becomes active. It won't be shown before the start time. The end time is optional - if set, the rule will expire and disappear automatically.
* **Required rule**: Enable this to make the rule mandatory to complete before any other non-required rules can be completed.
* **Hide from UI**: Enable this to hide the rule from the loyalty page. Useful for background rewards or API-triggered flows.
## Contract Address Section
Only shown for rules that require it. Otherwise, these fields won’t appear.
* **Contract address**: Enter the smart contract address relevant to the rule you're creating, such as a token contract, collection contract or a contract tied to a specific event.
* **Network**: Select the blockchain network where the contract is deployed.
## Reward Section
### Type of Reward
Choose between Points or Multiplier as the reward mechanism for this rule.
1. **Reward**: Grants a fixed number of points when the rule is completed.
* **Points to reward**: Enter the amount and type of points the user will earn upon completing the rule.
2. **Multiplier Reward**: Multiply all future rewards the user earns from other rules.
* **Multiplier**: Enter the multiplier value applied to future rewards. This value must be greater than 1.
* **Currencies to apply**: Select which point types the multiplier will affect.
* **Apply multiplier to user’s existing balance**: Enable this to retroactively increase the user’s existing point balance based on the set multiplier.
* **Update cadence**: Select how often we’ll validate user completion and update their balance.
* Immediately: Completion is checked as soon as the user performs the action (e.g. answering a quiz, clicking a link).
* Daily / Weekly / Monthly: Completion is checked at the end of each period and balances are updated if completed (e.g. Twitter follower rules).
* Note: Some rules have default cadences that can't be changed due to their logic.
* **User reward frequency**: Select how often a user can receive this reward.
* One time: The rule will disappear after the user completes it once.
* Daily / Weekly / Monthly: Users can complete the rule again in the next period.
* Daily resets at midnight UTC.
* Weekly resets at midnight on Monday.
* Monthly resets at midnight on the 1st of the month.
* Note: Some rules have default frequencies that can't be changed due to their logic.
## Custom Settings Section
Appears only for rules that require specific configurations. This section includes unique settings tailored to the rule type.
# Check-in
Source: https://docs.snagsolutions.io/loyalty/rules/check-in
## **Overview**
The "Check-in" loyalty rule allows admins to reward users for regularly engaging with the platform. Users earn rewards simply by visiting or interacting with the site on a scheduled basis. This rule supports streak-based rewards, which incentivizes consistent user engagement by providing increased rewards for consecutive check-ins.
## **Rule Configuration Fields**
### **Basic Settings**
* **Points to rward**: Define the number of points users receive for each check-in.
* **User reward frequency**: Determine how often users can check in and receive rewards (Daily, Weekly, Monthly).
* **Update Cadence**: The Check-in rule rewards users **immediately** upon completion of a valid check-in. This instant gratification helps drive continued engagement with the platform.
### **Custom Setting**
* **Count any rule completion as check-in**: Toggle to count any rule completion as a check-in.
* **Enable streak**: Toggle to activate streak-based reward multipliers.
* **Reward only streak completions**: If both of the above are enabled, and amount is set to 0, this setting will reward users only for completing the full streak. **Note**: This means the check-in rule will not appear on the frontend.
* **Streak Milestone**: Define specific numbers of consecutive days of check-ins for enhanced rewards.
* **Points per streak**: Specify the increased reward amounts for achieving each defined streak threshold.
* **Asset Selection**: Choose between an image or video that will be displayed as a modal when users successfully check in.
* **Image Option**: Upload an image file that will appear in the success modal.
* **Video Option**: Upload a video file that will play automatically in the success modal.
* **Visual Feedback**: The selected asset creates a visual reward that enhances the check-in experience, providing immediate confirmation of successful check-in completion.
# Code Entry
Source: https://docs.snagsolutions.io/loyalty/rules/code-entry
## **Overview**
The "Code Entry" loyalty rule allows admins to reward users based on
the entry of a specific code. This rule is useful for rewarding users for joining certain community events e.g twitter spaces.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Code Entry rule rewards users **immediately** upon successful entry of the code.
* **User Reward Frequency**: This is a one-time reward that users can claim after linking their accounts, helping to build a connected community across platforms.
### **Custom Settings**
* Skip the multiplier for this rule
* **Link**: Provide a URL for users to take further action.
* **Platform**: This lets you choose from specific list of platforms of which icon will be shown in the rule card for better user experience.
* available platforms:
* discord
* epic games
* instagram
* steam
* telegram
* tiktok
* twitch
* twitter/X
* youtube
* **Promo Code**: Define the promo code that users need to enter to earn the reward.
**Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# Complete Profile
Source: https://docs.snagsolutions.io/loyalty/rules/complete-profile
## Overview
The "Complete Profile" loyalty rule allows admins to reward users for completing their profile. This rule is useful for getting more engagement on the platform.
## Prerequisites
* The user must have completed their profile, which includes:
* A bio
* A profile picture
* A Twitter handle
* An email address
* A Discord handle
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: The Complete Profile rule rewards users **immediately** upon completion of the profile.
* **User Reward Frequency**: This is a one-time reward that users can claim after completing the profile.
### **Custom Settings**
* Skip the multiplier for this rule
# Connect Discord
Source: https://docs.snagsolutions.io/loyalty/rules/connect-discord
## **Overview**
The "Connect Discord" loyalty rule allows admins to reward users for connecting their Discord accounts to the platform. This rule encourages users to join the community Discord server and link their accounts, enabling better community engagement and cross-platform interaction.
## Prerequisites
* The user must have connected their Discord account to Snag.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Connect Discord rule rewards users **immediately** upon successful connection of their Discord account and fulfillment of any required conditions (like joining a specific server).
* **User Reward Frequency**: This is a one-time reward that users can claim after linking their accounts, helping to build a connected community across platforms.
### **Custom Settings**
* Skip the multiplier for this rule
In order to enable following configuration you must invite our bot to the server with read member permission.
Here is the [invite link](https://discord.com/oauth2/authorize?client_id=1079691446724075562\&permissions=8\&response_type=code\&redirect_uri=https://admin.snagsolutions.io/\&scope=bot+guilds.members.read)
* **Add Discord Guild user should follow to earn this reward**: Toggle to add a Discord guild/server that users should join to earn this reward.
* **Discord Server ID**: Enter the ID of your community's Discord server that users should join.
# Connect email
Source: https://docs.snagsolutions.io/loyalty/rules/connect-email
## **Overview**
The "Connect Email" loyalty rule allows admins to reward users for connecting their Email accounts to the platform. This rule encourages users to link their accounts, enabling better community engagement and cross-platform interaction.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Connect Email rule rewards users **immediately** upon successful connection of their Email account.
* **User Reward Frequency**: This is a one-time reward that users can claim after linking their accounts, helping to build a connected community across platforms.
### **Custom Settings**
* Skip the multiplier for this rule
# Connect Epic Games
Source: https://docs.snagsolutions.io/loyalty/rules/connect-epic
## **Overview**
The "Connect Epic Games" loyalty rule allows admins to reward users for connecting their Epic Games accounts to the platform. This rule encourages users to link their accounts, enabling better community engagement and cross-platform interaction.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Connect Epic Games rule rewards users **immediately** upon successful connection of their Epic Games account.
* **User Reward Frequency**: This is a one-time reward that users can claim after linking their accounts, helping to build a connected community across platforms.
### **Custom Settings**
* Skip the multiplier for this rule
**Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# Connect Steam
Source: https://docs.snagsolutions.io/loyalty/rules/connect-steam
## **Overview**
The "Connect Steam" loyalty rule allows admins to reward users for connecting their Steam accounts to the platform. This rule encourages users to link their accounts, enabling better community engagement and cross-platform interaction.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Connect Steam rule rewards users **immediately** upon successful connection of their Steam account.
* **User Reward Frequency**: This is a one-time reward that users can claim after linking their accounts, helping to build a connected community across platforms.
### **Custom Settings**
* Skip the multiplier for this rule
# Connect Telegram
Source: https://docs.snagsolutions.io/loyalty/rules/connect-telegram
## **Overview**
The "Connect Telegram" loyalty rule allows admins to reward users for connecting their Telegram accounts to the platform. This rule encourages users to link their accounts, enabling better community engagement and cross-platform interaction.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Connect Telegram rule rewards users **immediately** upon successful connection of their Telegram account.
* **User Reward Frequency**: This is a one-time reward that users can claim after linking their accounts, helping to build a connected community across platforms.
### **Custom Settings**
* Skip the multiplier for this rule
# Connect X
Source: https://docs.snagsolutions.io/loyalty/rules/connect-twitter
## **Overview**
The "Connect Twitter" loyalty rule allows admins to reward users for connecting their Twitter accounts to the platform. This rule encourages users to link their accounts, enabling better community engagement and cross-platform interaction.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Connect Twitter rule rewards users **immediately** upon successful connection of their Twitter account.
* **User Reward Frequency**: This is a one-time reward that users can claim after linking their accounts, helping to build a connected community across platforms.
### **Custom Settings**
* Skip the multiplier for this rule
# Connect wallet
Source: https://docs.snagsolutions.io/loyalty/rules/connect-wallet
## **Overview**
The "Connect Wallet" loyalty rule allows admins to reward users for connecting their Crypto Wallet to the platform..
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Connect Wallet rule rewards users **immediately** upon successful linking of their crypto wallet.
* **User Reward Frequency**: This is a one-time reward that users can claim after linking their accounts, helping to build a connected community across platforms.
### **Custom Settings**
* Skip the multiplier for this rule
* **Wallet Type**: Choose the type of wallet to connect to.
**Supported wallets:** EVM, Solana, IMX, SUI, and TON.
# Contract Event
Source: https://docs.snagsolutions.io/loyalty/rules/contract-event
## **Overview**
The "Contract Event" loyalty rule allows admins to reward users based on
specific events occurring on a contract. This rule is useful for rewarding
users for specific contract interactions, such as token transfers or
transactions.
## Contract Address
Users must select a contract from the available list, or add a new contract. This contract defines where the event will be monitored.
### Recommended Rules
Users can choose from pre-configured rule templates that will show upon selection of contract, such as:
* **Reward User for Every ERC20 Transfer Received**: Grants a reward whenever a user receives any ERC20 tokens.
* **Reward User for Large ERC20 Transfer Received**: Rewards the user only if the received amount exceeds a set threshold (e.g., 1000 tokens).
## Event Selection
User will be able to see the list of all the events of the selected contract to choose from.
### Criteria
* **Every Event**: The rule applies to all occurrences of the event.
* **By Parameter**: The rule only applies when specific conditions are met.
## User Address Mapping
This lets you define a mapping of the wallet address field that should be chosen for the reward. Examples include sender, recipient, or values derived from event parameters.
## Parameter Selection
Users can define specific conditions to filter events. Each condition consists of:
* **Parameter**: The relevant field in the event (e.g., `spender`).
* **Condition**: The logic applied to the parameter (e.g., `Equal`).
* **Value**: The specific value to match (e.g., a specific wallet address like `0xd8dA6BF26964aF9D7c`).
Multiple parameters can be added, and they will be combined with an AND logic.
## Event Tracking Duration
Users can set a custom date range to track the event by enabling the toggle. The selected range determines when the event monitoring begins and ends.
## Reward Configuration
Users can define the reward granted when the event occurs.
### Points to Reward
* The user can specify the reward amount (e.g., Xp1 tokens).
* **Set Maximum**: Enables an upper limit on the number of rewards a user can earn.
* **Bonus Reward**: Optionally enables extra rewards beyond the base amount.
### Event Count & Points
Users can configure:
* **Event Count**: The number of occurrences required to trigger the reward.
* **Points to Reward**: The reward per event occurrence.
## User Reward Frequency
Determines how often a user can receive the reward. Options include:
* **One-time**: The user receives the reward only once per rule configuration.
* **Daily**: The user can receive the reward once per day.
* **Weekly**: The user can receive the reward once per week.
* **Monthly**: The user can receive the reward once per month.
## Custom Settings
Users have additional options:
* **Skip the Multiplier for this Rule**: Ignores any external multipliers affecting rewards.
* **Only Check for Known Users**: Limits rewards to users that are already present and signed into the loyalty program.
## Call to Action (Optional)
Users can define a call-to-action link with custom button text (e.g., "Browse Items").
# Create Partner Account
Source: https://docs.snagsolutions.io/loyalty/rules/create-partner-account
## **Overview**
The "Create Partner Account" loyalty rule allows admins to reward users if they create an account on a partner platform.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Create Partner Account rule rewards users **immediately** upon successful completion of the partner account creation.
* **User Reward Frequency**: This is a one-time reward that users can claim after completing the partner account creation.
### **Custom Settings**
* **Link**: This lets you define the link to the partner platform.
* **Button Text**: This lets you define the button text to the partner platform.
* Skip the multiplier for this rule
# Get Discord Role
Source: https://docs.snagsolutions.io/loyalty/rules/discord-member-role
## Overview
The "Discord Member Role" loyalty rule allows admins to reward users for having a certain role in their Discord server. This rule is useful for encouraging users to join a specific Discord server and engage with the platform.
## Prerequisites
* Snag Discord bot must be added to the Discord server with the following permissions:
* View Audit Log
* Read Message History
* [Invite Link](https://discord.com/oauth2/authorize?client_id=1105803835173245028\&permissions=8\&response_type=code\&redirect_uri=https://admin.snagsolutions.io/\&scope=bot+guilds.members.read)
* The user must have connected their Discord account to Snag.
* The user must have any one of the defined roles in the Discord server.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: This defines that the rule will run daily/weekly/monthly at the defined start time and check if the users in the system have the defined role in the Discord server, This rule can also be claimed from the UI by clicking on the **"Claim" button** by the users.
* **User Reward Frequency**: This is a one-time reward that users can claim after linking their accounts, helping to build a connected community across platforms.
### **Custom Settings**
* Skip the multiplier for this rule
* **Discord Server Id**: The ID of the Discord server where the rule will be applied.
* **Discord Role Id**: The ID of the role that will be rewarded to the users. You can define multiple role ids and user will be rewarded if they have any of the roles.
# Send Discord messages
Source: https://docs.snagsolutions.io/loyalty/rules/discord-messages
## Overview
The "Discord Messages" loyalty rule allows admins to reward users for sending messages in their Discord server. This rule rewards discord messages based on a specific emoji response, normally from a moderator, or a specific string of text included by the user. This rule is useful for encouraging users to be more engaged in the Discord server.
## Prerequisites
* Snag Discord bot must be added to the Discord server with the following permissions:
* Read Messages
* Read Message History
* Read Message Content
* [Invite Link](https://discord.com/oauth2/authorize?client_id=1105803835173245028\&permissions=8\&response_type=code\&redirect_uri=https://admin.snagsolutions.io/\&scope=bot+guilds.members.read)
* The user must have connected their Discord account to Snag.
* The user must have message in defined channel with either specific emoji or text.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will receive the defined number of points based on their activity or achievement.
* **Multiplier**: Users will receive the multiplier of the defined range based on their qualification level.
* **Required Range**: Define a numerical range for eligibility (tokens, actions, followers, messages count, etc.).
* **Points to Reward**: Define the number of points assigned for the specified qualification range.
* **Add New Range**: Allows defining multiple qualification ranges with corresponding rewards.
### Basic Settings
* **Update Cadence**: This defines that the rule will run daily/weekly/monthly at the defined start time and check if the users has sent the defined number of messages in the Discord server which also includes the specific text or reaction, This rule can also be claimed from the UI by clicking on the **"Claim" button** by the users.
* **User Reward Frequency**: This defines how often the users can claim the reward, available options are **"One-time"**, **"Daily"**, **"Weekly"**, **"Monthly"** and **"Every Message"**. For **"Every Message"** option, the users will be rewarded for every message they send in the Discord server channel. Daily/Weekly/Monthly options will reward the users to claim the reward daily/weekly/monthly, this can encourage users to be more active in the Discord server.
### **Custom Settings**
* Skip the multiplier for this rule
* **Discord Channel Id**: The ID of the Discord channel where the rule will be applied.
**Message will be counted in the reward range if any of the following is true**:
* **Text**: The text that should be included in the message to be included in the reward range.
* **Emoji**: This defines that user must have on their message a specific emoji reaction, either from a moderator or a user. You can either add the emoji id or the name of the emoji. You can define multiple emojis and message will be counted if any of the emojis are present in the message.
# Follow X Account
Source: https://docs.snagsolutions.io/loyalty/rules/follow-x-account
## Overview
The "Follow X Account" loyalty rule allows admins to reward users for following a specific X account. This rule is useful for encouraging users to follow a specific X account.
## Prerequisites
* This rule is not enabled by default. You need to contact support to enable it.
[Contact Support](https://snagsolutions.io/contact)
* The user must have connected their X account to Snag.
* The user must follow the defined X account and submit the claim.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: Points for this rule will be rewarded immediately on user claim after they follow the defined X account.
* **User Reward Frequency**: This defines how often the user will be rewarded. You can choose between one time, daily, weekly, or monthly.
### **Custom Settings**
* **X Account URL**: This is the URL of the X account that the user will follow.
* Skip the multiplier for this rule
**Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# Link Click
Source: https://docs.snagsolutions.io/loyalty/rules/link-click
## **Overview**
The "Link Click" loyalty rule allows admins to reward users based on
the click of a specific link. This rule is useful for redirecting users to new launch or specific pages.
## **Rule Configuration Fields**
### **Reward**
* **Points**: Users will get the defined no of points.
### **Basic Settings**
* **Update Cadence**: The Link Click rule rewards users **immediately** upon successful click of the link.
* **User Reward Frequency**: This defines how often the user can earn the reward, e.g. daily, weekly, monthly, etc. If set to daily, the user can earn the reward once per day based on UTC time.
### **Custom Settings**
* **Verification Placeholder**: This placeholder text appears inside the input field to guide users on what to type.
* **Minimum verification text length**: Specify the number of characters that must be entered in the verification text.
* Skip the multiplier for this rule
* **Link**: Provide a URL for users to take further action.
* **Platform**: This lets you choose from specific list of platforms of which icon will be shown in the rule card for better user experience.
* available platforms:
* discord
* epic games
* instagram
* steam
* telegram
* tiktok
* twitch
* twitter/X
* youtube
* \*\*Time delay to verify \*\*: The time in seconds we'll wait before rewarding users for clicking the link to encourage completion of the flow.
**Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
## **Implementation Considerations for API-Based Partners**
The Link Click rule is designed for direct user interactions through the Snag platform's UI. For API-based partners, please note:
1. **No Click Verification**:
* The system does not verify if users actually clicked the provided link
* Rewards are granted when the completion is called, regardless of whether the link was clicked
2. **Implementation Note**:
* While the rule is named "Link Click", it functions more as a completion-based reward
* You can use this rule to reward users for any action that triggers the completion, not necessarily a link click
# Poll
Source: https://docs.snagsolutions.io/loyalty/rules/poll
This recipe explains the concept of a poll rule, how to configure it with Snag and how to issue rewards to your users.
## **Overview**
The "Poll" loyalty rule allows admins to reward users based on the completion of a poll.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Poll rule rewards users **immediately** upon successful completion of the poll.
* **User Reward Frequency**: This is a one-time reward that users can claim after completing the poll.
### **Custom Settings**
* Skip the multiplier for this rule
* **Question**: This lets you define the poll question.
* **Answers**: This lets you define the poll answers.
# Quiz
Source: https://docs.snagsolutions.io/loyalty/rules/quiz
This recipe explains the concept of a quiz rule, how to configure it with Snag and how to issue rewards to your users.
## **Overview**
The "Quiz" loyalty rule allows admins to reward users based on the completion of a quiz.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Quiz rule rewards users **immediately** upon successful completion of the quiz.
* **User Reward Frequency**: This is a one-time reward that users can claim after completing the quiz.
### **Custom Settings**
* Skip the multiplier for this rule
* **Question**: This is the question that will be asked to the user.
* **Answers**: This is the list of options that will be shown to the user.
* **Correct Answer**: This checkbox lets you define the correct answer to the question.
* **Allow multiple attempts**: This is a boolean that allows the user to attempt the quiz multiple times.
# Refer a friend
Source: https://docs.snagsolutions.io/loyalty/rules/refer-friends
## **Overview**
This rule rewards users for referring others, with multiple reward structures supporting first-level and second-level referrals.
An admin sets up a referral program where User X gets 1000 points for each new referral, and new users (User Y) get 500 points upon joining. Additionally, User X earns 10% of User Y’s earnings and 5% of User Z’s earnings. This rule is checked daily, ensuring that referrers continue to earn from their referrals' activity over time.
## **Rule Configuration Fields**
* **Referral Reward Amount for Referrer**: When User X refers to User Y, User X gets rewarded..
* **Points Rewarded to New User**: When User X refers to User Y, User Y gets an initial reward.
* **Percentage Points to Reward for First Referral**: When User X refers to User Y, User X can earn a percentage of Y’s earnings based on cadence (daily/weekly/monthly).
* **Percentage Points to Reward for Second Referral**: When User X refers to User Y, and Y refers to User Z, both X and Y can earn a percentage of Z’s earnings.
### **Update Cadence**
The Update Cadence field is crucial as it defines:
* **Reward Frequency**: This is only applicable to percentage based rewards, this determines how often the user will receive rewards (e.g., Daily, Weekly, Monthly).
* **Relation to Start Time**: The first verification of all the referrals and reward distribution will begin at the defined Start Time. Subsequent verifications and rewards will follow the selected cadence (e.g., if the cadence is set to "Daily," the system will check and reward holdings every 24 hours from the Start Time).
### **Custom Settings**
Users qualify for referral rewards based on conditions such as achieving points, completing profile details, or connecting social accounts.
# Snapshot Governance
Source: https://docs.snagsolutions.io/loyalty/rules/snapshot-governance
## **Overview**
The "Snapshot Governance" loyalty rule allows admins to reward users based on their participation in Snapshot governance [https://snapshot.box/](https://snapshot.box/).
This rule is useful for rewarding users for voting on proposals or participating in governance activities.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: This defines that the rule will run daily/weekly/monthly at the defined start time and check if the users in the system have voted on the proposal.
* **User Reward Frequency**: This is a one-time reward that users will be rewarded once they have voted on a proposal at the specified start time.
### **Custom Settings**
* **Snapshot Space Name**: The name of the snapshot space to check for governance activities.
* **Snapshot Proposal Id**: The id of the snapshot proposal to check for governance activities.
**Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# Steam Wishlist
Source: https://docs.snagsolutions.io/loyalty/rules/steam-wishlist
## Overview
The "Steam Wishlist" loyalty rule allows admins to reward users for wishlisting games on Steam. This rule is useful for promoting your game and increasing visibility on the Steam platform.
## Prerequisites
* The user must have connected their Steam account to Snag.
* The user must have added the specified game to their Steam wishlist.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: The Steam Wishlist rule rewards users **immediately** upon successfully adding the specified game to their Steam wishlist.
* **User Reward Frequency**: This defines how often the user can earn the reward, e.g. daily, weekly, monthly, etc. If set to daily, the user can earn the reward once per day based on UTC time.
### **Custom Settings**
* Skip the multiplier for this rule
* **Steam App ID**: The ID of the Steam game that users need to wishlist. This can be found in the URL of your Steam store page (e.g., [https://store.steampowered.com/app/1234567/Game\_Name/](https://store.steampowered.com/app/1234567/Game_Name/) where 1234567 is the App ID).
* **Go to Steam Store**: This will add a button on the rule display page to take the user to the Steam store page for the game.
## Limitations
* API usage is rate-limited. To avoid restrictions, you can provide your own Steam API key.
# Join Telegram Channel
Source: https://docs.snagsolutions.io/loyalty/rules/telegram-join
## Overview
The "Telegram Join" loyalty rule allows admins to reward users for joining their Telegram channel. This rule is useful for building a community in Telegram.
## Prerequisites
* Snag [Telegram loyalty bot](https://t.me/snag_loyalty_bot) must be added to the Telegram group with admin permissions:
* [Bot Link](https://t.me/snag_loyalty_bot)
* The user must have connected their Telegram account to Snag.
* The user must have joined the defined Telegram channel.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: This defines that the rule will run daily/weekly/monthly at the defined start time and check if new users has joined the defined Telegram channel. This rule can also be claimed from the UI by clicking on the **"Claim" button** by the users.
* **User Reward Frequency**: This is one time reward and user will be rewarded once they join the defined Telegram channel.
### **Custom Settings**
* Skip the multiplier for this rule
* **Telegram Channel Id**: The ID of the Telegram channel where the rule will be applied.
* **Go to Server**: This will add the button on rule display page to take the user to the Telegram channel.
# Send Telegram messages
Source: https://docs.snagsolutions.io/loyalty/rules/telegram-messages
## Overview
The "Telegram Messages" loyalty rule allows admins to reward users for sending messages in their Telegram channel. This rule is useful for encouraging users to be more engaged in the Telegram channel.
## Prerequisites
* Snag [Telegram loyalty bot](https://t.me/snag_loyalty_bot) must be added to the Telegram group with admin permissions:
* [Bot Link](https://t.me/snag_loyalty_bot)
* The user must have connected their Telegram account to Snag.
* The user must have sent messages in defined channel.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will receive the defined number of points based on their activity or achievement.
* **Multiplier**: Users will receive the multiplier of the defined range based on their qualification level.
* **Required Range**: Define a numerical range for eligibility (tokens, actions, followers, messages count, etc.).
* **Points to Reward**: Define the number of points assigned for the specified qualification range.
* **Add New Range**: Allows defining multiple qualification ranges with corresponding rewards.
### Basic Settings
* **Update Cadence**: This defines how often the user will be rewarded and also how often the rule will check if the user has sent the defined number of messages in the Telegram channel.
### **Custom Settings**
* Skip the multiplier for this rule
* **Telegram Channel Id**: The ID of the Telegram channel where the rule will be applied.
* **Go to Server**: This will add the button on rule display page to take the user to the Telegram channel.
# Text Input
Source: https://docs.snagsolutions.io/loyalty/rules/text-input
## **Overview**
The "Text Input" loyalty rule allows admins to reward users based on the text input in a specific field.
## **Rule Configuration Fields**
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Basic Settings**
* **Update Cadence**: The Text Input rule rewards users **immediately** upon successful text input.
* **User Reward Frequency**: This defines how often the user can earn the reward, e.g. daily, weekly, monthly, etc. If set to daily, the user can earn the reward once per day based on UTC time.
### **Custom Settings**
* **Button Text**: This is the text that will be shown on the button that will show the text input field.
* **Verification Placeholder**: This placeholder text appears inside the input field to guide users on what to type.
* **Minimum verification text length**: Specify the number of characters that must be entered in the verification text.
* Skip the multiplier for this rule
# Hold a token
Source: https://docs.snagsolutions.io/loyalty/rules/token-hold
## **Overview**
The "Token Hold" loyalty rule allows admins to reward users based on
their NFT holdings across supported blockchain networks. The rule
enables the aggregation of token balances across multiple collections
and defines a structured reward system based on holding requirements.
## **Rule Configuration Fields**
### **Contract Address**
* **Collection Contract Address**: Enter one or more contract addresses representing the collections.
* **Network**: Select the blockchain network where the contract is deployed.
* **Add New Collection**: Allows adding multiple collections for token aggregation.
* **Important Note**: Token holdings from different collections will be aggregated to determine total holdings when more than one collection is added.
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points based on their holdings.
* **Multiplier**: Users will get the multiplier of the defined range based on their holdings.
* **Reward Per Token**: Toggle on to reward users per token held.
* **Required Hold Tokens Range**: Define a range of tokens that need to be held for eligibility.
* **Points to Reward**: Define the number of points assigned for the specified holding range.
* **Add New Range**: Allows defining multiple token holding ranges with corresponding rewards.
* **Only reward existing users**: If enabled this will limit rewards to users already in the loyalty program instead of all eligible wallets.
### **Update Cadence**
The **Update Cadence** field is crucial as it defines:
1. **Reward Frequency**: Determines how often the user will receive rewards (e.g., Daily, Weekly, Monthly).
2. **Holding Verification**: Specifies when the system will check the token holdings to determine eligibility.
3. **Relation to Start Time**: The first verification of token holdings and reward distribution will begin at the defined **Start Time**. Subsequent verifications and rewards will follow the selected cadence (e.g., if the cadence is set to "Daily," the system will check and reward holdings every 24 hours from the Start Time).
### **Custom Settings**
* Only reward users that bought on native marketplace
* Only reward users with unlisted tokens
* Skip the multiplier for this rule
* Only reward single token ownership per collection
* Add API to get dynamic rewards for each token
* Add custom reward for each token
* Only reward users that have paid full royalty
* Only reward users that have verified Twitter accounts
### **Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# Hold an ERC-20 Token
Source: https://docs.snagsolutions.io/loyalty/rules/token-hold-erc20
## **Overview**
The "Token Hold ERC-20" loyalty rule allows admins to reward users based on
their ERC-20 holdings across supported blockchain networks. The rule
enables the aggregation of token balances across multiple collections
and defines a structured reward system based on holding requirements.
## **Rule Configuration Fields**
### **Contract Address**
* **Collection Contract Address**: Enter one or more contract addresses representing the collections.
* **Network**: Select the blockchain network where the contract is deployed.
* **Add New Collection**: Allows adding multiple erc20 collections for token aggregation.
* **Important Note**: Token holdings from different erc20 collections will be aggregated to determine total holdings when more than one collection is added.
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points based on their holdings.
* **Multiplier**: Users will get the multiplier of the defined range based on their holdings.
* **Reward Per Token**: Toggle on to reward users per token held.
* **Required Hold Tokens Range**: Define a range of tokens that need to be held for eligibility.
* **Points to Reward**: Define the number of points assigned for the specified holding range.
* **Add New Range**: Allows defining multiple token holding ranges with corresponding rewards.
* **Only reward existing users**: If enabled this will limit rewards to users already in the loyalty program instead of all eligible wallets.
### **Update Cadence**
The **Update Cadence** field is crucial as it defines:
1. **Reward Frequency**: Determines how often the user will receive rewards (e.g., Daily, Weekly, Monthly).
2. **Holding Verification**: Specifies when the system will check the token holdings to determine eligibility.
3. **Relation to Start Time**: The first verification of token holdings and reward distribution will begin at the defined **Start Time**. Subsequent verifications and rewards will follow the selected cadence (e.g., if the cadence is set to "Daily," the system will check and reward holdings every 24 hours from the Start Time).
### **Custom Settings**
* Skip the multiplier for this rule
### **Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# Token Mint
Source: https://docs.snagsolutions.io/loyalty/rules/token-mint
## **Overview**
The "Token Mint" loyalty rule allows admins to reward users based on
the minting of tokens in specific collections. This rule is useful for motivating users to mint new collections.
## **Rule Configuration Fields**
### **Contract Address**
* **Token Contract Address**: Enter the contract address of the token.
* **Network**: Select the blockchain network where the contract is deployed.
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Update Cadence**
The **Update Cadence** field is crucial as it defines:
1. **Reward Frequency**: Determines how often the user will receive rewards (e.g., Daily, Weekly, Monthly).
2. **Mint Verification**: Specifies when the system will check the token mint to determine eligibility.
3. **Relation to Start Time**: The first verification of token mint and reward distribution will begin at the defined **Start Time**. Subsequent verifications and rewards will follow the selected cadence (e.g., if the cadence is set to "Daily," the system will check and reward mints every 24 hours from the Start Time).
### **Custom Settings**
* Only reward users with unlisted tokens. This can only be enabled if all the collections are of erc721 type.
* Skip the multiplier for this rule
* Add API to get dynamic rewards for each token
* Add custom reward for each token
### **Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# Token Purchase
Source: https://docs.snagsolutions.io/loyalty/rules/token-purchase
## **Overview**
The "Token Purchase" loyalty rule allows admins to reward users based on
the purchase of a specific token. This rule is useful for pushing users to
purchase a specific token.
## **Rule Configuration Fields**
### **Contract Address**
* **Token Contract Address**: Enter the contract address of the token.
* **Network**: Select the blockchain network where the contract is deployed.
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Update Cadence**
The **Update Cadence** field is crucial as it defines:
1. **Reward Frequency**: Determines how often the user will receive rewards (e.g., Daily, Weekly, Monthly).
2. **Purchase Verification**: Specifies when the system will check the token purchase to determine eligibility.
3. **Relation to Start Time**: The first verification of token purchase and reward distribution will begin at the defined **Start Time**. Subsequent verifications and rewards will follow the selected cadence (e.g., if the cadence is set to "Daily," the system will check and reward purchases every 24 hours from the Start Time).
### **Custom Settings**
* Only reward users that bought on native marketplace
* Only reward users with unlisted tokens. This can only be enabled if all the collections are of erc721 type.
* Skip the multiplier for this rule
* Add API to get dynamic rewards for each token
* Add custom reward for each token
* Only reward users that have paid full royalty
* Only reward users that have verified Twitter accounts.
* Only reward users who have purchased in specific currency.
### **Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# Token Sale
Source: https://docs.snagsolutions.io/loyalty/rules/token-sale
## **Overview**
The "Token Sale" loyalty rule allows admins to reward users based on
the sale of tokens in specific collections. This rule is useful having
rotation of tokens.
## **Rule Configuration Fields**
### **Contract Address**
* **Token Contract Address**: Enter the contract address of the token.
* **Network**: Select the blockchain network where the contract is deployed.
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### **Update Cadence**
The **Update Cadence** field is crucial as it defines:
1. **Reward Frequency**: Determines how often the user will receive rewards (e.g., Daily, Weekly, Monthly).
2. **Sale Verification**: Specifies when the system will check the token sale to determine eligibility.
3. **Relation to Start Time**: The first verification of token sale and reward distribution will begin at the defined **Start Time**. Subsequent verifications and rewards will follow the selected cadence (e.g., if the cadence is set to "Daily," the system will check and reward sales every 24 hours from the Start Time).
### **Custom Settings**
* Only reward users that sold on native marketplace
* Only reward users with unlisted tokens. This can only be enabled if all the collections are of erc721 type.
* Skip the multiplier for this rule
* Add API to get dynamic rewards for each token
* Add custom reward for each token
* Only reward users that have sold with full royalty paid
* Only reward users that have verified Twitter accounts.
* Only reward users who have sold in specific currency.
### **Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# Reach X followers
Source: https://docs.snagsolutions.io/loyalty/rules/x-followers
## Overview
The "Twitter/X Followers" loyalty rule allows admins to reward users for having a certain number of followers on Twitter or X. This rule is useful for encouraging users with a large social media following to join the platform.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will receive the defined number of points based on their activity or achievement.
* **Multiplier**: Users will receive the multiplier of the defined range based on their qualification level.
* **Required Range**: Define a numerical range for eligibility (tokens, actions, followers, messages count, etc.).
* **Points to Reward**: Define the number of points assigned for the specified qualification range.
* **Add New Range**: Allows defining multiple qualification ranges with corresponding rewards.
### Basic Settings
* **Update Cadence**: This defines that the rule will run daily/weekly/monthly at the defined start time and check the no of followers of the users who joined the platform and their followers fall within the defined reward range.
* **User Reward Frequency**: This is a one-time reward that users can claim after linking their accounts, helping to build a connected community across platforms.
### **Custom Settings**
* Skip the multiplier for this rule
# Post New Tweet
Source: https://docs.snagsolutions.io/loyalty/rules/x-new-tweet
## Overview
The "Post New Tweet" loyalty rule allows admins to reward users for posting a new tweet with specific text on their X account. This rule is useful for getting more engagement on their X account.
## Prerequisites
* This rule is not enabled by default. You need to contact support to enable it.
[Contact Support](https://snagsolutions.io/contact)
* The user must have connected their X account to Snag.
* The user must post a new tweet with specific text on their X account and submit the claim.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: Points for this rule will be rewarded immediately on user claim after they follow the defined X account.
* **User Reward Frequency**: This defines how often the user will be rewarded. You can choose between one time, daily, weekly, or monthly.
### **Custom Settings**
* **Create X Post that includes**: This lets you define the text that the user must post in their tweet.
* Skip the multiplier for this rule
**Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# X Post Reaction
Source: https://docs.snagsolutions.io/loyalty/rules/x-post-reaction
## Overview
The "X Post Reaction" loyalty rule allows admins to reward users for commenting, reposting, or liking a specific X post.
Please note: Likes are not actively tracked and are only displayed to enhance user engagement.
## Prerequisites
* This rule is not enabled by default. You need to contact support to enable it.
[Contact Support](https://snagsolutions.io/contact)
* The user must have connected their X account to Snag.
* The user must have commented, reposted, or liked a specific X post, depending on the rule configuration.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: Points for this rule will be rewarded immediately on user claim after they follow the defined X account.
* **User Reward Frequency**: This defines how often the user will be rewarded. You can choose between one time, daily, weekly, or monthly.
### **Custom Settings**
* **X Post URL**: This lets you define the URL of the X post that the user must react to.
* **Required Actions**: This lets you define the actions that the user must perform on the X post.
* **Comment**: The user must comment on the X post.
* **Repost**: The user must repost the X post.
* **Like**: The user must like the X post. (Likes are not actively tracked and are only displayed to enhance user engagement.)
* Skip the multiplier for this rule
**Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# X Text in Bio
Source: https://docs.snagsolutions.io/loyalty/rules/x-text-in-bio
## Overview
The "X Text in Bio" loyalty rule allows admins to reward users for posting a specific text in their X bio. This rule is useful for getting more engagement on their X account.
## Prerequisites
* This rule is not enabled by default. You need to contact support to enable it.
[Contact Support](https://snagsolutions.io/contact)
* The user must have connected their X account to Snag.
* The user must have a specific text in their X bio and submit the claim.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: Points for this rule will be rewarded immediately on user claim after they follow the defined X account.
* **User Reward Frequency**: This defines how often the user will be rewarded. You can choose between one time, daily, weekly, or monthly.
### **Custom Settings**
* **Text to check in X Bio**: This lets you define the text that the user must have in their X bio.
* Skip the multiplier for this rule
**Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# X Text in Comment
Source: https://docs.snagsolutions.io/loyalty/rules/x-text-in-comment
## Overview
The "X Text in Comment" loyalty rule allows admins to reward users for posting a specific text in their X comment. This rule is useful for getting more engagement on their X account.
## Prerequisites
* This rule is not enabled by default. You need to contact support to enable it.
[Contact Support](https://snagsolutions.io/contact)
* The user must have connected their X account to Snag.
* The user must have a specific text in their X comment and submit the claim.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: Points for this rule will be rewarded immediately on user claim after they follow the defined X account.
* **User Reward Frequency**: This defines how often the user will be rewarded. You can choose between one time, daily, weekly, or monthly.
### **Custom Settings**
* **Text to check in X Comment**: This lets you define the text that the user must have in their X comment.
* Skip the multiplier for this rule
**Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# X Text in Username
Source: https://docs.snagsolutions.io/loyalty/rules/x-text-in-username
## Overview
The "X Text in Username" loyalty rule allows admins to reward users for posting a specific text in their X username. This rule is useful for getting more engagement on their X account.
## Prerequisites
* This rule is not enabled by default. You need to contact support to enable it.
[Contact Support](https://snagsolutions.io/contact)
* The user must have connected their X account to Snag.
* The user must have a specific text in their X username and submit the claim.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: Points for this rule will be rewarded immediately on user claim after they follow the defined X account.
* **User Reward Frequency**: This defines how often the user will be rewarded. You can choose between one time, daily, weekly, or monthly.
### **Custom Settings**
* **Text to check in X Username**: This lets you define the text that the user must have in their X username.
* Skip the multiplier for this rule
**Call to Action (Optional)**
This will show a call to action in our loyalty rule.
* **Link**: Provide a URL for users to take further action.
* **Button Text**: Define the button label.
# YouTube Comment
Source: https://docs.snagsolutions.io/loyalty/rules/youtube-comment
## Overview
The "YouTube Comment" loyalty rule allows admins to reward users for commenting on specific YouTube videos. This rule is useful for increasing engagement with your YouTube content and building community interaction.
## Prerequisites
* The user must have connected their Google account to Snag.
* The user must comment on the specified YouTube video.
* The user must gather the link of the comment they made on youtube video and submit the link for verification.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: The YouTube Comment rule rewards users **immediately** upon successful posting of a comment on the specified YouTube video.
* **User Reward Frequency**: This defines how often the user can earn the reward, e.g. daily, weekly, monthly, etc. If set to daily, the user can earn the reward once per day based on UTC time.
### **Custom Settings**
* Skip the multiplier for this rule
* **YouTube Video ID**: The ID of the YouTube video that users need to comment on. This can be found in the URL of your YouTube video (e.g., [https://www.youtube.com/watch?v=ABC123xyz](https://www.youtube.com/watch?v=ABC123xyz) where ABC123xyz is the Video ID).
* **YouTube Video Link**: This will add a button on the rule display page to take the user directly to the YouTube video.
## Limitations
* API usage is rate-limited. To avoid restrictions, you can provide your own YouTube API key.
# YouTube Subscriber
Source: https://docs.snagsolutions.io/loyalty/rules/youtube-subscriber
## Overview
The "YouTube Subscriber" loyalty rule allows admins to reward users for subscribing to specific YouTube channel. This rule is useful for growing your YouTube presence and encouraging your community to follow your content.
## Prerequisites
* The user must have connected their Google account to Snag.
* The user must subscribe to the specified YouTube channel.
## Rule Configuration Fields
### **Reward**
* **Type of Reward**: Choose between "Points" or "Multiplier".
* **Points**: Users will get the defined no of points.
* **Multiplier**: Users will get the multiplier of the defined amount.
### Basic Settings
* **Update Cadence**: The YouTube Subscriber rule rewards users **immediately** upon successfully subscribing to the specified YouTube channel.
* **User Reward Frequency**: This defines how often the user can earn the reward, e.g. daily, weekly, monthly, etc. If set to daily, the user can earn the reward once per day based on UTC time.
### **Custom Settings**
* Skip the multiplier for this rule
* **YouTube Channel ID**: The ID of the YouTube channel that users need to subscribe to.
To find your YouTube channel ID:
1. Sign in to YouTube
2. Click your profile picture → Settings
3. Select Advanced settings from the left menu
4. Your channel ID will be displayed there
* **YouTube Channel Link**: This will add a button on the rule display page to take the user directly to the YouTube channel.
## Limitations
* API usage is rate-limited. To avoid restrictions, you can provide your own YouTube API key.
# Set up loyalty currency
Source: https://docs.snagsolutions.io/loyalty/set-up-loyalty-currency
After you have enabled loyalty program on your admin page, you will need to create a loyalty currency.
## Overview
Configuring a loyalty currency is the first step to creating a loyalty program. This is the currency that will be used to track loyalty points and rewards. Moreover, you can configure multiple loyalty currencies to your admin page.
1. Navigate to the Loyalty builder tab in the admin page.
2. Click on the "Currencies and Balances" section.
3. Click on the "Add new currency" button.
4. Fill in the required fields and click "Save".
Congratulations! 🎉
You have created a loyalty currency and can now create your first loyalty rule.
# Updating & reseting balances
Source: https://docs.snagsolutions.io/loyalty/updating-balances
This recipe explains how to manually update user loyalty points balances (i.e. not as part of a rule completion or spend action; an example use-case is to reset all user point balances to 0).
## Overview
In some cases, you may need to manually update loyalty point balances outside the context of automated rules or spend actions. For example:
* Resetting all user balances to zero.
* Crediting or debiting points manually for a specific promotion or adjustment.
Snag provides two approaches for handling this: a no-code solution via the admin dashboard and a programmatic solution using the API.
***
## Approaches
### Admin Dashboard (recommended)
We provide a no-code solution for this via the admin dashboard. Note: this approach supports up to 250,000 balance changes per CSV upload.
#### Steps:
1. Go to the admin dashboard: [https://admin.snagsolutions.io](https://admin.snagsolutions.io).
2. Navigate to the `Loyalty` page from the left-side menu.
3. Click `Update Balances` (this opens the modal for updating user balances and provides a CSV template for uploading balance changes).
4. Download and fill out the CSV template with the relevant balance changes.
5. Upload the completed CSV file in the modal.
6. Click `Add` to queue the balance changes. A rule will be created to represent the queued changes. If it does not appear immediately, refresh the page.
7. Verify execution:
* Click the eye icon on the created rule.
* Compare the `Rewards` count to the number of rows in your CSV file. If they match, execution is complete.
***
### API
For programmatic updates, use the endpoint to create a loyalty transaction and update balances.
#### Endpoint:
**Request Body:**
```json
{
"description": "An explanation for the manual balance adjustment",
"loyaltyCurrencyId": "string",
"entries": [
{
"walletAddress": "0x00",
"direction": "debit",
"amount": 0
},
{
"walletAddress": "0x01",
"direction": "credit",
"amount": 100
}
]
}
```
* `description`: Explanation for the adjustment (e.g., “Reset balances to zero”).
* `loyaltyCurrencyId`: The ID of the loyalty currency to update.
* `entries`: A list of transactions specifying:
* `walletAddress`: The wallet of the user whose balance is being adjusted.
* `direction`: Either credit to add points or debit to remove points.
* `amount`: The number of points to credit or debit.
**Example Response:**
```json
{
"code": 200,
"message": "Values updated successfully."
}
```
#### Steps
1. Prepare the JSON payload with your required adjustments.
2. Send a POST request to the endpoint with your payload.
3. Verify the response to ensure the transaction was processed successfully.
## Summary
For flexibility and simplicity:
* Use the Admin Dashboard for batch updates and non-technical workflows.
* Use the API for programmatic and highly customized updates.
Both approaches ensure your loyalty balances are kept up to date with minimal effort.
***
## Point Reset Options
Snag admins have access to a **Reset Balances** feature, which allows for resetting loyalty balances in different ways. This feature provides three reset options:
1. Reset all balances
* Reset all user balances to zero
* The currency itself, ledger data and existing rules remain unchanged
2. Reset all balances and ledger data
* Resets all user balances to zero and resets the ledger data
* The ledger reset is done by cloning the exisitng currency and all associated rules
3. Reset all balances, ledger data and rules
* Reset all user balances to zero
* Clones the currency and deletes all associated rules without recreating them
### Important Notes
* This feature is only available to **Snag admins**. If other users require access to this functionality, they should contact Snag support.
* Resetting balances cannot be undone, so proceed with cauting when using these options.
# Verifying rule completion
Source: https://docs.snagsolutions.io/loyalty/verifying-rule-completion
This recipe explains how to submit and verify loyalty rule completion via the Snag API.
## Prerequisites
Before submitting and verifying loyalty rule completion, you must have a user registered in Snag.
Depending on the social platform, you'll need the following user information:
* **Twitter**: User's Twitter handle and Twitter user ID
* **Telegram**: User's Telegram handle and Telegram user ID
* **Discord**: User's Discord handle and Discord user ID
For more information on user management, see:
* [Managing user accounts](/recipes/api/managing-user-accounts)
## Overview
Use the Snag API to submit and verify loyalty rule completions from your own backend.
Because external verification to third-party services (e.g. Twitter, Telegram, etc.) may take up to a couple minutes,
we use an asynchronous process to verify rule completion.
> **Note:** The API-based verification process described in this recipe is only required for the following rule types:
>
> * Code Entry
> * Complete Profile
> * Connect Discord
> * Connect Email
> * Connect Epic
> * Connect Steam
> * Connect Telegram
> * Connect Twitter
> * Connect Wallet
> * Daily Check-In
> * Discord Member
> * Discord Messages
> * External Rule
> * Follow X Account
> * Link Click
> * Poll
> * Quiz
> * Telegram Join
> * Telegram Messages
> * Text Input
> * TokenHold (only for multiplier reward type) - this step is not required for Cadence based rules (e.g., Token Hold, Sold On ... etc), as these rules run automatically on the specified start time and on set cadence (daily, weekly, monthly).
> * X New Tweet
> * X Post Reaction
> * X Text in Bio
> * X Text in Comment
> * X Text in Username
> * Youtube Comment
> * Youtube Subscriber
> * Steam Wishlist
Let's set up a rule to follow a specific Twitter account. The twitter handle or twitter user ID can be configured in the admin dashboard.
We can then use the loyalty rule completion endpoint to submit a request to verify the rule completion.
We can use the loyalty rule status endpoint to check the status of the rule completion request.
When verification is complete, our system then creates a loyalty transaction to reward the user.
The rule completion endpoint will return an error if re-called and the rule is already completed for the user.
Here is an example implementation in javascript on how you can use the following three endpoints to submit and verify loyalty rule completion:
* [`POST /api/loyalty/rules/{id}/complete`](https://docs.snagsolutions.io/api-reference/loyalty/complete-loyalty-rule)
* [`POST /api/loyalty/rules/status`](https://docs.snagsolutions.io/api-reference/loyalty/get-processing-status-for-a-specific-user-on-loyalty-rules)
* [`GET /api/loyalty/transaction_entries`](https://docs.snagsolutions.io/api-reference/loyalty/get-loyalty-transaction-entries)
```JavaScript
const yourServerBaseUrl = "YOUR_SERVER_BASE_URL"
const userId = "USER_ID"
const ruleId = "RULE_ID"
let isLoading = false
let success = false
// After the claim is successful, we store the transaction entries for the user in this array
let transactionEntries = []
async function postCommentOnTwitter() {
console.log("Posted comment on Twitter!")
}
async function callCompleteEndpoint() {
isLoading = true
try {
const response = await fetch(`${yourServerBaseUrl}/loyalty/complete`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ userId, ruleId }),
})
console.log("Complete Endpoint Response:", await response.json())
pollStatus()
} catch (error) {
console.error("Error completing loyalty rule:", error)
isLoading = false
}
}
async function pollStatus() {
const statusUrl = `${yourServerBaseUrl}/loyalty/status?userId=${userId}`
let attempts = 0
async function poll() {
try {
const response = await fetch(statusUrl, {})
const statuses = await response.json()
console.log("Status Endpoint Response:", statuses)
const ruleStatus = statuses.find((item) => item.loyaltyRuleId === ruleId)
if (ruleStatus) {
if (ruleStatus.status === "completed") {
transactionEntries = await fetchTransactionEntries()
success = true
} else if (ruleStatus.status === "failed") {
success = false
} else if (attempts < 10) {
attempts++
setTimeout(poll, 1000)
} else {
success = false
}
} else if (attempts < 10) {
attempts++
setTimeout(poll, 1000)
} else {
success = false
}
} catch (error) {
console.error("Error polling status:", error)
success = false
} finally {
isLoading = false
button.textContent = "Claim"
}
}
poll()
}
async function fetchTransactionEntries() {
try {
const response = await fetch(
`${yourServerBaseUrl}/loyalty/transaction-entries?userId=${userId}&userCompletedLoyaltyRuleId=${ruleId}`,
{}
)
console.log("Transaction Entries Response:", await response.json())
} catch (error) {
console.error("Error fetching transaction entries:", error)
}
}
async function handleClaim() {
if (isLoading) return
await postCommentOnTwitter()
await callCompleteEndpoint()
}
```
# X rules logic
Source: https://docs.snagsolutions.io/loyalty/x-rules-logic
Additional context for X (Twitter) rules logic
We have two approaches to rewarding contributions on X (formerly Twitter) depending on partner requirements, and can support both out of the box:
### **Recommended Approach**
This approach is a X API ‘workaround’, allowing us to read the user’s completed actions without the additional cost associated with the X platform’s APIs and most of the functionality. Available logic includes:
1. Comment on specific X post.
2. Repost specific X post.
3. Follow X account for as long as the quest is live.
4. Use a specific phrase in a post or reply (ie. “Snag Solutions is 🐐’ed”).
5. Use a specific phrase in your bio.
6. Use a specific phrase in your username.
### **Requires X API**
This approach requires your X API key be inputted into your loyalty program builder by a Snag admin, and typically requires the X Pro plan which starts at \$5,000 to not miss any data. These quests query all actions associated with a specific rule vs. requiring a user to claim based on engaging with a specific post or account to capture all contributions. Available logic includes:
1. Repost on X.
2. Quote or Comment on an X post.
3. Like a post on X.
4. X post liked by project’s main account (Pacmoon style rewards):
* Add a multiplier for verified X accounts.
* Reward users based on the impression of their post.
5. Mention (@) or Hashtag (#) rewards (i.e 10 points / #winning / day).
# Announce it on socials
Source: https://docs.snagsolutions.io/marketplace/announce
Once you're marketplace is live, here’s everything you need to know to announce it to your community! Feel free to insert screenshots of your marketplace throughout the thread to enhance product visibility!

**Thread Template:**
1. We’re excited to announce the launch of the official \[Project Name] marketplace, powered by Snag Solutions. Let's take a look at some of the unique features our marketplace offers users 👇
\[Insert Link Here]
2. P2P Trading: With P2P trading you can trade seamlessly across our collection(s) securely! Navigate to ‘Trades’ under the wallet dropdown menu and say goodbye to risky third party platforms. Native trading ensures that all assets belong to our verified collections and restricts transactions to our collections only.
3. Credit Card Purchasing: You can now purchase \[Project Name] NFTs with just a few clicks using your credit/debit card!mGet those wallets out and experience a seamless and secure onboarding process for new and existing holders. Moonpay allows purchasing from Visa and Mastercard globally as well as any of the [following credit cards](https://stripe.com/docs/payments/cards/supported-card-brands).
4. Community Feed: Holders can now access our community feed with project announcements, community posts and more. Post content and react + comment on others posts to engage with our community! Holders can create a trading post and trade directly from the feed experience. Say goodbye to navigating from your Discord WTT channel to a third party site or person, it’s time to trade on one channel securely.
5. Token Gated Social Profiles & Directory: You can link your socials to increase your visibility within our community and engage with others seamlessly. Once you’ve created a profile you can access the token gated holder directory via the Holders tab to find other holders and compare your stats!
6. Thank you for your support as we continue to grow and improve the user experience. We're excited to work with @Snag\_Solutions to onboard more users to our community with the \_\_\_\_\_ marketplace!
**Important Note:**
When including the marketplace link, ensure the URL begins with `https://` to enable proper link previews.
# Launch a marketplace
Source: https://docs.snagsolutions.io/marketplace/launch-a-marketplace

This recipe is a quickstart guide to setting up your Snag powered marketplace, covering marketplace configuration and customization.
### Why launch your own marketplace
By launching a Snag powered marketplace you take control of the entire purchasing experience, creating an easier shopping journey for your audience. With key integrations and an experience optimized for conversion, Snag powered marketplaces are the best place for brands, games, and apps to sell their digital assets and enable secondary trading.
### Walkthrough
For a text-based walkthrough [check out Snag's 'How To' article on our blog](https://www.snagsolutions.io/how-to-use-snag-s-self-serve-tool).
### Launching your marketplace
From experience launching >100 marketplaces with partners, below are suggestions to maximize this tool's effectiveness.
### Suggested linking to enable marketplace discovery
We suggest linking your marketplace to enable discovery via the following social & site elements
| Property | Suggestion | Context |
| ------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| Twitter Bio | Link in bio or as website | This is the single biggest change to drive direct traffic to the marketplace |
| Linktree | Include at the top of your linktree as 'project name marketplace' | It's up to you if you want to remove other marketplace links, but we suggest you place ours at the top regardless. |
| Site homepage | Prominent call to action either in topline nav, homepage UI, or both | Again, you to keep or remove other marketplace links. We aggregate listings to act as a source of truth for buyers. |
| Tweets | Share directly with your followers! | We're happy to subsidize 0-fees at launch and/or partner on giveaways & spaces to augment the message. |
### Landing Page suggestions
If you're using our landing page builder to create a home page for your marketplace, please review the following suggestions to create the best user experience:
*You can customize your landing page, tailor its sections and features, and tell everyone your brand's story. You can choose from four different types of sections:*
### Showcase

### Showcase section variations
The showcase contains a title, supporting text, banner and item or collection preview. All of the mentioned components are optional so you can create multiple variations of the showcase section. Here are some examples

As you see, the showcase section can be used and customized in multiple ways to achieve the desired outcome.
> 💡 Tip: With the showcase section you can promote upcoming drops, live actions, mints, etc. or link to previous drops.
### Background
If you toggle on the banner you can choose from the predefined background or upload your own image. We recommend an aspect ratio of 5:1 and at least a 1000px width. You can also set a banner link to an internal or external page.
> 💡 Tip: Make sure you use a dark enough image so that it is easy to read the text above it and that your photos look good on mobile.

### Collection or item preview
You can also show a collection or item preview. If you select an item preview, you can specify the items you wish to display or filter them based on sorting criteria.


### Strip

The strip contains a title, copy, and button link. The button can link to an existing collection or the whole marketplace. It also supports external links.
### Strip section variants
All of the mentioned components are optional so you can create multiple variations of the strip section. Here are some examples:

### Background
To change the strip section background you can choose a color or use one of the predefined background templates. If you change the hex color the templates will inherit the color you provide.

There is also an option to upload your own image. You can upload a PNG or JPG. We recommend an aspect ratio of 5:2 and at least a 1440px width.
> 💡 Tip: Make sure you use a dark enough image so that it is easy to read the text above it and that your photos look good on mobile.

You can toggle on a black overlay to create more separation between the background and other elements.

### Featured

The featured contains a title, copy, button link and a featured item or collection. The button links to the collection or item that you've selected.
### Alignment
You can choose to align the image left or right.

# Customization
Source: https://docs.snagsolutions.io/setup/customization
Snag gives partners powerful tools to customize their platform's branding, layout, and theme—no code required. This guide walks through all available customization options to help you tailor your white-labeled experience to your brand and community.
## Overview
The **Customization** tab is where you manage all visual and branding settings for your platform. It’s organized into three main sections:
1. **Platform Settings** - Define platform-wide identity like name, favicon and currency.
2. **Themes** - Set global colors, typography and custom CSS.
3. **Header** - Control your logo, home page, navigation links and social links.
***
## Platform Settings
These settings define your platform’s core identity and optional capabilities.

* **Platform Name**: Sets the name shown in the UI and browser.
* **Favicon**: Upload a 32x32 icon that appears in the browser tab.
* **Delegate Cash**: Toggle [Delegate.cash](http://Delegate.cash) support for secure delegated access.
* **Currency**: Select how prices are displayed - either in Crypto or Fiat.
***
## Themes
Set platform colors to align with your brand identity. Themes define the look and feel of your entire platform.

### Colors
Define your color system to ensure consistency across all UI components:
* **Primary Color**: Main brand color used for primary buttons and key highlights.
* **Secondary Color**: Applied to secondary buttons and container backgrounds.
* **Background Color**: Sets the default page background color.
* **Text Colors**: Define both **primary** and **secondary** text colors for clear readability.
* **Separator Color**: Used for lines, borders, and dividers between elements.
Make sure your colors have enough contrast for accessibility.
### Fonts
Choose a default font or upload your own to match your brand typography.
* You can **add multiple fonts**.
* Use **Custom CSS** to target specific elements or sections with your uploaded fonts.
### Custom CSS
Edit the `stylesheet.css` file to add advanced visual overrides or tweaks.
### Page Background
Upload a custom background image or texture - this will appear across **all pages**.
***
## Header
Use this section to personalize the top navigation area of your platform.

* **Header Logo**: Upload a PNG or JPG in any ratio. This will be shown in the top-left of your header.
* **Header Text**: Optional label (e.g. "Loyalty Program", "Ecosystem" or "Season 01").
* **Home Page**: Select the default landing page from your available pages.
* **Navigation Links**: Define custom nav items to guide users to key areas of your platform or to external pages.
* **Social Links**: Link social profiles by adding URLs for Twitter, Discord, Telegram and more.
# Hostname
Source: https://docs.snagsolutions.io/setup/hostname
### Activating your platform
1. Decide on the domain name where you'd like to point your platform.
1. E.g. `{yourwebsite}.com`
2. Choose the**subdomain** for your platform.
1. E.g. `loyalty.{yourwebsite}.com`
3. Have a technical member on your team add a DNS record to your domain host. We will be adding a `CNAME record`.
* See example in AWS Route 53

4. Navigate to the 'Hostname' section on admin.snagsolutions.io and input your new subdomain.
If you're having trouble with setting up your subdomain / CNAME, please refer to the following pages to resolve those issues:
* GoDaddy: [https://www.godaddy.com/help/add-a-cname-record-19236](https://www.godaddy.com/help/add-a-cname-record-19236)
* Cloudflare: [https://developers.cloudflare.com/dns/zone-setups/partial-setup/setup/](https://developers.cloudflare.com/dns/zone-setups/partial-setup/setup/)
* NameCheap: [https://www.namecheap.com/support/knowledgebase/article.aspx/9646/2237/how-to-create-a-cname-record-for-your-domain/](https://www.namecheap.com/support/knowledgebase/article.aspx/9646/2237/how-to-create-a-cname-record-for-your-domain/)
***
Contact us if you have any questions or need additional help configuring your specific environment.
# Set up overview
Source: https://docs.snagsolutions.io/setup/setup-overview
Snag lets you launch your all-in-one branded engagement platform using our no-code tools. Use the Snag admin dashboard to create a loyalty program, set up a rewards shop, build custom pages and more.
This section walks through the key steps to go live, from setup to launch.
## Launch checklist
When you first open the Snag admin dashboard, whether from the “Get Started” button on our website or the top-right link here, you’ll be prompted to enter some basic info about your project. You can always update this later under **Customization → Platform Settings**.
Make it yours. Head to the **Customization** tab to set your theme colors, upload fonts and fine-tune your platform’s visual style. Learn more [here](/setup/customization).
Before going live, you’ll need to sign our partner agreement. You’ll find it on the **Snag Admin Home** page.
Launch under your own domain by following [these steps](/setup/hostname). This ensures your platform feels fully branded end to end.
Now you’re all set to start configuring your loyalty program with different types of rules. Begin by [creating your first loyalty rule →](/loyalty/create-your-first-rule)
We test constantly, but it’s still smart to run your own QA. A few key checks:
* Cross-device experience
* Cross-wallet compatibility
* Rule completion
Post it on X or wherever you connect with your community.
# User profiles
Source: https://docs.snagsolutions.io/setup/user-profiles
The following will guide you through creating a user profile and the functionality available within profiles.
### Overview
User profiles are a powerful tool allowing projects to learn more about their audience, and build a CRM to engage more customers. Snag user profiles are complete, and allow you to collect social profile connections, associate multiple wallets under one account, and associate an email address with accounts to send email announcements (also available via the Snag platform).
### Set up
On the admin side you can choose what profile elements you'd like your users to have.

### User side
**Edit Profile**
Once a user connects their wallet they can edit their profile by accessing the 'Edit Profile' section in the user dropdown menu:

**About**
In the 'About' section of their profile the user can add information about themselves.

**Accounts & Wallets**
Under 'Accounts & Wallets' the user can associate social profiles and other wallets to their Snag profile, as defined by your preferences during set up. Email connection is on by default.

**Notifications**
Users can connect their emails, and via admin.snagsolutions.io you can send them email announcements. Users connect their email under 'Accounts & Wallets' and can Opt-in to 'Email Announcements' under the 'Notifications' section.

# Function Templates
Source: https://docs.snagsolutions.io/stratus/function-templates
Ready-to-use templates for common Stratus function patterns
## Overview
Check out the [Function Syntax](https://docs.snagsolutions.io/stratus/syntax) page for more information on how to create and validate Stratus functions
and the [Overview](https://docs.snagsolutions.io/stratus/functions) page before you start..
These templates are starting points. You should modify them based on your
specific requirements and add appropriate error handling.
Here are some common function templates you can use as starting points for your Stratus functions. Simply copy the code and replace the placeholder values with your specific parameters.
## Track Relay.Link Bridge Activity
This function rewards users for bridging assets through [relay.link](https://relay.link). Replace the constants in the first lines of the function with your actual values.
There are two core steps to this function both of which can exist as part of any function:
1. It tracks all incoming transfers to the `DESTINATION_CHAIN_ID`.
2. It uses the Coingecko API for price tracking. It requires a minimum of 1\$ worth of coins to be bridged over and the dollar amount is multiplied by the REWARD\_MULTIPLIER variable.
### Function Code
```javascript bridge-rewards.js
const axios = require('axios')
/**
* Required consts for the function
*/
const LOYALTY_API_KEY = 'REPLACE_WITH_YOUR_API_KEY'
const LOYALTY_RULE_ID = 'REPLACE_WITH_YOUR_LOYALTY_RULE_ID'
const REWARD_MULTIPLIER = '1' // USD value will be multiplied by 1
const DESTINATION_CHAIN_ID = 'REPLACE_WITH_CHAINID'
const GAS_TOKEN_ID = 'eth' // replace with the gas token ID of the destination chain
/**
* Additional logger functionality
*/
const logs = []
const errors = []
const log = Object.assign(
(message) => {
logs.push(message)
},
{
error: (errorMessage) => {
errors.push(errorMessage)
},
logs,
errors,
}
)
/**
* Get reward amount
*/
function rewardAmount(amount) {
const number = parseFloat(amount)
if (isNaN(number) || number < 1) return 0
return Math.floor(number * REWARD_MULTIPLIER)
}
/**
* Mark loyalty rule as completed to reward user
*/
async function completeLoyaltyRule(reward, log) {
try {
if (!LOYALTY_API_KEY) {
throw new Error('LOYALTY_API_KEY is not defined')
}
await axios.post(
`https://admin.snagsolutions.io/api/loyalty/rules/${LOYALTY_RULE_ID}/complete`,
{
verifyOnly: 'false',
amount: reward.reward,
walletAddress: reward.walletAddress,
idempotencyKey: reward.txHash,
},
{
headers: {
'Content-Type': 'application/json',
'X-API-KEY': LOYALTY_API_KEY,
},
}
)
log(
`${reward.walletAddress} rewarded with ${reward.reward} points for $${reward.amount} transaction, rule ${LOYALTY_RULE_ID}`
)
} catch (error) {
log.error(`Failed for ${reward.walletAddress}: ${error.message}`)
}
}
/**
* Get recent relay requests
*/
async function getRelayRequests() {
const limit = 20
const endTimestamp = Math.floor(Date.now() / 1000)
const startTimestamp = endTimestamp - 10 * 60
const allResults = []
let continuation = null
try {
if (!DESTINATION_CHAIN_ID) {
throw new Error('DESTINATION_CHAIN_ID is not defined')
}
do {
let baseUrl = 'https://api.relay.link/requests/v2'
const queryParams = [
`sortBy=createdAt`,
`destinationChainId=${DESTINATION_CHAIN_ID}`,
`startTimestamp=${startTimestamp}`,
`endTimestamp=${endTimestamp}`,
`limit=${limit}`,
]
if (continuation) {
queryParams.push(`continuation=${encodeURIComponent(continuation)}`)
}
const url = `${baseUrl}?${queryParams.join('&')}`
const response = await axios.get(url)
const data = response.data
if (Array.isArray(data.requests)) {
allResults.push(...data.requests)
}
continuation = data.continuation
} while (continuation)
return allResults
} catch (error) {
log.error(`[getRelayRequests] Error fetching relay requests`)
log.error(error)
return []
}
}
/**
* Get recent relay rewards
*/
async function getRecentRewards() {
const txArray = await getRelayRequests()
const rewards = []
try {
if (!txArray || txArray.length === 0) {
log('No new rewards found')
return rewards
}
for (const tx of txArray) {
if (tx?.status === 'success' && tx?.user) {
const currencyInChainId =
tx?.data?.metadata?.currencyIn?.currency?.chainId
if (currencyInChainId === DESTINATION_CHAIN_ID) {
continue
}
const amountUsd =
tx?.data?.metadata?.currencyOut?.amountUsdCurrent ||
tx?.data?.metadata?.currencyIn?.amountUsdCurrent ||
0
if (!amountUsd) continue
const currency = tx?.data?.currency
if (!currency || !['usdc', GAS_TOKEN_ID].includes(currency)) continue
const txHash = tx?.data?.outTxs?.[0]?.hash
const amountToReward = rewardAmount(amountUsd)
if (amountToReward > 0) {
rewards.push({
walletAddress: tx.recipient,
amount: amountUsd,
reward: amountToReward,
txHash: txHash,
})
}
}
}
} catch (e) {
log.error(`[getRecentRewards] Error fetching relay requests`)
log.error(e)
}
return rewards
}
/**
* Reward users
*/
async function rewardUsers(rewards, log) {
for (const reward of rewards) {
await completeLoyaltyRule(reward, log)
}
}
module.exports.handler = async (input, output) => {
try {
const rewards = await getRecentRewards()
if (rewards.length === 0) {
log('No rewards found')
} else {
log(`Found ${rewards.length} rewards`)
await rewardUsers(rewards, log)
}
// Set result
output.setResult({
logs,
rewards,
errors,
})
return output.buildOutput()
} catch (error) {
log.error('Error in user code:', error)
throw error
}
}
```
## Transaction Entries On-Chain
Some projects prefer to host points onchain to generate transaction volume and decentralize points data. This function listens to transaction entries and mints/burns tokens based on account balance changes.
It can be adjusted to any token contract.
1. Click `Add New Function`
2. In the `Subscription` field, either select an existing Snag Subscription, or create a new one, as in the image below.

3. Finally, replace the `LOYALTY_CURRENCY_ID` with your loyalty currency ID and
the `ERC20_CONTRACT_ADDRESS` with your token contract address in the first lines.
4. Click `Save` and you're good to go.
### Function Code
```javascript mint-burn.js
const { encodeFunctionData } = require('viem')
// Replace with your contract address
const ERC20_CONTRACT_ADDRESS = '0x0000000000000000000000000000000000000000'
// Replace with your loyalty currency ID
const LOYALTY_CURRENCY_ID = 'YOUR_LOYALTY_CURRENCY_ID'
module.exports.handler = async (input, output) => {
let operations = []
// Parse input if it's a string
if (typeof input === 'string') {
try {
let parsed = JSON.parse(input)
if (typeof parsed === 'string') {
parsed = JSON.parse(parsed)
}
input = parsed
} catch (err) {
output.setResult({
message: 'Invalid JSON input',
error: err,
input: input,
operations,
})
return output.buildOutput()
}
}
if (!Array.isArray(input)) {
output.setResult({
message: 'Expected input to be an array of events',
input: input,
operations,
})
return output.buildOutput()
}
const mintABI = [
{
inputs: [
{ internalType: 'address', name: 'to', type: 'address' },
{ internalType: 'uint256', name: 'amount', type: 'uint256' },
],
name: 'mint',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
]
const burnABI = [
{
inputs: [
{ internalType: 'address', name: 'from', type: 'address' },
{ internalType: 'uint256', name: 'amount', type: 'uint256' },
],
name: 'burn',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
]
try {
for (const event of input) {
if (!event.data) continue
const dataItem = event.data
const tokenAmount = BigInt(dataItem.amount) * BigInt(10) ** BigInt(18)
// Replace with your loyalty currency ID
if (dataItem.loyaltyCurrencyId !== LOYALTY_CURRENCY_ID) {
continue
}
let operationType = null
if (dataItem.direction === 'credit') {
operationType = 'mint'
} else if (dataItem.direction === 'debit') {
operationType = 'burn'
} else {
continue
}
const walletAddress = dataItem.loyaltyAccount?.user?.walletAddress
if (!walletAddress) continue
let data
if (operationType === 'mint') {
data = encodeFunctionData({
abi: mintABI,
functionName: 'mint',
args: [walletAddress, tokenAmount.toString()],
})
} else if (operationType === 'burn') {
data = encodeFunctionData({
abi: burnABI,
functionName: 'burn',
args: [walletAddress, tokenAmount.toString()],
})
}
output.addTransaction({
to: ERC20_CONTRACT_ADDRESS,
data: data,
value: '0x0',
})
}
output.setResult({
message: 'Token transactions created.',
operations,
})
return output.buildOutput()
} catch (error) {
console.error('Error in user code:', error)
throw error
}
}
```
## DEX Trading Rewards
This function tracks and rewards users based on their trading volume, using Redis for persistence.
It is based on a subscription to a USDC based uniswap pool, tracking the `Swap` event.
Replace the constants in the first lines of the function with your actual values.
### Function Code
```javascript trading-rewards.js
const { Redis } = require('ioredis')
const axios = require('axios')
const LOYALTY_RULE_ID = 'YOUR_LOYALTY_RULE_ID'
const LOYALTY_API_KEY = 'YOUR_API_KEY'
const REDIS_URL = 'YOUR_REDIS_URL'
const VOLUME_THRESHOLD = 10 // $10 USD threshold
const redis = new Redis(REDIS_URL)
/**
* Mark loyalty rule as completed to reward user
*/
async function completeLoyaltyRule(walletAddress) {
if (!LOYALTY_API_KEY) {
throw new Error('LOYALTY_API_KEY is not defined')
}
await axios.post(
`https://admin.snagsolutions.io/api/loyalty/rules/${LOYALTY_RULE_ID}/complete`,
{
verifyOnly: 'false',
walletAddress: walletAddress,
},
{
headers: {
'Content-Type': 'application/json',
'X-API-KEY': LOYALTY_API_KEY,
},
}
)
}
module.exports.handler = async (input, output) => {
const operations = []
try {
operations.push('Starting handler execution: parsing input')
if (typeof input === 'string') {
let parsed = JSON.parse(input)
if (typeof parsed === 'string') parsed = JSON.parse(parsed)
input = parsed
}
if (!Array.isArray(input) || input.length === 0) {
output.setResult({ message: 'No event data provided', input, operations })
return output.buildOutput()
}
const event = input[0]
if (!event.decodedEvent || !event.decodedEvent.args) {
throw new Error('Event data missing decodedEvent.args')
}
const args = event.decodedEvent.args
// Process swap events (assuming token0 is USDC with 6 decimals)
if (args.hasOwnProperty('amount0')) {
const { sender, amount0 } = args
const traderWallet = sender
const tradeDollarValue = Math.abs(Number(amount0)) / 1e6
const redisVolumeKey = `${traderWallet}-swapVolume`
const redisRewardedKey = `${traderWallet}-swapRewarded`
const alreadyRewarded = await redis.get(redisRewardedKey)
if (alreadyRewarded) {
output.setResult({
message: `User ${traderWallet} has already been rewarded for swap volume.`,
operations,
})
return output.buildOutput()
}
const storedVolumeStr = await redis.get(redisVolumeKey)
const storedVolume = storedVolumeStr ? parseFloat(storedVolumeStr) : 0
const newVolume = storedVolume + tradeDollarValue
await redis.set(redisVolumeKey, newVolume.toString())
if (storedVolume < redisRewardedKey && newVolume >= VOLUME_THRESHOLD) {
// Complete loyalty rule when threshold is reached
await completeLoyaltyRule(traderWallet)
await redis.set(redisRewardedKey, 'true')
output.setResult({
message: `User ${traderWallet} rewarded for reaching $${VOLUME_THRESHOLD} swap volume.`,
cumulativeSwapVolume: newVolume,
operations,
})
return output.buildOutput()
}
output.setResult({
message: `User ${traderWallet} cumulative swap volume updated to $${newVolume.toFixed(2)}.`,
cumulativeSwapVolume: newVolume,
operations,
})
return output.buildOutput()
}
output.setResult({ message: 'Unknown event type', operations })
return output.buildOutput()
} catch (error) {
operations.push(`Error encountered: ${error.message}`)
console.error('Error in handler:', error)
output.setError(error.message)
output.setResult({ operations })
return output.buildOutput()
}
}
```
## Usage Notes
1. Replace placeholder values (marked with `YOUR_*`) with your specific parameters
2. Update Redis URLs with your instance details
3. Adjust reward multipliers and thresholds as needed
4. Test thoroughly in development before deploying to production
Remember to handle your API keys and sensitive data securely. Never commit
them directly in your code.
## Common Parameters to Replace
* `LOYALTY_RULE_ID`: Your specific loyalty rule identifier
* `REDIS_URL`: Your Redis instance connection string
* `ERC20_CONTRACT_ADDRESS`: The address of your token contract
* `VOLUME_THRESHOLD`: Minimum volume required for rewards
* `MULTIPLIER`: Reward calculation multiplier
These templates are starting points. You should modify them based on your
specific requirements and add appropriate error handling.
# Functions
Source: https://docs.snagsolutions.io/stratus/functions
Write and execute serverless JavaScript functions with Stratus
## Overview
Stratus functions enable developers to write and execute JavaScript functions in a serverless environment. These functions:
* Scale horizontally
* Run in isolated VMs
* Have web access for external integrations
* Support complex logic combinations
Functions can interact with external services, allowing you to integrate with your own database, subgraphs, and other services.
## Invocation Types
Execute functions on a cron schedule with minimum 1-minute resolution
Invoke functions via HTTP POST requests using API keys
Trigger functions automatically when subscribed events occur
### Schedule Invocation
While there's no maximum schedule limit, the minimum resolution is 1 minute. Schedules with smaller intervals will fail.
### Webhook Invocation
To invoke functions via webhook:
1. Create a Stratus-scoped API key in the admin panel
2. Use the unique webhook URL assigned to your function
```bash Webhook Example
curl --request POST \
--url https://admin.snagsolutions.io/api/stratus/functions//invoke \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: ' \
--data '{
"organizationId": "org-1234",
"websiteId": "site-5678",
"input": {
"foo": 123,
"bar": "example value"
}
}'
```
### Subscription Invocation
Functions linked to subscriptions execute automatically when subscription events fire. Unlike webhooks, subscription-based invocations receive a single payload per event.
## Writing Functions
### Basic Structure
All Stratus functions must follow these rules:
Only one handler function can be exported per file
Handlers must be asynchronous
Functions must accept `input` and `output` parameters
```javascript Basic Template
module.exports.handler = async (input, output) => {
// Your function logic here
};
```
### The Output Class
The `output` parameter provides methods for managing function results and actions:
Sets the function result data (called once before buildOutput)
```typescript
setResult(resultObject: Record): void
```
Logs a failure and stops future executions
```typescript
setError(error: string): void
```
Adds a transaction to the execution queue (requires relayer connection)
```typescript
addTransaction(tx: Pick): void
```
Finalizes and returns the function output (required)
```typescript
buildOutput(): Record
```
## Executing Transactions
To execute transactions, your function must be connected to a relayer in your account.
### Transaction Rules
* Maximum 500 transactions per function run
* Transactions execute in the order they're added
* All transactions use the connected relayer
## Approved Modules
Only pre-approved npm modules can be used in Stratus functions. Contact Snag Solutions if you need additional modules.
Currently approved modules:
* `axios`
* `lodash`
* `viem`
* `ioRedis`
## Example Function
```javascript
const axios = require('axios');
module.exports.handler = async (input, output) => {
try {
// Make an external API call
const response = await axios.get('https://api.example.com/data');
// Set the result
output.setResult({
data: response.data,
timestamp: Date.now()
});
// Add a transaction if needed
output.addTransaction({
to: '0x123...',
data: '0x456...',
value: '0'
});
// Return the built output
return output.buildOutput();
} catch (error) {
output.setError(`Function failed: ${error.message}`);
return output.buildOutput();
}
};
```
Contact Snag Solutions if you need access to additional npm modules for your Stratus functions.
# Relayers
Source: https://docs.snagsolutions.io/stratus/relayers
Secure private key management for blockchain transactions
# Relayers
Relayers are secure private keys managed by Snag Solutions that enable developers to sign messages and relay transactions on-chain. They are commonly used for:
* Creating gasless transactions
* Triggering admin actions
* Maintaining on-chain oracles
* And much more
Snag Solutions handles both key security and failed transaction management.
## Creating a Relayer
1. Navigate to the Relayers section
2. Provide a name for your relayer
3. Select a blockchain network from the dropdown
4. Click "Create Relayer"
The private key is generated and stored exclusively within AWS KMS (Key Management Service). All signing operations take place inside a secure signing enclave.
## Funding Your Relayer
To pay for transactions, you'll need to deposit funds into your relayer:
1. Copy your relayer's address
2. Send funds from any wallet to this address
3. Ensure you're on the same blockchain network
API access for relayer operations is currently in development. We expect to provide full API access to all partners by the end of Q1 2025.
## Withdrawing Funds
To withdraw funds from your relayer:
1. Click the "Withdraw" button
2. Enter the destination address
3. Specify the amount to withdraw
All on-chain transactions are final. Triple-check the withdrawal address before confirming the transaction.
## Security
Our relayer system prioritizes security through:
* AWS KMS integration
* Secure signing enclaves
* Automated transaction monitoring
* Failed transaction handling
# Stratus overview
Source: https://docs.snagsolutions.io/stratus/stratus-overview

Stratus is Snag’s cloud-native solution designed to provide complete flexibility for building complex rule logic and on-chain operations. With Stratus, you can seamlessly integrate one or all three of its core services—**Functions**, **Relayers**, and **Subscriptions**—to develop the precise functionality you need. Each service is fully modular, so they can be used independently or combined within a function to suit your application’s unique requirements.
# Subscriptions
Source: https://docs.snagsolutions.io/stratus/subscriptions
Managing Stratus Subscription
## Overview
Subscriptions empower developers to receive real-time updates triggered by smart contract events or internal loyalty actions. These notifications can either be sent to a webhook endpoint or used to automatically invoke functions.
## Event Types
### Blockchain Events
Blockchain events notify you whenever a smart contract emits an event or a function is called. These events track on-chain state with minimal latency (typically one block), making them ideal for real-time applications.
Start by adding the desired smart contract to your admin panel.
Choose "EVENT" from the subscription options. All available events for the contract will be populated automatically.
### Blockchain Function Events
The process mirrors blockchain events with a slight variation:
Ensure the contract is registered in your admin panel.
Choose "FUNCTION" after adding the contract. All smart contract functions will be listed automatically.
### Snag Events
Snag events allow subscriptions to internal platform actions. These events relate to loyalty account activities and may have a slight delay (up to 30 seconds) after the action is recorded.
## Event Types Reference
Triggered when a user's account balance is updated
Emitted when a user's profile is created or updated
Emitted for token-related activities
### LoyaltyTransactionEntry
```json Sample Payload
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"loyaltyAccountId": "account-uuid-001",
"loyaltyTransactionId": "transaction-uuid-001",
"loyaltyCurrencyId": "currency-uuid-001",
"amount": "100.00",
"direction": "credit",
"metadata": {},
"loyaltyAccountStartAmount": "500.00",
"loyaltyAccountEndAmount": "600.00",
"loyaltyAccountLockVersion": 1,
"hideInUi": false,
"idempotencyKey": "unique-key-001",
"idempotencyKeyExpiresAt": "2025-03-05T00:00:00Z",
"dismissedInUi": false,
"organizationId": "org-uuid-001",
"websiteId": "website-uuid-001",
"createdAt": "2025-03-04T12:00:00Z",
"updatedAt": "2025-03-04T12:00:00Z",
"loyaltyAccount": {
"user": {
"walletAddress": "0x123456789abcdef"
}
},
"loyaltyTransaction": {
"loyaltyRule": {
"id": "rule-uuid-001"
}
}
}
```
### UserMetadata
```json Sample Payload
{
"id": "234e4567-e89b-12d3-a456-426614174001",
"userId": "user-uuid-001",
"isBlocked": false,
"websiteId": "website-uuid-001",
"organizationId": "org-uuid-001",
"emailAddress": "user@example.com",
"twitterUser": "userTwitter",
"twitterUserId": "twitter-001",
"twitterUserFollowersCount": 150,
"twitterVerifiedAt": "2025-03-04T10:00:00Z",
"discordUser": "userDiscord",
"discordUserId": "discord-001",
"discordVerifiedAt": "2025-03-04T10:05:00Z",
"instagramUser": "userInstagram",
"instagramUserId": "insta-001",
"instagramVerifiedAt": "2025-03-04T10:10:00Z",
"logoUrl": "https://example.com/logo.png",
"displayName": "User Display Name",
"location": "New York, USA",
"bio": "Sample bio text.",
"portfolioUrl": "https://example.com/portfolio",
"createdAt": "2025-03-04T09:00:00Z",
"updatedAt": "2025-03-04T11:00:00Z",
"meta": {}
}
```
### UserTokenActivity
```json Sample Payload
{
"id": "345e4567-e89b-12d3-a456-426614174002",
"collectionId": "collection-001",
"walletAddress": "0xabcdef1234567890",
"tokenId": "token-001",
"like": true,
"views": 1000,
"createdAt": "2025-03-04T08:00:00Z",
"updatedAt": "2025-03-04T08:30:00Z",
"userId": "user-uuid-001",
"organizationId": "org-uuid-001",
"websiteId": "website-uuid-001",
"websiteCollectionId": "website-collection-001"
}
```
# Function syntax
Source: https://docs.snagsolutions.io/stratus/syntax
Learn how to create and validate Stratus functions with proper syntax, module restrictions, and best practices
## Overview
To maintain consistency and security, all Stratus functions are validated before they are saved. This guide explains the required syntax, module restrictions, and best practices to help you create functions that pass validation.
## Module Export & Handler Function
### Single Handler Export
Your code must export exactly one handler function.
Exporting multiple handler definitions or not exporting a handler at all will cause validation to fail.
```javascript
// ❌ Incorrect – no exported handler:
const handler = async (input, output) => { ... };
```
### Proper Export Format
Always export your handler as a property of `module.exports`.
```javascript
// ✅ Correct:
module.exports.handler = async (input, output) => {
// Function body...
};
```
The exported handler must be a function. Assigning non-function values (e.g., a string) will trigger an error.
## Handler Function Parameters & Behavior
### Parameter Requirements
The handler function must accept exactly two parameters:
* `input` – holds input data
* `output` – provides methods for setting and building the function's output
```javascript
module.exports.handler = async (input, output) => { ... };
```
### Using output.setResult
Inside your handler, you must call `output.setResult` to set the result object.
```javascript
// ❌ Incorrect:
module.exports.handler = async (input, output) => {
// Missing call to output.setResult
return output.buildOutput();
};
```
### Calling output.buildOutput()
The handler must return the result of `output.buildOutput()`. Omitting this call is not allowed.
```javascript
// ✅ Correct:
module.exports.handler = async (input, output) => {
output.setResult({ message: "Hello" });
return output.buildOutput();
};
```
If the handler does not accept exactly two parameters, validation will fail with a message similar to:
"The 'handler' function must accept exactly two parameters: 'input' and 'output'."
## Module Import Requirements
### Allowed Modules
You may include external modules via `require()`, but only approved packages are allowed:
* `axios`
* `lodash`
* `viem` and its approved subpath `viem/chains`
```javascript
const axios = require('axios');
```
### Disallowed Modules
The following are not allowed:
* Modules not on the approved list (e.g., Node's `fs`)
* Unapproved subpaths from approved packages
* Dynamic requires (using variables for module names)
```javascript
// ❌ Incorrect:
const mod = 'axios';
const axios = require(mod); // Dynamic require not allowed
```
### Extra Exports
Adding extra properties to `module.exports` (aside from the handler) is allowed and will not affect validation:
```javascript
module.exports.extra = "some extra value";
module.exports.handler = async (input, output) => {
output.setResult({ message: "Hello" });
return output.buildOutput();
};
```
## JavaScript Syntax
### Valid JavaScript
Your code must be syntactically valid JavaScript. Common syntax errors include:
* Missing closing braces
* Unmatched parentheses
* Invalid syntax
```javascript
// ❌ Example of Syntax Error:
module.exports.handler = async (input, output) => {
output.setResult({ message: "Hello" })
return output.buildOutput(; // Error: Unmatched parenthesis
};
```
## Common Validation Error Messages
You may encounter the following validation errors:
```bash Common Errors
"Module 'unknown/chains' is not approved"
"User code must export exactly one handler function"
"Invalid dynamic require detected"
"Failed to validate user code: ..."
"The 'handler' property must be assigned to a function"
"Multiple handler definitions found"
"The 'handler' function must accept exactly two parameters: 'input' and 'output'"
"The 'handler' function must use output.setResult"
"The 'handler' function must call output.buildOutput()"
```
## Examples
### Valid Stratus Function with External Module
```javascript
const axios = require('axios');
module.exports.handler = async (input, output) => {
const response = await axios.get("https://example.com");
output.setResult({ data: response.data });
return output.buildOutput();
};
```
### Valid Function Without External Modules
```javascript
module.exports.handler = async (input, output) => {
output.setResult({ message: "Hello World!" });
return output.buildOutput();
};
```
### Common Mistakes
```javascript
// ❌ Incorrect: Multiple handler definitions
module.exports.handler = async (input, output) => { ... };
module.exports.handler = async (input, output) => { ... };
```
```javascript
// ❌ Incorrect: Missing output.setResult
module.exports.handler = async (input, output) => {
return output.buildOutput();
};
```
```javascript
// ❌ Incorrect: Dynamic require
const mod = 'axios';
const axios = require(mod);
```
## Summary
To ensure your Stratus function passes syntax validation:
* Export one handler function using the correct module export syntax
* Ensure the handler is asynchronous and accepts exactly two parameters: `input` and `output`
* Call both `output.setResult` and `output.buildOutput()` within your handler
* Import only approved modules using string literals (no dynamic requires)
* Write valid JavaScript with correct syntax
# Webhooks
Source: https://docs.snagsolutions.io/stratus/webhooks
Ingesting and validating Webhooks
## Overview
Stratus subscriptions deliver events via webhooks, enabling your systems to respond immediately to key events. This guide explains how to set up and validate webhook notifications.
## Getting Started
Toggle webhooks within your subscription settings
Provide the URL where your system will accept POST requests
Save the `Signing Key` from your subscription settings for payload validation
## Implementation Guide
### Webhook Validation
Each webhook payload includes a signature header (`x-signature`) that should be validated to ensure authenticity.
```javascript Next.js Example
// https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries
export const config = {
api: {
bodyParser: false,
},
}
export default async function handler(req, res) {
try {
if (req.method !== 'POST') {
res.setHeader('Allow', 'POST')
return res.status(405).json({ error: 'Method Not Allowed' })
}
const rawBody = (await getRawBody(req)).toString('utf-8')
const signature = req.headers['x-signature']
if (!signature) {
console.error('Missing signature')
return res.status(400).json({ error: 'Missing signature' })
}
const secret = process.env.WEBHOOK_SECRET
if (!secret) {
console.error('Server misconfiguration: Missing WEBHOOK_SECRET')
return res
.status(500)
.json({ error: 'Server misconfiguration: Missing WEBHOOK_SECRET' })
}
const computedSignature = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex')
if (
!crypto.timingSafeEqual(
new Uint8Array(Buffer.from(computedSignature)),
new Uint8Array(Buffer.from(signature))
)
) {
console.error('Invalid signature')
return res.status(401).json({ error: 'Invalid signature' })
}
const payload = JSON.parse(rawBody)
payload.forEach((event) => {
console.log('Received event:', event)
})
res.status(200).json({ status: 'Webhook processed successfully' })
} catch (error) {
console.error('Webhook processing error:', error)
res.status(500).json({ error: 'Internal Server Error' })
}
}
```
## Important Considerations
Multiple events may be batched into a single webhook payload
Failed webhooks are retried exponentially up to five times
Always validate webhook signatures using your WEBHOOK\_SECRET
Never expose your WEBHOOK\_SECRET in client-side code or public repositories. Always store it securely in environment variables.
# User authentication overview
Source: https://docs.snagsolutions.io/user-auth/auth-overview
Snag supports multiple authentication providers, allowing users to log in via wallets, email and social accounts. Our team will configure authentication for your platform based on the details you provide.

## Supported authentication providers
* [Dynamic (EVM, Solana, SUI)](/user-auth/dynamic)
* [Thirdweb](/user-auth/thirdweb)
* [Privy](/user-auth/privy)
* [Immutable Passport](/user-auth/immutable-passport)
* [Sequence Wallet](/user-auth/sequence)
* [Auth0](/user-auth/auth0)
## How it works
Select one or more authentication providers that best fit your platform.
Each provider requires specific keys and configurations. Refer to the
separate provider pages for details on what to provide.
Once you have all the required details, share them with us. Our team will
set up authentication on your behalf.
# Auth0
Source: https://docs.snagsolutions.io/user-auth/auth0

## Required information:
* Client ID
* Issuer Link
* Sign-in button text (optional)
## How to find these credentials:
1. Create an application in [Auth0](https://auth0.com/).
2. Copy your **Client ID** and **Issuer Link**.
3. Send these details to us.
# Dynamic
Source: https://docs.snagsolutions.io/user-auth/dynamic

## Required information:
* Dynamic Environment ID
* API Base URL
## How to find these credentials:
1. Sign up for [Dynamic](https://dynamic.xyz/) and log into your developer dashboard.
2. Copy your **Environment ID**.
3. If you have the cookie based auth enabled in dynamic, you will need to provide the **API Base URL** as well.
You will be able to find it in [https://app.dynamic.xyz/dashboard/developer/domains](https://app.dynamic.xyz/dashboard/developer/domains).
The api base url will be in the following format [https://cookie-based-auth-domain/api/v0](https://cookie-based-auth-domain/api/v0)
4. Send these values to us.
# Immutable Passport
Source: https://docs.snagsolutions.io/user-auth/immutable

## Required Information:
* Client ID
* Publishable Key
## How to find these credentials:
1. Log into your [Immutable Hub]().
2. Copy your **Client ID** and **Publishable Key**.
3. Add the following redirect URLs to your Immutable dashboard:
* `https:///immutable/redirect`
* [`https://snag-web.onrender.com/immutable/redirect`](https://snag-web.onrender.com/immutable/redirect)
4. Send these details to us.
# Privy
Source: https://docs.snagsolutions.io/user-auth/privy

## Required Information:
* Client ID
* App ID
## How to find these credentials:
1. Sign up for [Privy](https://privy.io/) and access your developer dashboard.
2. Copy your **Client ID** and **App ID**.
3. Send these values to us.
# Sequence Wallet
Source: https://docs.snagsolutions.io/user-auth/sequence

## Required Information:
* Sequence Project ID (Access Key)
* WAAS Configuration Key
* Google OAuth Client ID
* Client Secret
* WalletConnect Project ID
* Network (e.g. Arbitrum Sepolia)
## How to find these credentials:
1. Configure Google OAuth in the **Google Developer Console**:
* Create an OAuth application in the **Google Developer Console**.
* Ensure you allow `https:///`
2. Sign up for [WalletConnect](https://walletconnect.com/) and retrieve your **Project ID**.
3. Sign up for [Sequence](https://sequence.xyz/) and access your project dashboard.
4. Retrieve your **Project ID, WAAS Configuration Key**.
5. Deploy the parent contract in the Sequence **build dashboard**.
6. Send these details (**Project ID, WAAS Configuration Key, Google OAuth Client ID, Client Secret, WalletConnect Project ID**) to us.
# Thirdweb
Source: https://docs.snagsolutions.io/user-auth/thirdweb

## Required information:
* Client ID
* Sign-in button text (optional)
## How to find these credentials:
1. Go to the [**Thirdweb Dashboard**](https://playground.thirdweb.com/connect/sign-in/button).
2. Generate a **Client ID** for your application.
3. Send this Client ID to us.
# Welcome to Snag Docs
Source: https://docs.snagsolutions.io/welcome
Snag is the leading onchain loyalty platform, helping Web3 brands incentivize engagement, automate rewards and track user contributions. Power growth with customizable point-based programs and integrated marketplace features.
## Introduction
This documentation covers everything you need to integrate Snag’s loyalty and marketplace solutions. Set up rewards, manage authentication, and customize your ecosystem with our API and SDKs.
## Getting Started
Your first steps with Snag.
Comprehensive guides to seamlessly integrate our APIs.
Leveraging our SDK for typesafe interaction with our APIs.
Configure reward programs & automate incentives.
Set up a project-branded NFT trading experience.
## Advanced Features
Powerful tools for scaling.
Execute advanced reward logic with Snag’s onchain cloud.
Enable seamless wallet & social logins via different providers.
## Common Docs
* [Available loyalty rules](/loyalty/available-loyalty-rules)
* [Rules configuration](/loyalty/rules-configuration)
* [Create your first rule](/loyalty/create-your-first-rule)
* [User profiles](setup/user-profiles)
* [Rewards shop](create/rewards-shop)
## Need help?
Visit our [contact us](https://www.snagsolutions.io/contact) page to connect with our team 📨