Starship Rewards API

Reference Data API

Access categories, subcategories, countries, and currencies for product filtering and localization

Reference Data API

The Reference Data API provides essential lookup data for categories, subcategories, countries, and currencies. This data is used for product filtering, localization, and building user interfaces.

Categories API

List Categories

Get all active categories with pagination.

GET /api/v1/categories
Authorization: Bearer {token}

Query Parameters:

ParameterTypeDescription
pageintegerPage number (default: 1)
per_pageintegerItems per page (default: 25, max: 100)

Example Response:

[
  {
    "id": 1,
    "name": "Gift Cards"
  },
  {
    "id": 2,
    "name": "Mobile Top-up"
  },
  {
    "id": 3,
    "name": "Digital Services"
  }
]

PHP Example:

// Get all categories for navigation menu
try {
    $categories = $api->getCategories(1, 50);

    echo "<select name='category_id'>\n";
    echo "<option value=''>All Categories</option>\n";

    foreach ($categories as $category) {
        echo "<option value='{$category['id']}'>";
        echo htmlspecialchars($category['name']);
        echo "</option>\n";
    }

    echo "</select>\n";

    // Or create a simple array for JSON API
    $categoryList = [];
    foreach ($categories as $category) {
        $categoryList[] = [
            'id' => $category['id'],
            'name' => $category['name'],
            'slug' => strtolower(str_replace(' ', '-', $category['name']))
        ];
    }

    echo json_encode($categoryList, JSON_PRETTY_PRINT);

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

Get Category by ID

Retrieve a specific category by its unique identifier.

GET /api/v1/categories/{id}
Authorization: Bearer {token}

Example Response:

{
  "id": 1,
  "name": "Gift Cards"
}

PHP Example:

// Get specific category
try {
    $category = $api->getCategoryById(1);
    echo "Category: {$category['name']} (ID: {$category['id']})\n";

    // Use category for product filtering
    $products = $api->getProducts(['category_id' => $category['id']]);
    echo "Found " . count($products) . " products in this category\n";

} catch (Exception $e) {
    if (strpos($e->getMessage(), '404') !== false) {
        echo "Category not found or inactive\n";
    } else {
        echo "Error: " . $e->getMessage() . "\n";
    }
}

Subcategories API

List Subcategories

Get all active subcategories with pagination.

GET /api/v1/subcategories
Authorization: Bearer {token}

Query Parameters:

ParameterTypeDescription
pageintegerPage number (default: 1)
per_pageintegerItems per page (default: 25, max: 100)

Example Response:

[
  {
    "id": 101,
    "name": "Retail Gift Cards"
  },
  {
    "id": 102,
    "name": "Entertainment Gift Cards"
  },
  {
    "id": 201,
    "name": "Prepaid Mobile Credit"
  }
]

PHP Example:

// Get subcategories for advanced filtering
try {
    $subcategories = $api->getSubcategories(1, 100);

    // Group subcategories by parent category (if you have category relationships)
    $groupedSubcategories = [];
    foreach ($subcategories as $subcategory) {
        // Extract category from subcategory name (simplified approach)
        if (strpos($subcategory['name'], 'Gift Cards') !== false) {
            $groupedSubcategories['Gift Cards'][] = $subcategory;
        } elseif (strpos($subcategory['name'], 'Mobile') !== false) {
            $groupedSubcategories['Mobile Top-up'][] = $subcategory;
        } else {
            $groupedSubcategories['Other'][] = $subcategory;
        }
    }

    // Create hierarchical filter structure
    echo "<div class='filter-section'>\n";
    foreach ($groupedSubcategories as $categoryName => $subs) {
        echo "<h4>{$categoryName}</h4>\n";
        echo "<div class='subcategory-filters'>\n";

        foreach ($subs as $subcategory) {
            echo "<label>\n";
            echo "<input type='checkbox' name='subcategory[]' value='{$subcategory['id']}' />";
            echo htmlspecialchars($subcategory['name']);
            echo "</label>\n";
        }

        echo "</div>\n";
    }
    echo "</div>\n";

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

Get Subcategory by ID

Retrieve a specific subcategory by its unique identifier.

GET /api/v1/subcategories/{id}
Authorization: Bearer {token}

Example Response:

{
  "id": 101,
  "name": "Retail Gift Cards"
}
// Get subcategory details for product filtering
try {
    $subcategoryId = 101;
    $subcategory = $api->getSubcategoryById($subcategoryId);

    // Use subcategory data for specific product filtering
    $products = $api->getProducts([
        'subcategory_id' => $subcategory['id'],
        'per_page' => 20
    ]);

    echo "<h2>Products in: " . htmlspecialchars($subcategory['name']) . "</h2>\n";
    echo "<div class='product-grid'>\n";

    foreach ($products as $product) {
        echo "<div class='product-card'>\n";
        echo "  <h3>" . htmlspecialchars($product['name']) . "</h3>\n";
        echo "  <p>Category: " . htmlspecialchars($subcategory['name']) . "</p>\n";
        echo "</div>\n";
    }

    echo "</div>\n";

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

Countries API

List Countries

Get all countries with pagination and filtering options.

GET /api/v1/countries
Authorization: Bearer {token}

Query Parameters:

ParameterTypeDescription
pageintegerPage number (default: 1)
per_pageintegerItems per page (default: 25, max: 100)

Example Response:

[
  {
    "id": 1,
    "name": "United States",
    "alpha2": "US",
    "alpha3": "USA",
    "official_name": "United States of America",
    "numeric_code": "840",
    "dialing_prefix": "+1"
  },
  {
    "id": 2,
    "name": "United Kingdom",
    "alpha2": "GB",
    "alpha3": "GBR",
    "official_name": "United Kingdom of Great Britain and Northern Ireland",
    "numeric_code": "826",
    "dialing_prefix": "+44"
  }
]

Get Country by ID

Retrieve a specific country by its unique identifier.

GET /api/v1/countries/{id}
Authorization: Bearer {token}

Example Response:

{
  "id": 1,
  "name": "United States",
  "alpha2": "US",
  "alpha3": "USA",
  "official_name": "United States of America",
  "numeric_code": "840",
  "dialing_prefix": "+1"
}

Currencies API

List Currencies

Get all currencies with pagination support.

GET /api/v1/currencies
Authorization: Bearer {token}

Query Parameters:

ParameterTypeDescription
pageintegerPage number (default: 1)
per_pageintegerItems per page (default: 25, max: 100)

Example Response:

[
  {
    "id": 1,
    "country_id": 1,
    "name": "US Dollar",
    "currency": "USD",
    "symbol": "$",
    "currency_code": "USD",
    "precision": 2
  },
  {
    "id": 2,
    "country_id": 2,
    "name": "Pound Sterling",
    "currency": "GBP",
    "symbol": "£",
    "currency_code": "GBP",
    "precision": 2
  }
]

Get Currency by ID

Retrieve a specific currency by its unique identifier.

GET /api/v1/currencies/{id}
Authorization: Bearer {token}

Example Response:

{
  "id": 1,
  "country_id": 1,
  "name": "US Dollar",
  "currency": "USD",
  "symbol": "$",
  "currency_code": "USD",
  "precision": 2
}

Code Example

Here's a basic PHP implementation for the Reference Data API:

<?php

class ReferenceDataAPI {
    private $token;
    private $baseUrl = '{{host}}';

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

    public function getCategories($page = 1) {
        return $this->makeRequest('/api/v1/categories', ['page' => $page]);
    }

    public function getCategoryById($id) {
        return $this->makeRequest("/api/v1/categories/{$id}");
    }

    public function getSubcategories($page = 1) {
        return $this->makeRequest('/api/v1/subcategories', ['page' => $page]);
    }

    public function getSubcategoryById($id) {
        return $this->makeRequest("/api/v1/subcategories/{$id}");
    }

    public function getCountries($page = 1) {
        return $this->makeRequest('/api/v1/countries', ['page' => $page]);
    }

    public function getCountryById($id) {
        return $this->makeRequest("/api/v1/countries/{$id}");
    }

    public function getCurrencies($page = 1) {
        return $this->makeRequest('/api/v1/currencies', ['page' => $page]);
    }

    public function getCurrencyById($id) {
        return $this->makeRequest("/api/v1/currencies/{$id}");
    }

    private function makeRequest($endpoint, $params = []) {
        $url = $this->baseUrl . $endpoint;
        if (!empty($params)) {
            $url .= '?' . http_build_query($params);
        }

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

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

        if ($httpCode !== 200) {
            throw new Exception("API request failed with status {$httpCode}");
        }

        return json_decode($response, true);
    }
}

// Usage
$api = new ReferenceDataAPI('your_token_here');

try {
    $categories = $api->getCategories();
    $countries = $api->getCountries();
    $currencies = $api->getCurrencies();

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

Response Fields

Category Fields

FieldTypeDescription
idintegerUnique category identifier
namestringDisplay name of the category

Subcategory Fields

FieldTypeDescription
idintegerUnique subcategory identifier
namestringDisplay name of the subcategory

Country Fields

FieldTypeDescription
idintegerUnique country identifier
namestringCommon country name
alpha2stringISO 3166-1 alpha-2 country code
alpha3stringISO 3166-1 alpha-3 country code
official_namestringOfficial country name
numeric_codestringISO 3166-1 numeric country code
dialing_prefixstringInternational dialing prefix

Currency Fields

FieldTypeDescription
idintegerUnique currency identifier
country_idintegerAssociated country ID
namestringFull currency name
currencystringCurrency abbreviation
symbolstringCurrency symbol
currency_codestringISO currency code
precisionintegerDecimal precision for amounts

Common Use Cases

Building Product Filters

Use categories and subcategories to create hierarchical product filters:

  1. Fetch all categories for top-level navigation

    GET /api/v1/categories?per_page=100
  2. Load subcategories for detailed filtering

    GET /api/v1/subcategories?per_page=100
  3. Use category/subcategory IDs in product search queries

    GET /api/v1/products?category_id=1&subcategory_id=101

Example Implementation:

// Build category filter dropdown
$categories = $api->getCategories(1, 100);
foreach ($categories as $category) {
    echo "<option value='{$category['id']}'>{$category['name']}</option>";
}

// Filter products by category
$giftCardProducts = $api->getProducts(['category_id' => 1]);

Localization and Currency Display

Combine country and currency data for proper localization:

  1. Get user's country from their profile or IP geolocation

    $userCountryCode = 'US'; // From user profile or IP detection
    $countries = $api->getCountries();
    $userCountry = array_filter($countries, function($c) use ($userCountryCode) {
        return $c['alpha2'] === $userCountryCode;
    })[0];
  2. Fetch associated currency information

    $currencies = $api->getCurrencies();
    $userCurrency = array_filter($currencies, function($c) use ($userCountry) {
        return $c['country_id'] === $userCountry['id'];
    })[0];
  3. Use currency precision and symbols for proper price formatting

    function formatPrice($amount, $currency) {
        $formatted = number_format($amount, $currency['precision']);
        return $currency['symbol'] . $formatted;
    }
    
    // Usage: $12.50, €15.00, £10.99
    echo formatPrice(12.50, $userCurrency);

Product Availability by Region

Reference data helps determine product availability:

Example: Check if products are available in user's country

function isProductAvailableInCountry($productCountryIds, $userCountryId) {
    return in_array($userCountryId, $productCountryIds);
}

// Get user's country
$userCountry = $api->getCountryById($userCountryId);

// Check product availability
$product = $api->getProductById(1001);
if (isProductAvailableInCountry($product['supported_countries'], $userCountry['id'])) {
    echo "✓ Available in {$userCountry['name']}";
} else {
    echo "✗ Not available in {$userCountry['name']}";
}

Real-World Integration Examples

1. Multi-Currency Checkout Flow

class CheckoutProcessor {
    private $api;

    public function processCheckout($userId, $productId, $amount) {
        // Get user's country and currency
        $user = $this->getUserById($userId);
        $country = $this->api->getCountryById($user['country_id']);
        $currency = $this->api->getCurrencyById($user['preferred_currency']);

        // Format price with proper currency
        $formattedPrice = $this->formatPrice($amount, $currency);

        // Display checkout summary
        return [
            'product_id' => $productId,
            'amount' => $amount,
            'formatted_price' => $formattedPrice,
            'currency_code' => $currency['currency_code'],
            'country' => $country['name']
        ];
    }
}

2. Dynamic Category Navigation

class CategoryNavigator {
    private $api;

    public function buildCategoryMenu() {
        $categories = $this->api->getCategories(1, 50);
        $subcategories = $this->api->getSubcategories(1, 200);

        $menu = [];
        foreach ($categories as $category) {
            $menu[$category['id']] = [
                'name' => $category['name'],
                'subcategories' => array_filter($subcategories, function($sub) use ($category) {
                    return strpos($sub['name'], $category['name']) !== false;
                })
            ];
        }

        return $menu;
    }
}

3. Currency Converter Widget

class CurrencyConverter {
    private $api;

    public function convertPrice($amount, $fromCurrencyId, $toCurrencyId) {
        $fromCurrency = $this->api->getCurrencyById($fromCurrencyId);
        $toCurrency = $this->api->getCurrencyById($toCurrencyId);

        // In a real implementation, you'd fetch exchange rates
        $exchangeRate = $this->getExchangeRate($fromCurrency['currency_code'], $toCurrency['currency_code']);
        $convertedAmount = $amount * $exchangeRate;

        return [
            'original' => $this->formatPrice($amount, $fromCurrency),
            'converted' => $this->formatPrice($convertedAmount, $toCurrency),
            'rate' => $exchangeRate
        ];
    }
}

## Error Handling

All reference data endpoints return consistent error responses:

**Common Error Codes:**
- `400 Bad Request`: Invalid parameters or ID format
- `401 Unauthorized`: Missing or invalid authentication token
- `404 Not Found`: Resource not found or inactive
- `500 Internal Server Error`: Server-side processing error

**Error Response Format:**
```json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Category not found",
    "details": {}
  }
}

Best Practices

Caching Strategy

Reference data changes infrequently, making it ideal for caching:

  • Cache categories and subcategories for 24 hours
  • Cache countries indefinitely (they rarely change)
  • Cache currencies for 1 hour (exchange rates may affect display)

Pagination

Always handle pagination for large datasets:

  • Use reasonable per_page values (25-100)
  • Check X-Total-Pages header for complete data
  • Implement client-side pagination for better user experience

Data Validation

Validate reference data IDs before making API calls:

  • Ensure IDs are positive integers
  • Handle cases where referenced data might be inactive
  • Provide fallback options for missing reference data