Publisher API

Integrate with Revifly to discover offers and generate unique vouchers for your audience.

Authentication

Every request requires your API credentials in headers. These are issued by Revifly when your account is approved.

X-API-Key: your_api_key
X-API-Secret: your_api_secret

Credentials are available in your Publisher Portal. Never expose the secret client-side.

Base URL

https://revifly.com/api/v1/publisher/

Mobile hash — user identity

Revifly identifies users via a SHA-256 hash of their mobile number in E.164 format. You compute this hash on your server and pass it as customer_identifier. Revifly stores it as-is — it is never hashed a second time and the raw mobile number never reaches our servers.

Algorithm
1. Take the user's mobile number
2. Strip all non-digit characters ( +  spaces  -  parentheses )
3. Include the full country code → result is E.164 digits
      India : "919876543210"
      UK    : "447911123456"
      US    : "15551234567"
4. hash = lowercase( SHA-256( e164_digit_string ) )
Code examples
// JavaScript (Node.js / browser Web Crypto)
async function mobileHash(mobile) {
    const digits = mobile.replace(/\D/g, '');
    const buf = await crypto.subtle.digest(
        'SHA-256',
        new TextEncoder().encode(digits)
    );
    return Array.from(new Uint8Array(buf))
        .map(b => b.toString(16).padStart(2, '0')).join('');
}

// Python
import hashlib
def mobile_hash(mobile: str) -> str:
    digits = ''.join(c for c in mobile if c.isdigit())
    return hashlib.sha256(digits.encode()).hexdigest()

// PHP
function mobileHash(string $mobile): string {
    $digits = preg_replace('/\D/', '', $mobile);
    return hash('sha256', $digits);
}
Test vector
Input  : "919876543210"          (Indian number with country code, digits only)
SHA-256: 9b4fc4c2...             (verify: echo -n "919876543210" | sha256sum)
Stability warning. This hash is the user's permanent identity in Revifly — it drives deduplication, active-cap enforcement, and voucher wallet history. If you change the normalization (e.g. add/remove the country code, change the input string in any way) the same user produces a different hash and loses all history. Implement once, freeze the algorithm.

GET get_offers

Fetch the catalogue of active offers you can promote. Cache this response — it changes infrequently.

Endpoint: GET /api/v1/publisher/get_offers

Query parameters
ParamTypeDefaultDescription
brand_idintFilter to a single brand
qstringSearch in title, description, brand name
limitint50Results per page (max 100)
offsetint0Pagination offset
Response
{
  "status": "success",
  "data": {
    "publisher": { "publisher_id": 1, "publisher_name": "Acme App" },
    "pagination": { "limit": 50, "offset": 0, "count": 12 },
    "offers": [
      {
        "offer_id": 42,
        "brand_id": 7,
        "brand_name": "FashionBrand",
        "title": "20% off your first order",
        "description": "Exclusive discount for new customers.",
        "category": "Fashion",
        "discount_type": "percentage",
        "discount_value": 20.0,
        "min_purchase_amount": 500.0,
        "currency": "INR",
        "start_date": "2026-01-01",
        "end_date": "2026-12-31",
        "status": "active",
        "terms_and_conditions": "Valid on orders of ₹500 or more. Valid until 31 Dec 2026.",
        "image_url": "https://...",
        "brand_logo_url": "https://...",
        "shop_url": "https://fashionbrand.myshopify.com"
      }
    ]
  }
}

GET get_offer_detail impression tracking

Fetch a single offer and record an impression. Call this when you are about to show a specific offer to a specific user — it logs one impression event for brand reporting.

Endpoint: GET /api/v1/publisher/get_offer_detail?offer_id={id}

Query parameters
ParamTypeRequiredDescription
offer_idintYesOffer to fetch and log
user_hashstring (64 hex)NoMobile hash of the user being shown the offer
sub_sourcestringNoAttribution tag, max 100 chars
Response
{
  "status": "success",
  "data": {
    "offer": { /* same fields as get_offers */ }
  }
}

Returns OFFER_NOT_FOUND (404) if the offer is inactive, expired, or not in your catalogue. Rate limit: 200 req/min per publisher.

POST generate_voucher

Generate a unique voucher code for an offer. The voucher is created in Shopify and is ready to use at checkout immediately.

Endpoint: POST /api/v1/publisher/generate_voucher
Content-Type: application/json

Request body
FieldTypeRequiredDescription
offer_idintYesOffer to generate a voucher for
customer_identifierstring (64 hex)RecommendedMobile hash of the user (see Mobile hash above). Required for deduplication and active-cap enforcement.
quantityintNo1–50, default 1
sub_sourcestringNoAttribution tag, max 100 chars (e.g. campaign name, placement)
custom_codestringNoRequest a specific voucher code string
Example request
POST https://revifly.com/api/v1/publisher/generate_voucher
Content-Type: application/json
X-API-Key: your_api_key
X-API-Secret: your_api_secret

