Skip to content

Coins (Hubble Managed)

Complete coin management system for managing digital coin wallets, transactions, and rewards.

Hubble’s managed coin system provides a complete solution for your digital coin wallets. Credit coins to users, debit coins for purchases, and track all transactions with full audit trails.

This is ideal if you don’t have your own in-app currency infrastructure and want to quickly implement a robust currency system.

Base URLs

EnvironmentBase URL
Developmenthttps://api.dev.myhubble.money
Productionhttps://api.myhubble.money

Authentication

All API requests require authentication using a Bearer token obtained from the login API.

Required Headers:

HeaderDescriptionRequired
AuthorizationBearer token obtained from login APIYes
Content-Typeapplication/jsonYes
X-Request-IdRequest tracking IDRecommended

Endpoints

1. Get Coin Balance

Retrieve the coin balance for a specific user.

HTTP Method: GET

Endpoint: /v1/partners/coins/{userId}/balance

Path Parameters:

ParameterTypeDescription
userIdstringYour unique user identifier

Response:

Status Code: 200 OK

{
"userId": "USR-001",
"available": 1500.00,
"held": 0.00,
"consumed": 500.00,
"expired": 100.00,
"total": 1500.00
}

Response Fields:

FieldTypeDescription
userIdstringUser identifier
availabledecimalCoins available for use
helddecimalCoins reserved (for future use)
consumeddecimalTotal coins spent
expireddecimalTotal coins expired
totaldecimalSum of available + held

2. Credit Coins

Credit coins to a user’s wallet.

HTTP Method: POST

Endpoint: /v1/partners/coins/credit

Request Body:

{
"userId": "USR-001",
"idempotencyKey": "REWARD-2025-Q1-001",
"amount": 500.00,
"remarks": "Q1 Performance Bonus",
"expiresOn": "2025-12-31"
}

Request Fields:

FieldTypeRequiredDescription
userIdstringYesYour unique user identifier
idempotencyKeystringYesUnique key to prevent duplicates
amountdecimalYesCoins to credit (> 0)
remarksstringNoTransaction notes
expiresOndateNoExpiry date (YYYY-MM-DD). Uses default if not provided

Response:

Status Code: 201 Created

{
"transactionId": "01HKXYZ123ABC456DEF789GHI",
"userId": "USR-001",
"type": "CREDIT",
"status": "SUCCESS",
"amount": 500.00,
"remarks": "Q1 Performance Bonus",
"transactedAt": "2025-01-16T10:30:00"
}

3. Bulk Credit Coins

Credit coins to multiple users in a single request. Maximum 100 credits per request.

HTTP Method: POST

Endpoint: /v1/partners/coins/bulk-credit

Request Body:

{
"credits": [
{
"userId": "USR-001",
"idempotencyKey": "WELCOME-2025-001",
"amount": 100.00,
"remarks": "Welcome bonus",
"expiresOn": "2025-12-31"
},
{
"userId": "USR-002",
"idempotencyKey": "WELCOME-2025-002",
"amount": 150.00,
"remarks": "Referral reward"
}
]
}

Request Fields:

FieldTypeRequiredDescription
creditsarrayYesList of credit operations (max 100)
credits[].userIdstringYesYour unique user identifier
credits[].idempotencyKeystringYesUnique key per credit
credits[].amountdecimalYesCoins to credit (> 0)
credits[].remarksstringNoTransaction notes
credits[].expiresOndateNoExpiry date for this credit

Response:

Status Code: 200 OK

{
"totalOperations": 2,
"successfulOperations": 2,
"results": [
{
"transactionId": "01HKXYZ123ABC456DEF789GHI",
"userId": "USR-001",
"type": "CREDIT",
"status": "SUCCESS",
"amount": 100.00,
"remarks": "Welcome bonus",
"transactedAt": "2025-01-16T10:30:00"
},
{
"transactionId": "01HKXYZ789XYZ012PQR345STU",
"userId": "USR-002",
"type": "CREDIT",
"status": "SUCCESS",
"amount": 150.00,
"remarks": "Referral reward",
"transactedAt": "2025-01-16T10:30:01"
}
],
"failedOperations": []
}

Partial Failure Response:

{
"totalOperations": 3,
"successfulOperations": 2,
"results": [...],
"failedOperations": [
{
"idempotencyKey": "WELCOME-2025-003",
"userId": "USR-003",
"error": "Credit amount 15000.00 exceeds maximum allowed 10000.00"
}
]
}

4. Debit Coins

Debit coins from a user’s wallet. Coins are consumed in FIFO order (oldest expiring coins first).

HTTP Method: POST

Endpoint: /v1/partners/coins/debit

Request Body:

{
"userId": "USR-001",
"idempotencyKey": "ORDER-2025-ORD456",
"amount": 200.00,
"remarks": "Gift card purchase"
}

Request Fields:

FieldTypeRequiredDescription
userIdstringYesYour unique user identifier
idempotencyKeystringYesUnique key to prevent duplicates
amountdecimalYesCoins to debit (> 0)
remarksstringNoTransaction notes

