@raba7ni/raba7ni
v1.0.8
Published
Official SDK for the Raba7ni Platform Developer API
Downloads
927
Readme
@raba7ni/raba7ni
Official TypeScript SDK for the Raba7ni Loyalty Platform Developer API.
Installation
npm install @raba7ni/raba7niQuick Start
import { Raba7niSDK } from "@raba7ni/raba7ni";
const sdk = new Raba7niSDK({
appId: "app_your_app_id",
apiKey: "dev_your_api_key",
});
// Test connection
const scopes = await sdk.testConnection();
console.log("Connected! Scopes:", scopes.scopes);
// Validate a member
const result = await sdk.validateMember(5, "+1234567890");
console.log("Is member:", result.is_member);Configuration
| Option | Type | Default | Description |
| ------------ | -------- | ------------------------- | ----------------------------------- |
| appId | string | required | Application ID (starts with app_) |
| apiKey | string | required | API Key (starts with dev_) |
| baseUrl | string | https://app.raba7ni.com | API base URL |
| locale | string | en-us | Locale for responses |
| timeout | number | 30000 | Request timeout (ms) |
| maxRetries | number | 3 | Max retry attempts |
| retryDelay | number | 1000 | Initial retry delay (ms) |
const sdk = new Raba7niSDK({
appId: "app_...",
apiKey: "dev_...",
timeout: 60000, // 60 seconds
maxRetries: 5,
});API Reference
Connection & Scopes
testConnection()
Test API connection and get available scopes.
const result = await sdk.testConnection();
// { scopes: ['members:read', 'members:write', ...], application: { id, name } }getWebhookEvents()
Get list of available webhook events.
const events = await sdk.getWebhookEvents();Member APIs
validateMember(cardId, phoneNumber, options?)
Check if a phone number is a registered member.
const result = await sdk.validateMember(5, "+1234567890", {
include_member_data: true,
});
if (result.is_member) {
console.log("Member:", result.member);
}getMemberDetails(cardId, phoneNumber)
Get detailed member information.
[!CAUTION] > Backend/Staff Use Only - This endpoint is designed for store owner/staff backend systems (POS, admin dashboards). It should NOT be exposed to customer-facing applications as a "login" method. Anyone knowing a phone number could access member data without verification.
For customer-facing apps, use
requestMemberOTP()+ OTP verification before showing member data. See Member Authentication below.
// Staff/Admin lookup (backend only)
const details = await sdk.getMemberDetails(5, "+1234567890");
console.log("Points:", details.card_relationship.points);requestMemberOTP(email, cardId)
Request OTP for new member registration.
const otp = await sdk.requestMemberOTP("[email protected]", 5);
if (otp.member_exists) {
console.log("Member already registered");
} else {
console.log("OTP sent, expires at:", otp.expires_at);
}findOrCreateMember(request)
Find existing member or create new one. Optionally create order and award points.
[!NOTE] Phone behavior:
- New members:
phone_numberis required along withverification_code- Existing members:
phone_numberis optional - if provided and member has no phone, it will be updated- Response includes
phone_updated: truewhen an existing member's phone was added
// Basic usage - find or create member
const result = await sdk.findOrCreateMember({
card_id: 5,
name: "John Doe",
email: "[email protected]",
phone_number: "+1234567890", // Required for NEW members only
verification_code: "123456", // Required for NEW members only
});
// With order and points
const result = await sdk.findOrCreateMember({
card_id: 5,
name: "John Doe",
email: "[email protected]",
phone_number: "+1234567890",
create_order: true,
order: {
award_points: true,
total_amount: 50.0,
items: [
{ name: "Coffee", amount: 15.0 },
{ name: "Sandwich", amount: 35.0 },
],
},
});
console.log("Is new member:", result.is_new);
console.log("Phone updated:", result.phone_updated); // true if missing phone was added
console.log("Points awarded:", result.transaction?.points);Member Authentication for Customer Apps
When building customer-facing apps (e-commerce, mobile apps, customer portals), never use getMemberDetails() as a login method. Instead, implement proper OTP-based authentication:
// Step 1: Check if member exists and send OTP
async function initiateLogin(email: string, cardId: number) {
const otp = await sdk.requestMemberOTP(email, cardId);
if (otp.member_exists) {
// OTP sent to existing member's email
return { needsOTP: true, email };
} else {
// New member - OTP sent for registration
return { needsOTP: true, isNew: true, email };
}
}
// Step 2: Verify OTP and get/create member
async function verifyLoginOTP(
email: string,
otp: string,
cardId: number,
memberData?: { name: string; phone: string }
) {
// For existing members: findOrCreateMember finds by email
// For new members: provide name + phone for registration
const result = await sdk.findOrCreateMember({
card_id: cardId,
email,
verification_code: otp,
name: memberData?.name, // Required for new members
phone_number: memberData?.phone, // Required for new, optional for existing
});
// If member existed without phone and we provided one
if (result.phone_updated) {
console.log("Member phone was updated");
}
// Now safe to show member data - they verified ownership
return result.member;
}[!IMPORTANT] The
verification_codeparameter ensures the person requesting data actually owns the email address. Without this, anyone could query member data just by knowing a phone number.
Card APIs
listCards()
Get all loyalty cards accessible by your API key.
const { cards, total } = await sdk.listCards();
cards.forEach((card) => console.log(card.name));getCardInfo(cardId)
Get details about a specific card.
const card = await sdk.getCardInfo(5);
console.log("Points per currency:", card.points_per_currency);listCardRewards(cardId)
Get available rewards for a card.
const { rewards } = await sdk.listCardRewards(5);
rewards.forEach((reward) => {
console.log(`${reward.name}: ${reward.points} points`);
});Claim Request APIs
listClaimRequests(cardId, status?)
Get claim requests for a card.
// All claims
const { claim_requests } = await sdk.listClaimRequests(5);
// Filtered by status
const pending = await sdk.listClaimRequests(5, "pending");requestClaimOTP(memberEmail, cardId, rewardId?)
Request OTP for claiming a reward.
const otp = await sdk.requestClaimOTP("[email protected]", 5, 10);
console.log("Claim OTP expires:", otp.expires_at);createClaimRequest(request)
Create a new reward claim request.
const { claim_request } = await sdk.createClaimRequest({
member_email: "[email protected]",
card_id: 5,
reward_id: 10,
verification_code: "123456",
member_note: "Please deliver to office",
});
console.log("Claim ID:", claim_request.id);
console.log("Status:", claim_request.status); // 'pending'getClaimRequest(requestId)
Get claim request details.
const { claim_request } = await sdk.getClaimRequest(123);approveClaimRequest(requestId, staffNote?)
Approve a pending claim request.
const { claim_request } = await sdk.approveClaimRequest(123, "Approved!");rejectClaimRequest(requestId, staffNote?)
Reject a pending claim request.
const { claim_request } = await sdk.rejectClaimRequest(123, "Out of stock");Referral APIs
getReferralStats(cardId)
Get referral statistics for a card.
const stats = await sdk.getReferralStats(5);
console.log("Total referrals:", stats.total_referrals);
console.log("Successful:", stats.successful_referrals);listReferrers(cardId)
Get top referrers for a card.
const { referrers } = await sdk.listReferrers(5);
referrers.forEach((r) => {
console.log(`${r.member_name}: ${r.referral_count} referrals`);
});listReferrerReferrals(cardId, memberId)
Get all referrals made by a specific member.
const { referrals } = await sdk.listReferrerReferrals(5, 100);validateReferralCode(referralCode, cardId)
Check if a referral code is valid.
const result = await sdk.validateReferralCode("REF123ABC", 5);
if (result.is_valid) {
console.log("Referred by:", result.referrer?.name);
}applyReferral(referralCode, cardId, refereeEmail)
Apply a referral code to a new member.
const { referral } = await sdk.applyReferral(
"REF123ABC",
5,
"[email protected]"
);Webhook Handling
Verifying Webhooks
import { WebhookHandler } from "@raba7ni/raba7ni";
const handler = new WebhookHandler("your_webhook_secret");
// Express example
app.post("/webhooks", (req, res) => {
const signature = req.headers["x-webhook-signature"];
const payload = JSON.stringify(req.body);
handler.handleWebhook(payload, signature, {
onMemberJoined: async (data) => {
console.log("New member:", data.member.name);
},
onMemberLeft: async (data) => {
console.log("Member left:", data.member.name);
},
onClaimRequestCreated: async (data) => {
console.log("New claim:", data.claim_request.id);
},
onClaimRequestProcessed: async (data) => {
console.log("Claim processed:", data.status);
},
onUnknownEvent: async (event, data) => {
console.log("Unknown event:", event);
},
});
res.status(200).send("OK");
});Manual Verification
import { verifyWebhookSignature, parseWebhookPayload } from "@raba7ni/raba7ni";
const isValid = verifyWebhookSignature(payload, signature, secret);
if (isValid) {
const webhook = parseWebhookPayload(payload);
console.log("Event:", webhook.event);
}Error Handling
import {
Raba7niError,
AuthenticationError,
RateLimitError,
ValidationError,
} from "@raba7ni/raba7ni";
try {
await sdk.validateMember(5, "+123");
} catch (error) {
if (error instanceof AuthenticationError) {
console.error("Invalid credentials");
} else if (error instanceof RateLimitError) {
console.error("Rate limited, retry after:", error.retryAfter);
} else if (error instanceof ValidationError) {
console.error("Validation errors:", error.validationErrors);
} else if (error instanceof Raba7niError) {
console.error("API error:", error.message, error.code);
}
}Rate Limiting
The SDK tracks rate limits automatically:
const info = sdk.getRateLimitInfo();
console.log("Hourly remaining:", info.hourlyRemaining);
console.log("Daily remaining:", info.dailyRemaining);Utilities
import {
normalizePhoneNumber,
validateEmail,
validateCardId,
} from "@raba7ni/raba7ni";
// Normalize phone numbers
normalizePhoneNumber("+1 (555) 123-4567"); // '+15551234567'
// Validate email format
validateEmail("[email protected]"); // true
// Validate card ID
validateCardId("5"); // 5 (number)TypeScript Types
All types are exported for full TypeScript support:
import type {
Member,
Card,
Reward,
ClaimRequest,
Order,
Transaction,
WebhookPayload,
ClaimRequestCreatedWebhookData,
ClaimRequestProcessedWebhookData,
} from "@raba7ni/raba7ni";Support
- Documentation: https://app.raba7ni.com/docs/developer-api.php
Requirements
- Node.js 18+
- TypeScript 5.0+ (for TypeScript users)
License
MIT © Raba7ni
