Germany Carbon Intensity Spot Price

Germany Carbon Intensity Spot Price

You need to fetch the Germany Carbon Intensity spot price programmatically and embed it into a PHP application with clean error handling and practical operational details. By the end of this guide, you’ll be able to call the Energy API for the Germany Carbon Intensity symbol, parse the response fields you actually need, and productionize the integration with caching and retries.

What the symbol represents and what you will build

This guide focuses on the Energy API symbol “Germany Carbon Intensity” (code: CARBON_INT_DE), reported in gCO2/kWh. You will set up a GET workflow to retrieve the latest rate for this symbol, then wire it into PHP and a small Python script for verification. You’ll handle success and error envelopes, and understand which fields to read and how to cache appropriately.

Illustration: Germany Carbon Intensity Spot Price
  • Symbol name: Germany Carbon Intensity
  • Symbol code: CARBON_INT_DE
  • Unit: gCO2/kWh
  • Authentication: api_key query parameter (use YOUR_API_KEY only in examples)
  • Plan notes: Starter $19.99/mo, 7-day trial with 50 calls

Important field paths to read from the latest endpoint: rates.CARBON_INT_DE, dates.CARBON_INT_DE, currencies.CARBON_INT_DE. The response’s base may be MIXED.

Endpoint, authentication, and request shape

You will use a single read endpoint to pull the latest value for the symbol:

  • HTTP method: GET
  • Endpoint: https://energy-api.com/api/v1/latest
  • Required query params:
    • symbols: CARBON_INT_DE
    • api_key: YOUR_API_KEY

Notes:

  • Do not append base=USD when your request also includes TTF_GAS or EUA_CO2 in the symbols list. For a single-symbol call to CARBON_INT_DE, a base parameter is not required.
  • The base in the response may be MIXED, and you should rely on currencies.{SYMBOL} to interpret units or denomination for each symbol.

For full parameter details, see the Documentation.

Quick test with cURL

Use a terminal to validate connectivity and authentication. Replace YOUR_API_KEY with your real key in your environment or shell history as appropriate.

curl -G "https://energy-api.com/api/v1/latest" --data-urlencode "symbols=CARBON_INT_DE" --data-urlencode "api_key=YOUR_API_KEY"

If the symbol is online and available, you will receive a success envelope. The official sample below demonstrates the structure and fields of a success response (note: the symbol in this sample is OMIE_ES_DA; use the same field structure for CARBON_INT_DE):

{
"success": true,
"date": "2026-11-14",
"base": "EUR",
"rates": {
"OMIE_ES_DA": 169.4824
},
"dates": {
"OMIE_ES_DA": "2026-11-14"
},
"currencies": {
"OMIE_ES_DA": "EUR"
},
"base_filter_note": null,
"missing_symbols": null
}

Field usage you’ll replicate for CARBON_INT_DE:

  • success: Boolean indicating whether the call returned prices.
  • date: The API’s evaluation or publication date for the batch.
  • rates.{SYMBOL}: The numeric value for the symbol (for carbon intensity, gCO2/kWh).
  • dates.{SYMBOL}: The date the specific symbol value corresponds to.
  • currencies.{SYMBOL}: The denomination or unit context for the symbol; for CARBON_INT_DE, treat this as the unit context (gCO2/kWh).
  • base: May be MIXED; always prefer currencies.{SYMBOL} for symbol-level interpretation.

Handling real-world availability and errors

In practice, a symbol may be temporarily unavailable. The live call for CARBON_INT_DE did not succeed at the time of capture. You must handle this gracefully and surface a clear status in your app while avoiding hard failures.

Here is the real error envelope returned for CARBON_INT_DE. Copy it as-is to reproduce and test your error path:

{"success":false,"error":"Symbol CARBON_INT_DE is not currently available. See \/api\/v1\/symbols for the current catalog."}

Recommendations for error handling:

  • Detect success === false and log error for observability.
  • Serve a cached value if you have one that is still within your staleness threshold.
  • Fail soft in the UI: display a “Temporarily unavailable” banner and omit the numeric widget.
  • Set up a retry with exponential backoff; do not hammer the endpoint.

PHP implementation: from request to safe parsing

The following PHP example performs a GET request, decodes JSON, validates the envelope, and reads the fields for CARBON_INT_DE. It includes error handling and a minimal caching strategy using the filesystem. Adjust caching to match your operational constraints.

PHP: simple client with file cache

<?php
declare(strict_types=1);

// Configuration
$apiBase = 'https://energy-api.com/api/v1/latest';
$symbol = 'CARBON_INT_DE';
$apiKey = 'YOUR_API_KEY'; // store securely in env/secret manager in production

// Very lightweight cache
$cacheFile = __DIR__ . '/carbon_int_de_cache.json';
$cacheTtlSeconds = 300; // 5 minutes