{
  "offer_id": 42,
  "customer_identifier": "9b4fc4c2e7c5a2a3e1e9f98b05e3f5b1...",
  "sub_source": "home_feed"
}
Success response
{
  "status": "success",
  "data": {
    "voucher_code": "RV-ABC123XYZ",
    "voucher_id": 456,
    "offer_id": 42,
    "offer_title": "20% off your first order",
    "brand_name": "FashionBrand",
    "expiry": "2026-12-31 23:59:59",
    "image_url": "https://...",
    "checkout_url": "https://fashionbrand.myshopify.com/discount/RV-ABC123XYZ"
  }
}

checkout_url pre-applies the voucher at checkout — link users directly to it to reduce redemption friction.

Active-voucher cap

Each publisher has a configurable cap on how many active (generated but not yet used, unexpired) vouchers a single user can hold simultaneously. The default is 10. If the user is at their cap you will receive:

HTTP 429
{
  "status": "error",
  "message": "User has reached the active voucher limit for this publisher",
  "data": { "error_code": "USER_ACTIVE_VOUCHER_LIMIT" }
}

This is an anti-abuse guard. Contact Revifly support to adjust the cap for your account.

GET user_vouchers wallet API

Fetch all vouchers belonging to a user (identified by their mobile hash) for your publisher account. Use this to build a "My Vouchers" view within your app.

Endpoint: GET /api/v1/publisher/user_vouchers

Query parameters
ParamTypeRequiredDescription
user_hashstring (64 hex)YesMobile hash of the user
statusstringNoall (default), active, used, or expired
limitintNoMax results (default 20, max 100)
offsetintNoPagination offset
Response
{
  "status": "success",
  "data": {
    "user_hash": "9b4fc4c2...",
    "pagination": { "limit": 20, "offset": 0, "count": 3 },
    "vouchers": [
      {
        "voucher_id": 456,
        "voucher_code": "RV-ABC123XYZ",
        "offer_id": 42,
        "offer_title": "20% off your first order",
        "brand_name": "FashionBrand",
        "discount_type": "percentage",
        "discount_value": 20.0,
        "currency": "INR",
        "status": "active",
        "validity": "Valid until 31 Dec 2026",
        "expiry_date": "2026-12-31",
        "created_at": "2026-05-18 10:00:00"
      }
    ]
  }
}

Only returns vouchers generated by your publisher account. Rate limit: 100 req/min per publisher.

Hosted wallet page zero build

Instead of building a voucher wallet UI yourself, you can link users to Revifly's hosted wallet page. It shows their available and used vouchers with copy buttons and shop links, served from Revifly's domain.

URL format
https://revifly.com/wallet/?pub={your_publisher_code}&uhash={user_mobile_hash}
Example link
# Compute the user's hash and build the URL
user_hash = mobileHash("919876543210")
wallet_url = "https://revifly.com/wallet/?pub=mypublishercode&uhash=" + user_hash
  • No authentication required — the hash itself acts as the key
  • The page is noindex — not indexed by search engines
  • Shows vouchers for your publisher account only
  • Rate limited: 60 requests/min per publisher+hash+IP

Error codes

CodeHTTPMeaning
PUBLISHER_INVALID401API key or secret incorrect
VALIDATION_ERROR400Missing or malformed required field
INVALID_CUSTOMER_IDENTIFIER400customer_identifier is not a valid 64-char hex mobile hash
INVALID_USER_HASH400user_hash is not a valid 64-char hex mobile hash
OFFER_NOT_FOUND404Offer does not exist or is not in your catalogue
OFFER_NOT_ACTIVE403Offer exists but is not currently active
OFFER_DATE_INVALID403Offer is outside its valid date range
BRAND_CAMPAIGN_PAUSED403Brand has paused the campaign
QUANTITY_LIMIT_EXCEEDED400Requested quantity is above the max (50)
PUBLISHER_DAILY_LIMIT_REACHED429Publisher daily voucher cap reached
USER_ACTIVE_VOUCHER_LIMIT429User already holds the maximum active vouchers for this publisher
USER_DAILY_LIMIT_REACHED429User has generated too many vouchers in the past 24 hours
DUPLICATE_VOUCHER409User already has a voucher for this offer (one-per-customer offer)
VOUCHER_CREATION_FAILED500Voucher creation failed on Revifly's side — retry
RATE_LIMIT429API rate limit exceeded
INTERNAL_ERROR500Unexpected server error — retry

Integration models

Four ways to distribute Revifly offers — choose based on your platform's capabilities.

ModelHow it worksBest for
1 — Landing page Link users to /v/?o={offer_id}&pub={code}. Revifly collects the mobile, generates and displays the voucher. Any publisher — zero integration effort
2 — Direct API Call get_offer_detail (impression), then generate_voucher with the user's mobile hash. Display the voucher code in your own UI. Apps with a known logged-in user
3 — Campaign token Generate a single-use token via the portal. Link user to /c/{token}. User picks an offer; Revifly generates the voucher. SMS, email, or push campaigns to a specific user
4 — Feed sync Pull the full offer catalogue via get_offers on a schedule. Render offers in your platform; link click-throughs to Model 1 or use Model 2 for generation. Aggregators, loyalty portals with their own UI