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.

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:

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 === "success") {
          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()
}