function readCache(string $file, int $ttl): ?array {
if (!file_exists($file)) {
return null;
}
$age = time() - filemtime($file);
if ($age > $ttl) {
return null;
}
$raw = file_get_contents($file);
if ($raw === false) {
return null;
}
$data = json_decode($raw, true);
return is_array($data) ? $data : null;
}

function writeCache(string $file, array $data): void {
@file_put_contents($file, json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
}

function fetchLatest(string $baseUrl, string $symbol, string $apiKey): array {
$query = http_build_query([
'symbols' => $symbol,
'api_key' => $apiKey,
], '', '&', PHP_QUERY_RFC3986);

$url = $baseUrl . '?' . $query;

$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_HTTPHEADER => [
'Accept: application/json',
],
]);
$body = curl_exec($ch);
$errNo = curl_errno($ch);
$errMsg = curl_error($ch);
$status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($errNo !== 0) {
throw new RuntimeException("HTTP transport error: {$errMsg}", $errNo);
}
if ($status < 200 || $status >= 300) {
throw new RuntimeException("Unexpected HTTP status: {$status}");
}

$data = json_decode($body, true);
if (!is_array($data)) {
throw new RuntimeException('Invalid JSON response');
}
return $data;
}

// 1) Try live fetch
try {
$json = fetchLatest($apiBase, $symbol, $apiKey);

if (!isset($json['success']) || $json['success'] !== true) {
// Error envelope from API
$msg = isset($json['error']) ? (string)$json['error'] : 'Unknown API error';
// Try cache as fallback
$cached = readCache($cacheFile, $cacheTtlSeconds);
if ($cached !== null && isset($cached['rates'][$symbol])) {
$rate = $cached['rates'][$symbol];
$date = $cached['dates'][$symbol] ?? ($cached['date'] ?? 'n/a');
$unit = $cached['currencies'][$symbol] ?? 'gCO2/kWh';
echo "USING CACHED: {$symbol} {$rate} {$unit} ({$date})\n";
// Also surface error context for observability
error_log("Live fetch failed: {$msg}");
} else {
throw new RuntimeException("Live fetch failed and no cache available: {$msg}");
}
} else {
// Success envelope
// Read the symbol-specific fields (these keys must exist for your symbol)
$rate = $json['rates'][$symbol] ?? null;
$date = $json['dates'][$symbol] ?? null;
$unit = $json['currencies'][$symbol] ?? null;

if ($rate === null) {
throw new RuntimeException("Symbol {$symbol} missing in rates");
}

// Persist to cache for fallbacks
writeCache($cacheFile, $json);

// Application output
echo "{$symbol} {$rate} " . ($unit ?? 'gCO2/kWh') . " (" . ($date ?? $json['date'] ?? 'n/a') . ")\n";
}
} catch (Throwable $e) {
// Last-resort failure path
http_response_code(503);
echo "Service unavailable for {$symbol}: " . $e->getMessage() . "\n";
}

Key points in this PHP client:

  • symbols is set to CARBON_INT_DE and api_key is passed as a query parameter.
  • On success, read rates.CARBON_INT_DE, dates.CARBON_INT_DE, currencies.CARBON_INT_DE.
  • On error or temporary unavailability, serve a cached response if recent.
  • Timeouts protect your web threads; adjust for your environment.

Python verification script

The following Python snippet makes the same call, parses the same fields, and prints a human-readable summary. Use this during development to validate deployments or run as a cron-based health check. It mirrors the success-and-error logic described above.

import os
import sys
import json
import time
import urllib.parse
import urllib.request

API_BASE = "https://energy-api.com/api/v1/latest"
SYMBOL = "CARBON_INT_DE"
API_KEY = os.environ.get("ENERGY_API_KEY", "YOUR_API_KEY")

def get_latest(symbol, api_key, timeout=10):
params = {
"symbols": symbol,
"api_key": api_key,
}
url = API_BASE + "?" + urllib.parse.urlencode(params, doseq=True)
req = urllib.request.Request(url, headers={"Accept": "application/json"})
with urllib.request.urlopen(req, timeout=timeout) as resp:
body = resp.read().decode("utf-8")
data = json.loads(body)
return data

def main():
try:
data = get_latest(SYMBOL, API_KEY)
except Exception as e:
print(f"Transport or HTTP error: {e}", file=sys.stderr)
sys.exit(2)

if not isinstance(data, dict) or data.get("success") is not True:
# Print the error envelope and exit non-zero so monitoring can alert
print(json.dumps(data, ensure_ascii=False))
sys.exit(1)

rate = data.get("rates", {}).get(SYMBOL)
date = data.get("dates", {}).get(SYMBOL, data.get("date"))
unit = data.get("currencies", {}).get(SYMBOL, "gCO2/kWh")

if rate is None:
print("Missing symbol in rates", file=sys.stderr)
sys.exit(3)

print(f"{SYMBOL} {rate} {unit} ({date})")

