Overview

The ByteFLASH Tuning Data API gives authorised partners programmatic access to our vehicle tuning database. You can retrieve manufacturer lists, models, generation ranges, and detailed Stage 1 tuning figures (stock and tuned horsepower & torque, plus ECU types) to display on your own website.

Base URL
https://www.byteflash.co.uk/api/v1/
Format
JSON (UTF-8)
Authentication
API key (header or query param)

All responses share this envelope structure:

{
  "success": true,
  "count":   42,          // number of items returned (where applicable)
  "data_key": [ ... ]    // payload: key name varies per endpoint
}

// On error:
{
  "success": false,
  "error":   "Human-readable error message"
}

Authentication

Every request must include your API key. There are two ways to send it; the header method is strongly preferred for server-side code, as the key will not appear in server logs or browser history.

Method 1: HTTP Header (recommended)

// Add this header to every request:
X-API-Key: bf_your_key_here

Method 2: Query Parameter

https://www.byteflash.co.uk/api/v1/?action=manufacturers&api_key=bf_your_key_here
Avoid the query-parameter method in production. Your key will appear in browser network tools, server access logs, and any analytics package that records full URLs. Use it only for quick local testing.

Your API key was provided to you by ByteFLASH. Treat it like a password; it is only sent to you once. If you ever lose it or suspect it has been compromised, contact us and we will issue a replacement immediately.

Errors & Status Codes

HTTP CodeMeaningCommon cause
200 OKSuccessNormal response
400 Bad RequestMissing or invalid parameterForgot manufacturer_id, unknown action
401 UnauthorizedNo key or wrong keyMissing or incorrect X-API-Key
403 ForbiddenKey valid but access deniedKey suspended, or request from a domain not on your whitelist
429 Too Many RequestsRate limit exceededOver your hourly allowance; check the Retry-After response header

Always check success === true before using the payload:

$data = json_decode($response, true);

if (!$data['success']) {
    // log or display $data['error']
    throw new RuntimeException('API error: ' . $data['error']);
}

Rate Limiting

Your API key has a request limit per rolling hour. When that limit is exceeded the API returns HTTP 429 Too Many Requests along with a Retry-After: 3600 header. If you need a higher limit, please get in touch with us.

Best practice: cache responses on your side. The vehicle database changes infrequently, so caching for 1–24 hours will keep you well within your limit even on busy sites, and makes your pages faster. See the caching example below.

Endpoints

All endpoints are GET requests to the same base URL; the action parameter selects the operation.

GET ?action=manufacturers

Returns all vehicle manufacturers in the database, with a logo URL and model count for each.

Parameters: none beyond action.

Example response:

{
  "success":       true,
  "count":         79,
  "manufacturers": [
    {
      "id":          5,
      "name":        "Audi",
      "logo_url":    "https://www.byteflash.co.uk/images/brands/Audi.png",
      "model_count": 18
    },
    {
      "id":          7,
      "name":        "BMW",
      "logo_url":    "https://www.byteflash.co.uk/images/brands/BMW.png",
      "model_count": 22
    }
    // ... more manufacturers
  ]
}
Logo URLs: logo_url will be null for any manufacturer where we do not hold a logo image. Always check for null before rendering an <img> tag, or fall back to displaying the name as text.

GET ?action=models&manufacturer_id={id}

Returns all models for a given manufacturer.

ParameterTypeRequired?Description
manufacturer_idintegerRequiredID from the manufacturers endpoint

Example response:

{
  "success":      true,
  "count":        22,
  "manufacturer": {
    "id":       7,
    "name":     "BMW",
    "logo_url": "https://www.byteflash.co.uk/images/brands/BMW.png"
  },
  "models": [
    { "id": 75, "name": "1 Series", "generation_count": 4 },
    { "id": 76, "name": "2 Series", "generation_count": 3 }
    // ...
  ]
}

GET ?action=generations&model_id={id}

Returns all generation/year ranges for a given model.

ParameterTypeRequired?Description
model_idintegerRequiredID from the models endpoint

Example response:

