Code Examples
PHP and the CurrencyCore API
Call /v1/convert and /v1/rates from PHP with cURL, an environment variable, a timeout, and error handling.
There is no official PHP SDK, so the cURL client below is the supported raw HTTP path. The extension is available in most PHP deployments and gives you explicit control over timeouts and status handling. This client separates transport failures from API errors, keeps the stable error code, and never puts the key in a URL.
The example needs PHP 8 or later with cURL. Free includes 1,000 requests per month at 60 per minute. Live keys require a paid plan; test keys use the same reference data and quota, capped at 60 per minute. Read CURRENCYCORE_API_KEY from the environment, not from a committed file.
<?php
class CurrencyCoreException extends RuntimeException
{
public function __construct(
public string $errorCode,
string $message,
public int $httpStatus
) {
parent::__construct($message);
}
}
function currencyCoreGet(string $path, array $params = []): array
{
$key = getenv("CURRENCYCORE_API_KEY");
if ($key === false || $key === "") {
throw new RuntimeException("Set CURRENCYCORE_API_KEY");
}
$url = "https://api.currency-core.com/v1" . $path;
if ($params !== []) {
$url .= "?" . http_build_query($params);
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 3,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . $key,
"Accept: application/json",
],
]);
$body = curl_exec($ch);
if ($body === false) {
$message = curl_error($ch);
curl_close($ch);
throw new RuntimeException("CurrencyCore request failed: " . $message);
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
try {
$payload = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
throw new RuntimeException("Invalid JSON from CurrencyCore", 0, $e);
}
if ($status >= 400) {
throw new CurrencyCoreException(
$payload["error"]["code"] ?? "http_error",
$payload["error"]["message"] ?? "HTTP " . $status,
$status
);
}
return $payload;
}
$conversion = currencyCoreGet("/convert", [
"from" => "USD",
"to" => "INR",
"amount" => 100,
]);
$rates = currencyCoreGet("/rates/EUR");
echo $conversion["results"][0]["result"], PHP_EOL;
echo $rates["rates"]["USD"], PHP_EOL;
/v1/convert returns one entry per target, and /v1/rates/{base} returns a map with the base at 1:
{
"from": "USD",
"amount": 100,
"date": "2026-11-10",
"results": [{ "to": "INR", "result": 8345.0, "rate": 83.45 }]
}
{ "base": "EUR", "date": "2026-11-10", "rates": { "EUR": 1, "USD": 1.0861 } }
Catch CurrencyCoreException and branch on errorCode. 400 means invalid input, 401 a bad key, 403 a plan gate or the Free 30-day window, and 429 a rate limit. Honor Retry-After and do not retry the other 4xx responses.
Cache by the response date and the query string. Historical values are stable for normal caching; today’s snapshot should follow your own freshness requirement, since the underlying fixings are daily.
Next steps
- API reference and OpenAPI specification
- Authentication and error codes
- Laravel guide for a framework integration
- All developer guides