PHP · Vercel Functions · vercel-php
Currency Converter
Converts between currencies using live exchange rates fetched and applied entirely server-side.
The frontend never talks to a rates API directly — a plain PHP backend fetches current exchange rates from a free, keyless API and performs the conversion before returning a single clean result.
Live demo
embed<?php
header('Content-Type: application/json');
$from = strtoupper($_GET['from'] ?? 'USD');
$to = strtoupper($_GET['to'] ?? 'CAD');
$amount = isset($_GET['amount']) ? filter_var($_GET['amount'], FILTER_VALIDATE_FLOAT) : null;
if ($amount === null || $amount === false || $amount < 0) {
http_response_code(400);
echo json_encode(['error' => 'amount must be a non-negative number']);
exit;
}
$url = 'https://open.er-api.com/v6/latest/' . urlencode($from);
$context = stream_context_create(['http' => ['timeout' => 8]]);
$response = @file_get_contents($url, false, $context);
if ($response === false) {
http_response_code(502);
echo json_encode(['error' => 'Upstream exchange rate service failed']);
exit;
}
$data = json_decode($response, true);
if (($data['result'] ?? null) !== 'success' || !isset($data['rates'][$to])) {
http_response_code(400);
echo json_encode(['error' => "Unsupported currency pair {$from}/{$to}"]);
exit;
}
$rate = $data['rates'][$to];
$result = round($amount * $rate, 4);
echo json_encode([
'from' => $from,
'to' => $to,
'amount' => $amount,
'rate' => $rate,
'result' => $result,
'updatedAt' => $data['time_last_update_utc'] ?? null,
]);
const fromSel = document.getElementById('from');
const toSel = document.getElementById('to');
const amountInput = document.getElementById('amount');
const errorBox = document.getElementById('error');
const result = document.getElementById('result');
async function convert() {
errorBox.textContent = '';
result.style.display = 'none';
const params = new URLSearchParams({
from: fromSel.value,
to: toSel.value,
amount: amountInput.value || '0',
});
const res = await fetch(`/api/convert?${params}`);
const data = await res.json();
if (!res.ok) {
errorBox.textContent = data.error || 'Conversion failed.';
return;
}
document.getElementById('amount-out').textContent = `${data.result.toLocaleString()} ${data.to}`;
document.getElementById('rate-out').textContent =
`1 ${data.from} = ${data.rate.toFixed(4)} ${data.to} · updated ${data.updatedAt}`;
result.style.display = 'block';
}
document.getElementById('go').addEventListener('click', convert);
document.getElementById('swap').addEventListener('click', () => {
const tmp = fromSel.value;
fromSel.value = toSel.value;
toSel.value = tmp;
convert();
});
convert();