{
  "success":      true,
  "count":        4,
  "manufacturer": { "id": 7, "name": "BMW", "logo_url": "https://..." },
  "model":        { "id": 75, "name": "1 Series" },
  "generations": [
    { "id": 160, "label": "E87 - 2004 - 2007", "variant_count": 12 },
    { "id": 161, "label": "E82 - 2007 - 2013", "variant_count": 9  }
    // ...
  ]
}

GET ?action=variants&generation_id={id}

Returns all tuning variants (engine configurations) for a generation, with full performance figures.

ParameterTypeRequired?Description
generation_idintegerRequiredID from the generations endpoint

Example response:

{
  "success":      true,
  "count":        12,
  "manufacturer": { "id": 7, "name": "BMW", "logo_url": "https://..." },
  "model":        { "id": 75, "name": "1 Series" },
  "generation":   { "id": 160, "label": "E87 - 2004 - 2007" },
  "variants": [
    {
      "id":              825,
      "engine_label":   "116i 115hp",
      "fuel":           "Petrol",
      "engine_size_cc":  1596,
      "power": {
        "stock_hp": 115,  "tuned_hp": 128,  "gain_hp": 13,
        "stock_nm": 150,  "tuned_nm": 165,  "gain_nm": 15
      },
      "ecus": [ "Bosch ME9.2" ]
    },
    {
      "id":              826,
      "engine_label":   "118D 122hp",
      "fuel":           "Diesel",
      "engine_size_cc":  1995,
      "power": {
        "stock_hp": 122,  "tuned_hp": 155,  "gain_hp": 33,
        "stock_nm": 280,  "tuned_nm": 340,  "gain_nm": 60
      },
      "ecus": [ "Bosch EDC16C35" ]
    },
    {
      "id":              827,
      "engine_label":   "118i 129hp",
      "fuel":           "Petrol",
      "engine_size_cc":  1995,
      "power": {
        "stock_hp": 129,  "tuned_hp": 145,  "gain_hp": 16,
        "stock_nm": 180,  "tuned_nm": 200,  "gain_nm": 20
      },
      "ecus": [ "Bosch MEV946", "Bosch MEV1746" ]
    }
    // ... more variants
  ]
}
Any field within power (stock_hp, tuned_hp, etc.) may be null where figures are not available for that engine. Always null-check before doing arithmetic or display.

Returns the complete hierarchy (manufacturers → models → generations → variants) in a single call. Useful for building a vehicle lookup widget without multiple round-trips.

ParameterTypeRequired?Description
makestringRequiredManufacturer name; partial match, case-insensitive. e.g. BMW or vw
modelstringOptionalModel name filter. e.g. 3 Series
generationstringOptionalGeneration label filter. e.g. F30

Example URL:

https://www.byteflash.co.uk/api/v1/?action=search&make=BMW&model=1+Series&api_key=bf_your_key

PHP Code Examples

All examples use PHP's built-in file_get_contents() with a stream context; no additional libraries required.

Basic request: fetch all manufacturers

<?php

$api_key  = 'bf_your_key_here';
$base_url = 'https://www.byteflash.co.uk/api/v1/';

// Build the request with the API key in a header
$context = stream_context_create([
    'http' => [
        'header'  => 'X-API-Key: ' . $api_key,
        'timeout' => 10,
    ]
]);

$url  = $base_url . '?action=manufacturers';
$json = file_get_contents($url, false, $context);

if ($json === false) {
    die('Could not reach the API.');
}

$data = json_decode($json, true);

if (!$data['success']) {
    die('API error: ' . $data['error']);
}

foreach ($data['manufacturers'] as $mfr) {
    echo $mfr['name'] . ' (' . $mfr['model_count'] . ' models)' . PHP_EOL;
}

Reusable API client class

For real projects, wrap the API calls in a simple class to avoid repetition:

<?php

class ByteFlashApi
{
    private $api_key;
    private $base_url = 'https://www.byteflash.co.uk/api/v1/';

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

