Starship Rewards API

Wallets API

Retrieve wallet information and manage multi-currency balances for client accounts

Wallets API

The Wallets API provides comprehensive access to client wallet information, enabling balance queries, wallet listing, and detailed wallet metadata retrieval for multi-currency transaction management.

Overview

The Wallets API consists of two main endpoints:

  • List Wallets - Retrieve all wallets for the authenticated client with filtering options
  • Get Wallet by ID - Get detailed information for a specific wallet including current balance

All wallet endpoints require authentication and return data in a consistent JSON format with real-time balance information.

List Wallets

Retrieve a paginated list of wallets for the authenticated client with optional filtering by currency, type, and status.

Endpoint

GET /api/v1/wallets

Authentication: Bearer token required

Query Parameters

ParameterTypeDefaultDescription
pagenumber1Page number for pagination (min: 1)
limitnumber50Number of items per page (min: 1, max: 10,000)
currency_idnumber-Filter by specific currency ID
typestring-Filter by wallet type ("PREPAID" or "POSTPAID")
is_activebooleantrueFilter by active status
sortobject{"field":"id","direction":"DESC"}Sort configuration

Sort Object Format

{
  "field": "id",        // Options: "id", "amount", "created_at", "updated_at"
  "direction": "DESC"   // Options: "ASC" or "DESC"
}

Response

Success Response (200 OK)

Headers:

X-Page: 1
X-Per-Page: 50
X-Total-Count: 5
X-Total-Pages: 1
X-Page-Size: 50
X-Has-More: false

Response Body:

[
  {
    "id": 101,
    "currency_id": 1,
    "amount": 5000.00,
    "type": "PREPAID"
  },
  {
    "id": 102,
    "currency_id": 2,
    "amount": 2500.50,
    "type": "PREPAID"
  },
  {
    "id": 103,
    "currency_id": 3,
    "amount": 10000.00,
    "type": "POSTPAID"
  }
]

Response Fields

FieldTypeDescription
idnumberUnique wallet identifier
currency_idnumberAssociated currency ID
amountnumberCurrent wallet balance
typestringWallet type classification

Error Responses

400 Bad Request

{
  "error": {
    "code": "BAD_REQUEST",
    "message": "Invalid query parameters"
  }
}

401 Unauthorized

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or expired authentication token"
  }
}

500 Internal Server Error

{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "Could not retrieve wallets"
  }
}

Examples

# List wallets filtered by currency
curl -X GET "{{host}}/api/v1/wallets?currency_id=1&limit=10" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"
<?php
function listWallets($token, $currencyId = null, $limit = 10) {
    $params = ['limit' => $limit];
    if ($currencyId) {
        $params['currency_id'] = $currencyId;
    }

    $url = '{{host}}/api/v1/wallets?' . http_build_query($params);

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . $token,
            'Accept: application/json'
        ]
    ]);

    $response = curl_exec($ch);
    curl_close($ch);

    return json_decode($response, true);
}

// Usage
$wallets = listWallets('YOUR_ACCESS_TOKEN', 1, 10);
foreach ($wallets as $wallet) {
    echo "Wallet #{$wallet['id']}: {$wallet['amount']}\n";
}
?>

Get Wallet by ID

Retrieve detailed information for a specific wallet including current balance, currency details, and wallet metadata.

Endpoint

GET /api/v1/wallets/:id

Authentication: Bearer token required

Path Parameters

ParameterTypeRequiredDescription
idnumberYesUnique wallet identifier

Response

Success Response (200 OK)

{
  "id": 101,
  "currency_id": 1,
  "amount": 5000.00,
  "type": "PREPAID"
}

Response Fields

FieldTypeDescription
idnumberUnique wallet identifier
currency_idnumberAssociated currency ID
amountnumberCurrent wallet balance (precision based on currency)
typestringWallet type ("PREPAID" or "POSTPAID")

Error Responses

400 Bad Request

{
  "error": {
    "code": "BAD_REQUEST",
    "message": "Invalid wallet ID"
  }
}

404 Not Found

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Wallet not found"
  }
}

500 Internal Server Error

{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "Failed to retrieve wallet"
  }
}

Examples

# Get specific wallet by ID
curl -X GET "{{host}}/api/v1/wallets/101" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"
<?php
function getWallet($token, $walletId) {
    $url = '{{host}}/api/v1/wallets/' . $walletId;

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . $token,
            'Accept: application/json'
        ]
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode === 404) {
        throw new Exception("Wallet not found");
    }

    return json_decode($response, true);
}

// Usage
try {
    $wallet = getWallet('YOUR_ACCESS_TOKEN', 101);
    echo "Wallet ID: {$wallet['id']}\n";
    echo "Balance: {$wallet['amount']}\n";
    echo "Type: {$wallet['type']}\n";
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}
?>

Implementation Notes

Balance Precision

Wallet balances are returned with precision appropriate to the currency:

  • Fiat currencies: 2 decimal places (e.g., USD: 100.50)
  • Zero-decimal currencies: No decimal places (e.g., JPY: 1000)

Wallet Types

PREPAID Wallets

  • Pre-funded wallet type for purchases
  • Requires balance to be loaded before making purchases
  • Funds must be available before transaction execution
  • Real-time balance deduction on purchase
  • Subject to transaction limits based on client configuration

