API Integration Guide
A step-by-step walkthrough for API partners - from environment setup and authentication to placing orders, handling all response states, and going live on production.
Follow the parts in order for your first integration.
Part I - Environments
Hubble provides two separate environments. You will start on Staging, and move to Production after your integration is verified.
1.1 Staging & Production URLs
| Environment | Base URL | Purpose |
|---|---|---|
| Staging | https://api.dev.myhubble.money | Testing and development |
| Production | https://api.myhubble.money | Live transactions with real money |
# Example: Login on Stagingcurl -X POST "https://api.dev.myhubble.money/v1/partners/auth/login" \ -H "Content-Type: application/json" \ -d '{ "clientId": "YOUR_STAGING_CLIENT_ID", "clientSecret": "YOUR_STAGING_CLIENT_SECRET" }'1.2 Staging Credentials
Use the integration portal to obtain your credentials:
- clientId — Your unique partner identifier
- clientSecret — Your secret key (store securely, never expose in client-side code)
Part II - Authentication
All API access begins with authentication. You exchange your credentials for a time-limited access token, which is then used for every subsequent request.
2.1 Login API
All API access begins with authentication. Exchange your credentials for a time-limited access token used for every subsequent request.
/v1/partners/auth/loginAuth Required: No — this is how you get the token.
Error Responses
| Status | Meaning | Common Cause |
|---|---|---|
401 | Unauthorized | Wrong clientId/clientSecret, or staging keys on production |
400 | Bad Request | Missing fields in request body |
403 | Forbidden | Request from a non-whitelisted IP |
curl -X POST "https://api.dev.myhubble.money/v1/partners/auth/login" \ -H "Content-Type: application/json" \ -d '{ "clientId": "YOUR_STAGING_CLIENT_ID", "clientSecret": "YOUR_STAGING_CLIENT_SECRET" }'Response (200 OK):
{ "token": "eyJhbGciOiJIUzI1NiIs...", "expiresInSecs": 3600}2.2 Token Management
The access token expires after expiresInSecs (typically 3600s / 1 hour). You must:
- Cache the token and reuse it for all requests within the validity window. Do not call Login before every request.
- Implement automatic token refresh before expiry. Recommended: refresh at 80% of expiry time (e.g., after 48 minutes for a 60-minute token).
- Handle 401 responses mid-session by re-authenticating and retrying the failed request automatically.
2.3 Request Headers
Every API call after authentication must include these headers:
| Header | Value | Description |
|---|---|---|
Authorization | Bearer <access_token> | JWT token from the Login API |
X-REQUEST-ID | A unique UUID per request | Critical for troubleshooting with Hubble support |
Content-Type | application/json | Required for all POST requests |
# Example headersAuthorization: Bearer <access_token>X-REQUEST-ID: 239774a8-f59c-496c-bb52-ceb683d60af3Content-Type: application/json2.4 Setup Checklist
- Configure base URLs separately (not hardcoded) so switching from staging to production is a config change, not a code change.
- Generate and log
X-REQUEST-IDfor every single API call.
Part III - Discovering Brands
Once authenticated, explore the brand catalog. Hubble offers 450+ gift card brands across categories like Food, Fashion, Electronics, Travel, and more.
3.1 Fetch Brand Catalog
Fetch the entire brand catalog using this API. Authentication is required. The access token is a token you get from the login API.
/v1/partners/productsQuery Parameters (all optional)
| Parameter | Type | Description |
|---|---|---|
q | string | Text search on brand titles and descriptions |
category | string | Filter by category, e.g. FOOD, FASHION, ELECTRONICS |
pageNo | integer | Page number starting from 1. Omit to get all brands. |
limit | integer | Page size for pagination |
# Fetch brand catalogcurl "https://api.dev.myhubble.money/v1/partners/products?category=FOOD&pageNo=1&limit=20" \ -H "Authorization: Bearer <access_token>" \ -H "X-REQUEST-ID: $(uuidgen)"3.2 Get Single Brand
Returns the full brand object for a specific product. Use this to fetch up-to-date details before placing an order.
/v1/partners/products/:productId
# Get single brandcurl "https://api.dev.myhubble.money/v1/partners/products/01GMMNJECTDZAG2YS61K58HVG8" \ -H "Authorization: Bearer <token>" \ -H "X-REQUEST-ID: $(uuidgen)"Each brand returned by the API contains critical fields that govern how you can order vouchers. You must understand these fields thoroughly before placing any orders.
3.3 Brand Status Values
Every brand has a status field that determines whether vouchers can be generated for it.
| Status | Meaning | What You Should Do |
|---|---|---|
| ACTIVE | Vouchers can be generated | Safe to display to end users and accept orders |
| INACTIVE | Vouchers CANNOT be generated | Remove from user-facing catalog immediately. Do not attempt orders. |
Brand Errors
| Code | Error | What To Do |
|---|---|---|
E100 | Brand temporarily disabled | Provider failure. Wait and retry later. |
E101 | Brand not enabled for you | Contact Hubble support to enable this brand. |
E102 | Brand not active | Brand is INACTIVE. Do not display to users. |
3.4 Denomination Types
The denominationType field tells you how the brand accepts order amounts.
| Type | How It Works | What to Validate |
|---|---|---|
FIXED | Only specific denominations in amountRestrictions.denominations are accepted | Your order denomination must exactly match one value in the array |
FLEXIBLE | Any amount between minVoucherAmount and maxVoucherAmount | Value must fall within min/max range. No fixed list to match against. |
When a brand is FIXED: You must read the amountRestrictions.denominations array and only allow users to select from those exact values.
For example, if Flipkart has denominations [100, 250, 500, 1000, 2000, 5000], you cannot send 600 or 1500 - only the exact listed values.
When a brand is FLEXIBLE: You can allow users to enter any custom amount, but you must enforce the min/max boundaries. For example, if a brand allows Rs 100 to Rs 10,000, sending Rs 50 or Rs 15,000 will fail.
Additional Amount Restrictions
maxVouchersPerOrder— Max total vouchers in a single ordermaxVouchersPerDenomination— Max vouchers of same denomination in one ordermaxDenominationsPerOrder— Max distinct denomination values in one orderminOrderAmount/maxOrderAmount— Total order amount boundaries
3.5 Card Type
The cardType field on the brand object is essential for building your voucher display logic. It tells you exactly what credentials the end user needs to redeem the gift card.
| Card Type | What Customer Needs | What to Display |
|---|---|---|
CARD_NUMBER_SECURED | Card number only | Show cardNumber. cardPin will be null. |
PIN_NO_SECURED | PIN only | Show cardPin. cardNumber will be null. |
CARD_AND_PIN_NO_SECURED | Both card number AND PIN | Show BOTH. If either is missing, customer cannot redeem. |
- Read cardType from the brand object before placing an order to know what your display UI needs to support.
- Handle null values gracefully — for CARD_NUMBER_SECURED brands,
cardPinwill be null. - For CARD_AND_PIN_NO_SECURED brands, you MUST display both credentials.
3.6 Redemption Type
The redemptionType tells you where the voucher can be used.
| Type | Where Voucher Can Be Used | How to Use This Information |
|---|---|---|
| ONLINE | Only on the brand’s website or app | Show an “Online Only” tag. |
| OFFLINE | Only at physical retail stores | Show an “In-Store Only” tag. The brand’s online checkout may not accept this voucher. |
| ONLINE_AND_OFFLINE | Both online and at physical stores | The most flexible type. Show “Online & In-Store” or similar messaging. |
How to use redemptionType in practice:
- Display the redemption channel clearly to end users so they know where they can use the voucher. A customer buying a voucher for in-store use will be frustrated if the brand only accepts it online.
- Use
retailModeNamefor display text (not theretailModeenum). The enum value ONLINE/OFFLINE is for your logic; theretailModeNamegives a user-friendly label. - Include
howToUseInstructions- these are brand-specific redemption steps provided by the brand. Display them alongside the voucher to help customers redeem successfully.
3.7 Deprecated Fields
The following fields will be removed in future API versions. Migrate as soon as possible.
| Deprecated Field | Use Instead | Notes |
|---|---|---|
iconImageUrl | thumbnailUrl | Brand image/logo URL |
minAmount / maxAmount | minOrderAmount / maxOrderAmount | Order amount limits |
usageInstructions | howToUseInstructions | Redemption steps for end users |
Brand Errors You May Encounter
| Code | Error | What To Do |
|---|---|---|
| E100 | Brand temporarily disabled | Brand disabled due to provider failures. Wait and retry later. |
| E101 | Brand not enabled for you | Contact Hubble support to enable this brand for your account. |
| E102 | Brand not active | The brand is INACTIVE. Do not display to users. Check catalog for updated status. |
Part IV - Placing Your First Order
This is the core of the integration, converting brand selections into actual gift card vouchers. This section covers the order request structure and the most common failure patterns.
4.1 Place Order
/v1/partners/ordersRequest Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
productId | string | Required | Brand/product ID from the catalog |
referenceId | string | Required | Your idempotency key (max 40 chars, globally unique) |
amount | number | Required | Total order amount (must = sum of denomination × qty) |
denominationDetails[] | array | Required | List of {denomination, quantity} pairs |
customerDetails | object | Conditional | Required for B2C, nullable for B2B |
deliveryDetails | object | Optional | Only if Hubble handles voucher delivery for you |
curl -X POST "https://api.dev.myhubble.money/v1/partners/orders" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -H "X-REQUEST-ID: 239774a8-f59c-496c-bb52-ceb683d60af3" \ -d '{ "productId": "01GMAW822RPDJ5C50XK24QC2C4", "referenceId": "ORD-2026-001", "amount": 1000, "denominationDetails": [ { "denomination": 500, "quantity": 2 } ], "customerDetails": { "name": "John Doe", "phoneNumber": "9876543212", "email": "john@example.com" } }'Response Body
Returns the Order Object
4.2 Customer Details
Part V - Order Handling
Not all orders complete instantly. Orders can return in one of three primary states: SUCCESS, FAILED, or PROCESSING. This section walks through each state with real examples so you know exactly what to expect and how to handle it.
5.1 Response States
| Status | Meaning | Your Action |
|---|---|---|
| SUCCESS | Vouchers generated — data in vouchers[] | Display vouchers to user |
| PROCESSING | Generation in progress — vouchers[] is empty | Poll or listen for webhook |
| FAILED | Generation failed — see failureReason | Show error, retry with new referenceId |
| CANCELLED | Cancelled by client request | Confirm cancellation to user |
| REVERSED | Reversed by client request | Process refund if applicable |
5.2 Handling SUCCESS
When an order completes successfully, the response includes a vouchers[] array with the generated gift card details. Here is a complete example using Flipkart as the brand.
Example: Placing a Flipkart Order (Staging)
Brand: Flipkart | Product ID: 01GMMNJECTDZAG2YS61K58HVG8 | Amount: Rs 500
curl -X POST "https://api.dev.myhubble.money/v1/partners/orders" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <access_token>" \ -H "X-REQUEST-ID: 239774a8-f59c-496c-bb52-ceb683d60af3" \ -d '{ "productId": "01GMMNJECTDZAG2YS61K58HVG8", "referenceId": "ref_1772006406973_tfrkrtu", "amount": 500, "denominationDetails": [ { "denomination": 500, "quantity": 1 } ], "customerDetails": { "name": "Test User", "phoneNumber": "9876543212", "email": "test@example.com" } }'SUCCESS Response (HTTP 200)
{ "id": "01KJA7HBZAPKDN0VVXTVN6R41H", "referenceId": "ref_1772006406973_tfrkrtu", "status": "SUCCESS", "vouchers": [ { "cardType": "CARD_AND_PIN_NO_SECURED", "cardPin": "215744", "cardNumber": "8090920011768104", "validTill": "2027-02-25", "amount": 500 } ], "failureReason": null}What to Do on SUCCESS
- Extract the
vouchers[]array - each object contains the gift card credentials. - Check the cardType field to determine what to display to the end user. In this Flipkart example,
CARD_AND_PIN_NO_SECUREDmeans the customer needs both the card number and PIN to redeem. - Display credentials: Show the cardNumber and cardPin to the customer.
- Show the expiry date: The
validTillfield tells the customer when the voucher expires. - Store the order: Save the Hubble id and your referenceId for reconciliation.
5.3 Handling FAILED Orders
When an order fails, the response includes an empty vouchers[] array and a failureReason explaining what went wrong. Here is an example using Jiomart as the brand. (Brands like Jiomart and Myntra are configured to fail in staging.)
Example: Placing a Jiomart Order (Staging)
Brand: Jiomart | Product ID: 01J1W4D2KRHMJZKPAQWXCEMF4M | Amount: Rs 500
Request
curl -X POST "https://api.dev.myhubble.money/v1/partners/orders" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <access_token>" \ -H "X-REQUEST-ID: 239774a8-f59c-496c-bb52-ceb683d60af3" \ -d '{ "productId": "01J1W4D2KRHMJZKPAQWXCEMF4M", "referenceId": "ref_1772017611584_94lcjp8", "amount": 500, "denominationDetails": [ { "denomination": 500, "quantity": 1 } ], "customerDetails": { "name": "Test User", "phoneNumber": "9876543212", "email": "test@example.com" } }'FAILED Response (HTTP 200)
{ "id": "01KJA7NYJHHRPQ47VMN4ZN3JFT", "referenceId": "ref_1772017611584_94lcjp8", "status": "FAILED", "vouchers": [], "failureReason": "Brand not available"}What to Do on FAILED
- Read the failureReason — in this case, “Brand not available” means Jiomart is not currently active or has no available providers.
- Do NOT reuse the referenceId — even though the order failed, the referenceId
ref_1772017611584_94lcjp8is now consumed. You must generate a new one for any retry. - Check the brand status — call
GET /v1/partners/products/:productIdto verify if the brand is ACTIVE before retrying. - Inform the user — show a meaningful error message. Do not expose raw error strings to end users.
- Log everything — save the Hubble
id, yourreferenceId, and thefailureReasonfor debugging.
Common Failure Reasons
| Reason | Resolution |
|---|---|
| ”Brand not available” | The brand is INACTIVE or has no active providers. Try a different brand or wait. |
| ”Voucher generation failed” | Provider-side failure (E200). Retry after 1–2 minutes. |
| ”Insufficient balance” | Wallet balance too low (E300). Top up before retrying. |
| ”Denomination not available” | The denomination is not in the brand’s allowed list (E150). Refresh your catalog. |
5.4 Handling PROCESSING Orders
Some orders do not resolve immediately. When voucher generation takes time (e.g., for large orders or certain providers), the API returns a PROCESSING status. The vouchers[] array will be empty, and you need to wait for the final state.
If an order is returned with the status PROCESSING, follow this protocol:
- Begin polling the Get Order endpoint — start polling 1 minute after order placement.
- Limit polling to a maximum of 5 attempts at reasonable intervals.
- Optionally, set up the Order Reached Terminal State webhook (recommended). You may configure your system to listen for the webhook to receive the final order status automatically instead of relying only on polling.
- Timeout handling — if the order remains in PROCESSING status after 15 minutes, mark it as FAILED on your side and contact Hubble support for further assistance.
Example: PROCESSING Response
Brand: Amazon | Amount: Rs 5,000 (10 x Rs 500)
{ "id": "01KJB2EXAMPLE0PROCESSING01", "referenceId": "ref_your_unique_id_here", "status": "PROCESSING", "vouchers": [], "failureReason": null}Key observations: The status is PROCESSING, vouchers[] is empty (no gift cards yet), and failureReason is null (it has not failed — it is still in progress).
What to Do Next: Wait for Resolution
You have two options to know when the order resolves:
Option A: Polling
If webhooks are not set up, poll the Get Order endpoint:
- Wait at least 1 minute after order placement before the first poll.
- Poll
GET /v1/partners/orders/:orderIdat reasonable intervals (e.g., every 2 minutes). - Limit polling to a maximum of 5 attempts.
- If the order remains PROCESSING after 15 minutes, mark it as FAILED on your side and contact Hubble support.
Resolved Response (After Polling or Webhook)
Once the order resolves, the Get Order API returns the full details:
{ "id": "01KJB2EXAMPLE0PROCESSING01", "referenceId": "ref_your_unique_id_here", "status": "SUCCESS", "vouchers": [ { "id": "01KJB2VOUCHER001", "cardType": "CARD_AND_PIN_NO_SECURED", "cardPin": "834291", "cardNumber": "5012340098761234", "validTill": "2027-02-25", "amount": 500 }, { "id": "01KJB2VOUCHER002", "cardType": "CARD_AND_PIN_NO_SECURED", "cardPin": "729103", "cardNumber": "5012340098765678", "validTill": "2027-02-25", "amount": 500 } ], "failureReason": null}Option B: Webhook (Recommended)
If you have the Order Reached Terminal State webhook configured, Hubble will push a notification to your endpoint when the order resolves to SUCCESS or FAILED.
// Webhook payload you will receive:{ "orderId": "01KJB2EXAMPLE0PROCESSING01", "status": "SUCCESS"}On receiving this webhook, call GET /v1/partners/orders/01KJB2EXAMPLE0PROCESSING01 to fetch the full order details including the vouchers[] array.
5.5 Handling Timeouts
If your HTTP request to the Place Order API times out (no response received at all):
- Call
GET /v1/partners/orders/by-reference/:referenceIdto check if the order was created. - A 404 response means the order was NOT created — you may safely retry with the same
referenceId. - Any other response means the order exists — process based on the returned status (SUCCESS, FAILED, or PROCESSING).
# Check if order exists by your referenceIdcurl "https://api.dev.myhubble.money/v1/partners/orders/by-reference/ORD-2026-001" \ -H "Authorization: Bearer <token>"
# 404 = not created, retry with same referenceId# 200 = exists, process based on statusPart VI - Go Live
Once your staging integration is working end-to-end (authenticate, fetch brands, place orders, handle all statuses), it is time to transition to production. Hubble will provide production credentials after verifying your staging integration.
6.1 Production Credentials
Hubble provides production credentials separately from staging. You will receive new clientId and clientSecret for production (different from staging)
6.2 IP Whitelisting
Hubble only allows API requests from pre-approved IP addresses. Use the integration portal to add your server’s static IPs. Production server IPs must be whitelisted separately from staging.
6.3 Wallet Balance
/v1/partners/wallet/balanceWallet Top-Up: Wallet loading is an offline process. Contact your Hubble account manager to request a top-up.
curl "https://api.myhubble.money/v1/partners/wallet/balance" \ -H "Authorization: Bearer <prod_token>" \ -H "X-REQUEST-ID: $(uuidgen)"Response:
{ "balance": 1000.50}6.4 Webhooks
Webhooks allow Hubble to push updates to your system in real time. Strongly recommended for a production-grade integration.
| Webhook | Triggers When… |
|---|---|
| Brand Updated | A brand’s status, denomination, or amount restrictions change |
| Wallet Low Balance | Wallet balance falls below your configured threshold |
| Order Reached Terminal State | A PROCESSING order transitions to SUCCESS or FAILED |
| Brand Discount Update | Subvention/discount percentage changes for a brand |
6.5 Catalog Sync
- Refresh your full catalog at least once per week (daily recommended).
- Subscribe to the Brand Updated webhook for real-time changes to status, denominations, and amount restrictions.
- Categories are NOT communicated via webhooks. Rely on periodic sync for category and new brand additions.
- Filter out INACTIVE brands from your user-facing catalog immediately when detected.
- Cache brand data locally to minimize API calls — but always validate denominations against the latest catalog before placing orders.
- If your sync is infrequent, orders will fail with
E150(denomination not available).
6.6 Rate Limiting
- Limits are enforced at two levels: Partner-level (across your entire account) and Brand-level (per product). If either is breached, the order fails.
- Two types: Amount (total monetary value) and Count (number of orders), across hourly, daily, and monthly windows.
- Brand-level limits can be scoped globally or per user for granular risk control.
- Rate limit failures are business logic failures, not HTTP 429 errors. Always check the response body for the failure reason.
- Before going live, define realistic limits and coordinate with Hubble ahead of high-volume campaigns or seasonal spikes.
Appendix
All Endpoints (Quick Reference)
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /v1/partners/auth/login | Authenticate and get access token |
| GET | /v1/partners/products | List all brands with filters |
| GET | /v1/partners/products/:productId | Get single brand details |
| POST | /v1/partners/orders | Place a voucher order |
| GET | /v1/partners/orders/:orderId | Get order by Hubble ID |
| GET | /v1/partners/orders/by-reference/:referenceId | Get order by your reference ID |
| GET | /v1/partners/orders/vouchers/:id | Get individual voucher details |
| POST | /v1/partners/orders/:orderId/resend-delivery | Retry voucher delivery |
| GET | /v1/partners/wallet/balance | Check wallet balance |