    /**
     * Low-level request. Returns decoded array or throws on error.
     */
    private function request(string $action, array $params = []): array
    {
        $params['action'] = $action;
        $url = $this->base_url . '?' . http_build_query($params);

        $context = stream_context_create([
            'http' => [
                'header'  => 'X-API-Key: ' . $this->api_key,
                'timeout' => 10,
            ]
        ]);

        $json = file_get_contents($url, false, $context);

        if ($json === false) {
            throw new RuntimeException('ByteFlash API: network error.');
        }

        $data = json_decode($json, true);

        if (!isset($data['success'])) {
            throw new RuntimeException('ByteFlash API: invalid JSON response.');
        }

        if (!$data['success']) {
            throw new RuntimeException('ByteFlash API error: ' . $data['error']);
        }

        return $data;
    }

    public function getManufacturers(): array
    {
        return $this->request('manufacturers')['manufacturers'];
    }

    public function getModels(int $manufacturer_id): array
    {
        return $this->request('models', ['manufacturer_id' => $manufacturer_id])['models'];
    }

    public function getGenerations(int $model_id): array
    {
        return $this->request('generations', ['model_id' => $model_id])['generations'];
    }

    public function getVariants(int $generation_id): array
    {
        return $this->request('variants', ['generation_id' => $generation_id])['variants'];
    }

    public function search(string $make, string $model = '', string $generation = ''): array
    {
        $params = ['make' => $make];
        if ($model)      $params['model']      = $model;
        if ($generation) $params['generation'] = $generation;
        return $this->request('search', $params)['results'];
    }
}

// Usage:
$api = new ByteFlashApi('bf_your_key_here');

$manufacturers = $api->getManufacturers();
$models        = $api->getModels(7);       // BMW
$generations   = $api->getGenerations(75);  // BMW 1 Series
$variants      = $api->getVariants(160);    // BMW 1 Series E87

Display a tuning results table

A complete, page-ready example. Drop it into any PHP page on your site after swapping in your key and populating $generation_id from user input.

<?php
$api_key       = 'bf_your_key_here';
$base_url      = 'https://www.byteflash.co.uk/api/v1/';
$generation_id = (int) ($_GET['gen'] ?? 0);

if (!$generation_id) { die('No generation selected.'); }

$context = stream_context_create(['http' => [
    'header'  => 'X-API-Key: ' . $api_key,
    'timeout' => 10,
]]);

$data = json_decode(
    file_get_contents($base_url . '?action=variants&generation_id=' . $generation_id, false, $context),
    true
);

if (!$data['success']) { die(htmlspecialchars($data['error'])); }

$mfr  = $data['manufacturer'];
$gen  = $data['generation'];
$vars = $data['variants'];
?>

<h2>
  <?php if ($mfr['logo_url']): ?>
    <img src="<?= htmlspecialchars($mfr['logo_url']) ?>"
         alt="<?= htmlspecialchars($mfr['name']) ?>"
         style="height:40px;vertical-align:middle;margin-right:10px">
  <?php endif; ?>
  <?= htmlspecialchars($data['model']['name'] . ' ' . $gen['label']) ?>
</h2>

<table>
  <thead>
    <tr>
      <th>Engine</th><th>Fuel</th>
      <th>Stock HP</th><th>Tuned HP</th><th>Gain HP</th>
      <th>Stock Nm</th><th>Tuned Nm</th><th>Gain Nm</th>
      <th>ECU(s)</th>
    </tr>
  </thead>
  <tbody>
  <?php foreach ($vars as $v): ?>
    <?php $p = $v['power']; ?>
    <tr>
      <td><?= htmlspecialchars($v['engine_label']) ?></td>
      <td><?= htmlspecialchars($v['fuel']) ?></td>
      <td><?= $p['stock_hp'] ?? '—' ?></td>
      <td><?= $p['tuned_hp'] ?? '—' ?></td>
      <td><?= $p['gain_hp'] !== null ? '+' . $p['gain_hp'] : '—' ?></td>
      <td><?= $p['stock_nm'] ?? '—' ?></td>
      <td><?= $p['tuned_nm'] ?? '—' ?></td>
      <td><?= $p['gain_nm'] !== null ? '+' . $p['gain_nm'] : '—' ?></td>
      <td><?= htmlspecialchars(implode(', ', $v['ecus'])) ?></td>
    </tr>
  <?php endforeach; ?>
  </tbody>