if __name__ == "__main__":
main()

JSON responses you should be ready to parse

Success response example (official sample; structure identical for CARBON_INT_DE reads):

{
"success": true,
"date": "2026-11-14",
"base": "EUR",
"rates": {
"OMIE_ES_DA": 169.4824
},
"dates": {
"OMIE_ES_DA": "2026-11-14"
},
"currencies": {
"OMIE_ES_DA": "EUR"
},
"base_filter_note": null,
"missing_symbols": null
}

Same success payload, minified (useful to test your JSON parser and logging in compact form):

{"success":true,"date":"2026-11-14","base":"EUR","rates":{"OMIE_ES_DA":169.4824},"dates":{"OMIE_ES_DA":"2026-11-14"},"currencies":{"OMIE_ES_DA":"EUR"},"base_filter_note":null,"missing_symbols":null}

Real-world error envelope for CARBON_INT_DE (copy exactly; this is what you’ll see when the symbol is temporarily off-catalog):

{"success":false,"error":"Symbol CARBON_INT_DE is not currently available. See \/api\/v1\/symbols for the current catalog."}

Success envelope again for parser validation in test fixtures (official sample values):

{
"success": true,
"date": "2026-11-14",
"base": "EUR",
"rates": {
"OMIE_ES_DA": 169.4824
},
"dates": {
"OMIE_ES_DA": "2026-11-14"
},
"currencies": {
"OMIE_ES_DA": "EUR"
},
"base_filter_note": null,
"missing_symbols": null
}

In your production code for CARBON_INT_DE, read from rates.CARBON_INT_DE, dates.CARBON_INT_DE, and currencies.CARBON_INT_DE. The success-envelope structure remains the same as in the official sample.

Operational guidance: units, base, caching, and scheduling

Units and interpretation:

  • CARBON_INT_DE is measured in gCO2/kWh. Present this unit verbatim to avoid ambiguity.
  • currencies.CARBON_INT_DE is the per-symbol context you should rely on; base may be MIXED.

Base and multi-symbol calls:

  • If you later add other symbols to the same request, prefer reading currencies.{SYMBOL} for each item.
  • Do not add base=USD when you also request TTF_GAS or EUA_CO2.

Caching strategy:

  • Use a short TTL (e.g., 1–5 minutes) to smooth transient outages while keeping your display fresh.
  • On success, persist the whole envelope for debugging; it includes fields like base_filter_note and missing_symbols that can accelerate troubleshooting.

Scheduling:

  • Set fetch intervals based on your display needs and plan limits. If you render dashboards, 1–5 minute cadence is typical.
  • Stagger cron or worker jobs to avoid thundering herds at the top of the minute.

Error budgets and fallbacks:

  • When success=false, immediately fall back to cached data if it’s recent enough.
  • Alerting should trigger if the symbol remains unavailable for longer than your tolerance window.

Troubleshooting and validation

Checklist when you see no value for CARBON_INT_DE:

  • Verify the exact symbol code is CARBON_INT_DE (case-sensitive).
  • Confirm api_key is present and valid in the query string.
  • Inspect the error envelope and log it verbatim; do not assume success.
  • Confirm your parsing reads rates.CARBON_INT_DE, dates.CARBON_INT_DE, currencies.CARBON_INT_DE.

Transport sanity checks:

  • Set sensible timeouts (connect and read) to prevent thread exhaustion on the server side.
  • Implement retry with exponential backoff and jitter. Avoid infinite loops.

Schema checks in CI:

  • Pin a sample success response and error response in fixtures (use the official samples above) to validate parsers for the same envelope structure.
  • When Energy API updates catalog availability, treat it as a data change, not a schema change; your error path must remain stable.

FAQ

Q: Which fields do I actually need to display the Germany Carbon Intensity spot value?
A: rates.CARBON_INT_DE (numeric value), dates.CARBON_INT_DE (the symbol’s date), and currencies.CARBON_INT_DE (unit context, gCO2/kWh). The response’s base may be MIXED.

Q: How do I authenticate?
A: Provide your key as the api_key query parameter. In examples, use the placeholder YOUR_API_KEY. Store the real key in environment variables or a secret manager.

Q: Should I pass a base currency parameter?
A: For CARBON_INT_DE, no base parameter is required. If you also query TTF_GAS or EUA_CO2, do not pass base=USD.

Q: What if the symbol is temporarily unavailable?
A: You will receive an error envelope with success=false. Serve a cached value (with a short TTL), log the error, and retry later with backoff.

Q: Where can I find all available symbols?
A: The error message references the catalog endpoint. Check the catalog in the Documentation to confirm symbol availability.

Ready to integrate Germany’s grid carbon intensity in your app? Start your 7-day / 50-call trial and ship this workflow in minutes: Register.

Ready to get started?

Get your API key and start querying energy commodity prices in minutes.

Get API Key