Response:

Status Code: 200 OK

{
"transactionId": "01HKXYZ123ABC456DEF789GHI",
"userId": "USR-001",
"type": "DEBIT",
"status": "SUCCESS",
"amount": 200.00,
"remarks": "Gift card purchase",
"transactedAt": "2025-01-16T10:30:00"
}

5. Reverse Transaction

Reverse a completed (SUCCESS) transaction.

HTTP Method: POST

Endpoint: /v1/partners/coins/reverse

Request Body:

{
"transactionId": "01HKXYZ123ABC456DEF789GHI",
"reason": "Order refund"
}

Request Fields:

FieldTypeRequiredDescription
transactionIdstringYesTransaction ID to reverse
reasonstringNoReason for reversal

Response:

Status Code: 200 OK

{
"transactionId": "01HKXYZ123ABC456DEF789GHI",
"userId": "USR-001",
"type": "DEBIT",
"status": "REVERSED",
"amount": 200.00,
"remarks": "Gift card purchase",
"transactedAt": "2025-01-16T10:30:00"
}

Reversal Behavior:

  • CREDIT reversed: Deducts coins from available balance. Only allowed if coins are fully intact (not consumed or expired).
  • DEBIT reversed: Restores coins back to available balance.

6. Get Transaction History

Retrieve transaction history for a user with optional filtering.

HTTP Method: GET

Endpoint: /v1/partners/coins/{userId}/transactions

Path Parameters:

ParameterTypeDescription
userIdstringYour unique user identifier

Query Parameters:

ParameterTypeDefaultDescription
typeenumAllFilter: CREDIT or DEBIT
pageNointeger0Page number (0-indexed)
limitinteger20Page size (max: 100)

Response:

Status Code: 200 OK

{
"data": [
{
"transactionId": "01HKXYZ123ABC456DEF789GHI",
"userId": "USR-001",
"type": "CREDIT",
"status": "SUCCESS",
"amount": 500.00,
"remarks": "Q1 Performance Bonus",
"transactedAt": "2025-01-15T10:30:00"
},
{
"transactionId": "01HKXYZ456DEF789ABC012GHI",
"userId": "USR-001",
"type": "DEBIT",
"status": "SUCCESS",
"amount": 200.00,
"remarks": "Gift card purchase",
"transactedAt": "2025-01-16T14:20:00"
}
],
"nextCursor": {
"pageNo": "1",
"limit": 20,
"totalElements": 45
}
}

Transaction States

CREDIT Flow

Request ──────────────────────────▶ SUCCESS
▼ (reverse)
REVERSED

DEBIT Flow

Request ──────────────────────────▶ SUCCESS
▼ (reverse)
REVERSED

Transaction Status Definitions

StatusDescription
SUCCESSTransaction completed successfully
REVERSEDCompleted transaction has been reversed

Error Responses

All error responses follow this structure:

{
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance. Required: 200.00, Available: 150.00",
"requestId": "req-abc123"
}

Common Error Codes

CodeHTTP StatusDescription
INVALID_INPUT400Request validation failed
INSUFFICIENT_BALANCE400Not enough coins for debit
ENTITY_NOT_FOUND404User, transaction, or resource not found
INVALID_OPERATION400Operation not allowed for current state
UNAUTHORIZED401Invalid credentials
INTERNAL_ERROR500Server error

Best Practices

1. Use Descriptive Idempotency Keys

Format your keys for easy tracking and debugging:

{TYPE}-{DATE}-{UNIQUE_ID}

Examples:

  • WELCOME-2025-Q1-USR001
  • REWARD-20250116-USR042
  • REFUND-ORDER123-USR007

2. Store Transaction IDs

Always store transaction IDs for:

  • Reconciliation
  • Reversals
  • Support inquiries
  • Audit trails

3. Set Appropriate Expiry Dates

Benefits of setting expiry dates:

  • Creates urgency for users to spend coins
  • Manages your liability
  • Drives engagement

4. Implement Retry with Backoff

Handle transient failures gracefully:

async function creditWithRetry(userId, amount, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await creditCoins(userId, amount);
} catch (error) {
if (i === maxRetries - 1) throw error;
await sleep(Math.pow(2, i) * 1000); // Exponential backoff
}
}
}

5. Check Balance Before Debit

Provide better UX by checking balance before attempting debit:

const balance = await getBalance(userId);
if (balance.available < amount) {
// Show user-friendly message
return;
}
await debitCoins(userId, amount);

6. Test in Development First

Always validate your integration in the development environment before deploying to production.


Usage Examples

Example 1: Welcome Bonus

Credit new users with welcome bonus coins:

Terminal window
curl -X POST 'https://api.myhubble.money/v1/partners/coins/credit' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H 'X-Request-Id: req-welcome-001' \
-d '{
"userId": "USR-001",
"idempotencyKey": "WELCOME-2025-USR001",
"amount": 100.00,
"remarks": "Welcome bonus for new user",
"expiresOn": "2025-12-31"
}'