</table>

Rendering manufacturer logos safely

Because logo_url can be null, always provide a text fallback:

<?php foreach ($manufacturers as $mfr): ?>
<div class="brand-card">
  <?php if ($mfr['logo_url']): ?>
    <img src="<?= htmlspecialchars($mfr['logo_url']) ?>"
         alt="<?= htmlspecialchars($mfr['name']) ?> logo"
         class="brand-logo">
  <?php else: ?>
    <span class="brand-name"><?= htmlspecialchars($mfr['name']) ?></span>
  <?php endif; ?>
</div>
<?php endforeach; ?>

Caching responses (recommended)

The vehicle database changes infrequently. Caching API responses on your server speeds up your pages and means your site keeps working if the API is temporarily unreachable.

<?php

function cachedApiCall(string $url, string $api_key, int $ttl_seconds = 3600): array
{
    // Cache file lives in your temp dir; adjust path as needed
    $cache_file = sys_get_temp_dir() . '/' . 'bf_api_' . md5($url) . '.json';

    // Return cached version if it exists and is still fresh
    if (file_exists($cache_file) && (time() - filemtime($cache_file)) < $ttl_seconds) {
        return json_decode(file_get_contents($cache_file), true);
    }

    // Fetch from API
    $context = stream_context_create(['http' => [
        'header'  => 'X-API-Key: ' . $api_key,
        'timeout' => 10,
    ]]);

    $json = @file_get_contents($url, false, $context);

    if ($json === false) {
        // Network error: serve stale cache if available, otherwise fail
        if (file_exists($cache_file)) {
            return json_decode(file_get_contents($cache_file), true);
        }
        throw new RuntimeException('API unreachable and no cached data available.');
    }

    $data = json_decode($json, true);

    if (!empty($data['success'])) {
        // Only cache successful responses
        file_put_contents($cache_file, $json, LOCK_EX);
    }

    return $data;
}

// Usage: cache the manufacturer list for 6 hours:
$api_key  = 'bf_your_key_here';
$base_url = 'https://www.byteflash.co.uk/api/v1/';

$data = cachedApiCall(
    $base_url . '?action=manufacturers',
    $api_key,
    21600  // 6 hours in seconds
);

$manufacturers = $data['manufacturers'] ?? [];

Key Security & Sharing Prevention

Your API key grants access to ByteFLASH data on your behalf. If a key is leaked, someone else could consume your request allowance. Here is what we do to protect you, and what you should do on your side.

What we enforce on our side

MechanismHow it works
Domain whitelisting Your key can be locked to one or more specific domains. Requests arriving with a different Origin or Referer header are rejected with HTTP 403. Contact us when setting up your account to enable this.
Rate limiting Your key has a per-hour request allowance. Even if a key is accidentally shared, any misuse is automatically bounded.
Request logging Every request is recorded with its IP address and origin domain. Unusual activity is monitored and may result in a key being suspended.
Instant revocation If your key is ever compromised, contact us and we can suspend or replace it immediately; the old key stops working straight away.
One-way key storage Keys are stored as a cryptographic hash. Even in the event of a database breach, the raw key values cannot be recovered.

What you should do

  • Never put your API key in client-side JavaScript. Anyone viewing your page source can steal it. Always make API calls from server-side PHP, then pass the resulting data to the browser as HTML or your own JSON.
  • Ask us to lock your key to your domain. This alone prevents almost all casual key theft.
  • Store the key in a config file or environment variable outside your web root, not hardcoded in PHP files that might end up in a repository.
  • Contact us immediately if you believe your key has been seen by someone who should not have it; we will issue a replacement straight away.
Never do this: key visible in browser source and network tools:
<script>
  fetch('https://www.byteflash.co.uk/api/v1/?action=manufacturers&api_key=bf_your_key')
    .then(r => r.json()).then(data => console.log(data));
</script>
Do this instead: Call the API from your server-side PHP and output the data directly into your page HTML, or serve it through your own endpoint; your API key never leaves your server.