POSTPAID Wallets

  • Credit-based wallet type allowing purchases on credit
  • Transactions allowed up to configured credit limit
  • Balance can be negative up to the credit limit
  • Requires periodic settlement/payment
  • Typically used for enterprise/corporate clients with credit arrangements

Security Considerations

Access Control

  • Clients can only access their own wallets
  • Admin users may have cross-client visibility
  • Wallet IDs are globally unique and non-guessable

Balance Consistency

  • Balances are calculated in real-time from transaction ledger
  • All operations are atomic to prevent race conditions
  • Implements optimistic locking for concurrent updates

Rate Limiting

The Wallets API implements the following rate limits:

  • List Wallets: 1000 requests per minute
  • Get Wallet by ID: 2000 requests per minute
  • Rate limits are applied per client authentication token

Caching Recommendations

For optimal performance:

  • Cache wallet list for up to 5 minutes
  • Cache individual wallet details for up to 1 minute
  • Always verify balance before initiating transactions
  • Implement cache invalidation on transaction events

Integration Examples

# List all wallets
curl -X GET "{{host}}/api/v1/wallets?limit=100&is_active=true" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"

# Get specific wallet
curl -X GET "{{host}}/api/v1/wallets/101" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"

# Filter wallets by currency
curl -X GET "{{host}}/api/v1/wallets?currency_id=1&limit=50" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"

# Filter by wallet type
curl -X GET "{{host}}/api/v1/wallets?type=PREPAID" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"
<?php

class WalletClient {
    private $baseUrl;
    private $token;

    public function __construct($baseUrl, $token) {
        $this->baseUrl = $baseUrl;
        $this->token = $token;
    }

    /**
     * List all wallets with optional filtering
     */
    public function listWallets($currencyId = null, $type = null, $limit = 50) {
        $params = [
            'limit' => $limit,
            'is_active' => true
        ];

        if ($currencyId !== null) {
            $params['currency_id'] = $currencyId;
        }
        if ($type !== null) {
            $params['type'] = $type;
        }

        $url = $this->baseUrl . '/api/v1/wallets?' . http_build_query($params);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->token,
                'Accept: application/json'
            ]
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode !== 200) {
            throw new Exception("API Error: HTTP $httpCode");
        }

        return json_decode($response, true);
    }

    /**
     * Get specific wallet by ID
     */
    public function getWallet($walletId) {
        $url = $this->baseUrl . '/api/v1/wallets/' . $walletId;

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->token,
                'Accept: application/json'
            ]
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode === 404) {
            throw new Exception("Wallet not found");
        }

        if ($httpCode !== 200) {
            throw new Exception("API Error: HTTP $httpCode");
        }

        return json_decode($response, true);
    }

    /**
     * Get current balance for a wallet
     */
    public function getBalance($walletId) {
        $wallet = $this->getWallet($walletId);
        return $wallet['amount'];
    }

    /**
     * Check if wallet has sufficient balance
     */
    public function hasSufficientBalance($walletId, $requiredAmount) {
        $balance = $this->getBalance($walletId);
        return $balance >= $requiredAmount;
    }

    /**
     * Find wallet by currency ID
     */
    public function findWalletByCurrency($currencyId) {
        $wallets = $this->listWallets($currencyId);
        return !empty($wallets) ? $wallets[0] : null;
    }
}

// Usage example
$client = new WalletClient('{{host}}', 'YOUR_ACCESS_TOKEN');

try {
    // List all wallets
    $wallets = $client->listWallets();
    echo "Total wallets: " . count($wallets) . "\n";

    // Get USD wallet (assuming currency_id 1 is USD)
    $usdWallets = $client->listWallets(1);

    // Get specific wallet
    $wallet = $client->getWallet(101);
    echo "Wallet balance: " . $wallet['amount'] . "\n";

    // Check balance before purchase
    $walletId = 101;
    $purchaseAmount = 100.00;

    if ($client->hasSufficientBalance($walletId, $purchaseAmount)) {
        echo "Sufficient balance for purchase\n";
    } else {
        echo "Insufficient balance\n";
    }

} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}
?>

Webhook Events

The Wallets API can trigger the following webhook events:

EventDescriptionPayload
wallet.balance.updatedTriggered when wallet balance changesWallet object with new balance
wallet.createdTriggered when new wallet is createdComplete wallet object
wallet.suspendedTriggered when wallet is suspendedWallet ID and suspension reason
wallet.activatedTriggered when wallet is reactivatedComplete wallet object

FAQ

Q: How many wallets can a client have? A: Clients can have one wallet per currency, with no limit on the number of different currencies supported.

Q: Can I transfer funds between wallets? A: Yes, wallet-to-wallet transfers are supported through the Transactions API, subject to forex rates for cross-currency transfers.

Q: What happens to wallet balance when an order fails? A: Failed orders trigger automatic refunds, returning the full amount to the source wallet within 24 hours.

Q: How are negative balances handled? A: The system prevents negative balances through pre-authorization checks. All transactions verify sufficient balance before processing.

Q: Can wallets be deleted? A: Wallets cannot be deleted but can be deactivated. Deactivated wallets retain their balance and transaction history for audit purposes.