Example 2: Bulk Reward Campaign

Reward multiple users at once:

Terminal window
curl -X POST 'https://api.myhubble.money/v1/partners/coins/bulk-credit' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H 'X-Request-Id: req-bulk-001' \
-d '{
"credits": [
{
"userId": "USR-001",
"idempotencyKey": "Q1REWARD-USR001",
"amount": 500.00,
"remarks": "Q1 top performer"
},
{
"userId": "USR-002",
"idempotencyKey": "Q1REWARD-USR002",
"amount": 300.00,
"remarks": "Q1 achievement"
}
]
}'

Example 3: Purchase Flow with Debit

Debit coins for a purchase:

Terminal window
curl -X POST 'https://api.myhubble.money/v1/partners/coins/debit' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H 'X-Request-Id: req-order-001' \
-d '{
"userId": "USR-001",
"idempotencyKey": "ORDER-2025-ORD123",
"amount": 250.00,
"remarks": "Amazon gift card purchase"
}'

Example 4: Refund Scenario

Reverse a transaction for refund:

Terminal window
curl -X POST 'https://api.myhubble.money/v1/partners/coins/reverse' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/json' \
-H 'X-Request-Id: req-refund-001' \
-d '{
"transactionId": "01HKXYZ123ABC456DEF789GHI",
"reason": "Customer requested refund"
}'

Example 5: Check Balance

Get user’s current coin balance:

Terminal window
curl -X GET 'https://api.myhubble.money/v1/partners/coins/balance/USR-001' \
-H 'Authorization: Bearer your-access-token' \
-H 'X-Request-Id: req-balance-001'

Example 6: Transaction History with Filters

Get credit transactions:

Terminal window
curl -X GET 'https://api.myhubble.money/v1/partners/coins/transactions/USR-001?type=CREDIT&pageNo=0&limit=50' \
-H 'Authorization: Bearer your-access-token' \
-H 'X-Request-Id: req-history-001'

Troubleshooting

Error: “Insufficient Balance”

Problem: User doesn’t have enough coins for the debit operation.

Solution: Check the user’s balance first using the Get Coin Balance endpoint before initiating a debit.

const balance = await getBalance(userId);
if (balance.available < requestedAmount) {
throw new Error(`Insufficient coins. Available: ${balance.available}`);
}

Error: “Duplicate Key” / Idempotency Key Already Used

Problem: The idempotency key has already been used for another transaction.

Solution:

  • If retrying a failed request, use the same idempotency key (you’ll get the original response)
  • For new transactions, use a unique idempotency key with transaction-specific identifiers

Note: Duplicate requests with the same idempotency key return the original transaction response, not an error.

Error: “Invalid Operation”

Problem: Attempting an operation that’s not allowed for the transaction’s current state.

Common scenarios:

  • Trying to reverse an already reversed transaction
  • Trying to reverse a credit where coins have been partially consumed
  • Trying to reverse a credit where coins have expired

Solution: Check transaction status before performing operations.

Error: “Entity Not Found”

Problem: The specified user or transaction doesn’t exist.

Solution:

  • Verify the userId matches your system’s user identifier
  • Verify the transactionId is correct (copy from original response)

Coins Not Appearing Immediately

Problem: User doesn’t see credited coins in their balance.

Solution:

  1. Check the transaction status via Get Transaction History
  2. Ensure the transaction status is SUCCESS
  3. Verify you’re checking the correct userId

Credit Reversal Blocked

Problem: Cannot reverse a credit transaction.

Solution: Credit reversal is only allowed if:

  • The lot has not been partially consumed (no debits from those coins)
  • The lot has not expired

If coins have been spent or expired, reversal is not possible.


Rate Limits

EndpointLimit
All endpoints1000 requests/minute per client
Bulk credit100 credits per request
Transaction history100 records per page (max limit)

Two-Phase Debit (Coming Soon)

A two-phase debit flow is planned for scenarios requiring hold-then-confirm semantics (e.g., checkout flows where the order needs confirmation before finalizing the debit).

Planned Endpoints:

EndpointMethodDescription
/v1/partners/coins/holdPOSTCreate a hold on coins
/v1/partners/coins/hold/{holdId}/confirmPOSTConfirm the hold and complete debit
/v1/partners/coins/hold/{holdId}/cancelPOSTCancel the hold and release coins

Planned Flow:

Request ──► INITIATED (hold created)
┌───────┴───────┐
▼ ▼
CONFIRMED CANCELLED
(debit done) (coins released)

This will be useful for:

  • E-commerce checkout flows where payment confirmation is separate from order placement
  • Reservation systems where coins are held pending final confirmation
  • Any scenario requiring a “soft lock” before committing the debit

Contact support to express interest or for early access.


Webhooks (Coming Soon)

Webhook notifications for transaction events will be available in a future release.


SDK Support

Official SDKs are planned for:

  • JavaScript/TypeScript
  • Python
  • Java
  • Go

Contact support for early access.