Developer API and webhooks
Connect your own systems (a CRM, an ERP, your back office) to Vikalp Omni. Read your Omni Pass members, reviews, wishlists and referrals; add and take Omni Pass tokens; publish and hide reviews; and get a signed message the moment something changes. On the Pro and Max plans.
Keys
In Vikalp Omni, open Settings → Developers and create a key. Pick Read only, or Read and change for keys that add tokens or publish reviews. The key is shown once; keep it secret, like a password. Only the store owner and team admins can create keys.
Send the key with every call:
curl https://api.vikalpomni.com/api/v1/omni-pass/members/7012345678901 \
-H "Authorization: Bearer vko_…"
Limits
| Pro | Max | |
|---|---|---|
| API calls a minute | 300 | 600 |
| API calls a month | 2,000,000 | Unlimited |
| Webhook addresses | 10 | 25 |
| Webhook messages a month | 1,000,000 | Unlimited |
Every answer says how many calls are left this minute (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset in seconds). Over the limit, the answer is 429: wait and try again. Monthly limits start again on the 1st (UTC).
Calls
All addresses start with https://api.vikalpomni.com/api/v1. Answers are JSON. Customer ids are Shopify’s (digits, as text); times are ISO 8601 in UTC; credits are in the smallest unit of your currency (cents, paise).
| Method | Address | What it does |
|---|---|---|
GET | /shop | Your store and its API limits |
GET | /omni-pass/tiers | Your Omni Pass tiers |
GET | /omni-pass/members | Members, a page at a time (filters: tier, updated_since) |
GET | /omni-pass/members/{customer_id} | One member: tokens, credits, tier |
GET | /omni-pass/members/{customer_id}/activity | Every change to a member’s tokens and credits |
POST | /omni-pass/members/{customer_id}/tokens | Add tokens (positive amount) or take them (negative), with a reason |
GET | /reviews | Reviews (filters: status, kind, product_id, customer_id, created_since) |
GET | /reviews/{id} | One review |
POST | /reviews/{id}/publish | Show a review on your store |
POST | /reviews/{id}/hide | Take a review off your store |
GET | /wishlist/items | Saved items (filters: customer_id, product_id, added_since) |
GET | /referrals | Referrals (filters: status, referrer_customer_id, created_since) |
GET | /referrals/{id} | One referral |
GET | /referrals/codes/{customer_id} | A customer’s referral code and its clicks |
Lists
Lists come a page at a time: ?page=1&limit=50 (up to 100). The answer is { "data": [...], "page": 1, "has_more": true }.
Adding and taking tokens
curl -X POST https://api.vikalpomni.com/api/v1/omni-pass/members/7012345678901/tokens \
-H "Authorization: Bearer vko_…" -H "Content-Type: application/json" \
-d '{"amount": 200, "reason": "Joined our events club", "idempotency_key": "club-7012345678901"}'
A negative amount takes tokens; a member can’t go below zero. Send an idempotency_key so a retried call changes nothing the second time. Customers who aren’t members yet join.
Errors
Errors are { "error": "…", "code": "…" } with the usual status: 400 something in the call is wrong, 401 no working key, 402 the plan doesn’t include the API, 403 a read-only key tried to change something, 404 not found, 409 not enough tokens, 429 over a limit.
Webhooks
In Settings → Developers, add an address (it must start with https://) and pick its events. We send each event as a POST with a JSON body:
{ "id": "…", "event": "omni_pass.balance_changed", "created_at": "2026-10-20T09:30:00.000Z",
"shop": "yourstore.myshopify.com", "data": { … } }
| Event | When |
|---|---|
omni_pass.balance_changed | Omni Pass tokens or credits added or taken |
omni_pass.tier_changed | An Omni Pass member moved to another tier |
review.created | A new review arrived |
referral.completed | A referral was completed and rewarded |
Answer with any 2xx status within 10 seconds. Otherwise we try again 10 times over about 3 hours. After 10 messages in a row aren’t delivered, the address is paused and Settings → Developers shows why; turn it on again once it’s fixed. The same event can arrive twice: use its id to skip repeats.
Checking the signature
Each message has X-Omni-Signature: t=<unix seconds>,v1=<signature>: an HMAC-SHA256 of <t>.<raw body> with the address’s signing secret (in Settings → Developers). Check it before trusting a message:
import { createHmac, timingSafeEqual } from 'node:crypto';
// header: the X-Omni-Signature header; body: the raw request body (a string)
function fromVikalpOmni(header, body, secret) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const expected = createHmac('sha256', secret).update(`${parts.t}.${body}`).digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return fresh && parts.v1?.length === expected.length && timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}
Questions
Email support@vikalpomni.com with “Developer API” in the subject.