TutorialesCódigo

Cómo obtener precios del oro en tiempo real en PHP

Consulta la API de goldprice.dev desde PHP con cURL nativo, BCMath para cálculos exactos, reintentos ante 429 y caché de 60 segundos, sin Composer.

26 jun 2026 · 4 min de lectura

Para obtener precios del oro en tiempo real en PHP, envía un GET a api.goldprice.dev/v1/spot/XAU-USD-SPOT con tu clave en la cabecera X-API-Key. Usa cURL nativo, sin Composer. Decodifica el JSON, conserva los precios como cadenas y calcula con BCMath. Guarda cada símbolo en caché durante 60 segundos. El plan gratuito incluye 5.000 consultas/mes, sin tarjeta. Probado en junio de 2026 con PHP 8.3.

Obtén tu clave de API de goldprice.dev

Crea una cuenta gratuita en goldprice.dev/onboarding. Tras confirmar tu correo, verás en tu panel una clave que empieza por ga_live_. Guárdala como variable de entorno:

Shell
export GOLDPRICE_API_KEY=ga_live_replace_with_your_key_here

El plan gratuito incluye 5.000 consultas/mes y precios al contado del oro en 31 monedas. No necesitas tarjeta.

Comprueba las extensiones necesarias

No necesitas paquetes de Composer. PHP 8 incluye curl y json; bcmath es una extensión estándar para cálculos decimales exactos. Comprueba que las tres estén activadas:

shell
php -m | grep -E '^(curl|json|bcmath)$'# curl# json# bcmath   <- if missing, install php8.3-bcmath (or enable in php.ini)

Escribe el cliente de goldprice

Guarda este código como goldprice.php. spot() almacena cada símbolo durante 60 segundos en un array estático, reintenta hasta 3 veces ante 429 con esperas exponenciales y devuelve el array decodificado. Los precios siguen siendo cadenas para que BCMath pueda calcular con precisión.

goldprice.php
<?php// php: goldprice.php, native cURL + BCMath, no Composer// curl-equivalent: https://api.goldprice.dev/v1/spot/XAU-USD-SPOTdeclare(strict_types=1);const API_BASE = 'https://api.goldprice.dev';const TIMEOUT  = 5;   // secondsconst TTL      = 60;  // secondsfinal class RateLimitedException extends RuntimeException {}final class GoldpriceClient{    private string $apiKey;    /** @var array<string, array{data: array, expires: int}> */    private static array $cache = [];    public function __construct()    {        $key = getenv('GOLDPRICE_API_KEY');        if ($key === false || $key === '') {            throw new RuntimeException('GOLDPRICE_API_KEY not set');        }        $this->apiKey = $key;    }    /**     * Fetch live spot price. Cached 60s per symbol, retries 3x on 429.     * Prices stay as strings for BCMath.     */    public function spot(string $symbol = 'XAU-USD-SPOT'): array    {        $now = time();        if (isset(self::$cache[$symbol]) && self::$cache[$symbol]['expires'] > $now) {            return self::$cache[$symbol]['data'];        }        for ($attempt = 0; $attempt < 3; $attempt++) {            try {                $data = $this->fetch($symbol);                self::$cache[$symbol] = ['data' => $data, 'expires' => $now + TTL];                return $data;            } catch (RateLimitedException) {                sleep(1 << $attempt); // 1s, 2s, 4s            }        }        throw new RateLimitedException('goldprice: 429 after 3 retries');    }    private function fetch(string $symbol): array    {        $ch = curl_init(API_BASE . '/v1/spot/' . rawurlencode($symbol));        curl_setopt_array($ch, [            CURLOPT_RETURNTRANSFER => true,            CURLOPT_TIMEOUT        => TIMEOUT,            CURLOPT_HTTPHEADER     => ['X-API-Key: ' . $this->apiKey],        ]);        $body = curl_exec($ch);        $code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);        curl_close($ch);        if ($code === 429) {            throw new RateLimitedException('rate limited');        }        if ($code !== 200 || $body === false) {            throw new RuntimeException("goldprice: unexpected status {$code}");        }        return json_decode((string) $body, true, 512, JSON_THROW_ON_ERROR);    }}$client = new GoldpriceClient();$r = $client->spot('XAU-USD-SPOT');// Prices are strings; use BCMath for exact math (e.g. price for 5 oz):$fiveOz = bcmul($r['price'], '5', 4);printf("%s-%s: %s (computed %s)\n", $r['symbol'], $r['quote_currency'], $r['price'], $r['computed_at']);printf("5 troy oz = %s %s\n", $fiveOz, $r['quote_currency']);

Ejecútalo

Ejecuta el archivo desde la CLI en la terminal donde exportaste GOLDPRICE_API_KEY. La primera llamada consulta la API; las siguientes llamadas a spot() en el mismo proceso durante 60 segundos devuelven el array en caché. La caché estática pertenece al proceso. Usa APCu o Redis para compartirla entre solicitudes de PHP-FPM.

shell
php goldprice.php# XAU-USD: 4012.75 (computed 2026-10-23T07:00:18.221118+00:00)# 5 troy oz = 20063.7500 USD

Cambia de moneda o metal

Los símbolos siguen el formato METAL-CURRENCY-SPOT. Pasa a spot() cualquiera de las 31 monedas al contado. Cada símbolo tiene su propia caché en el array estático. Una página con 5 símbolos hace como máximo 5 llamadas sin caché y las reutiliza si vuelve a renderizarse dentro del intervalo.

goldprice.php · varias monedas
$client = new GoldpriceClient();// USD spot, default$client->spot('XAU-USD-SPOT');$client->spot('XAU-INR-SPOT');$client->spot('XAU-EUR-SPOT');// Silver in USD$client->spot('XAG-USD-SPOT');

Resultado esperado

JSON
{  "symbol": "XAU",  "quote_currency": "USD",  "unit": "troy_ounce",  "contract_type": "spot",  "price": "4012.75",  "is_stale": false,  "computed_at": "2026-10-23T07:00:18.221118+00:00"}

La CLI imprime dos líneas: símbolo, moneda, precio y fecha y hora; después, el producto calculado con BCMath para 5 onzas troy. Tu código utiliza el array decodificado, con los precios como cadenas.

Errores comunes

CódigoQué vesSolución
401RuntimeException: goldprice: unexpected status 401Falta la clave de API o no es válida. Comprueba que PHP recibe la variable: php -r 'echo getenv("GOLDPRICE_API_KEY");'. PHP-FPM no comparte las variables de la CLI. Configura la clave con fastcgi_param o tu gestor de procesos. Si está vacía, cópiala de nuevo desde tu panel.
429Los tres reintentos con esperas devuelven 429 y se lanza RateLimitedExceptionHas alcanzado el límite por minuto. La caché de 60 segundos lo evita con tráfico regular. En PHP-FPM, la caché estática pertenece a cada solicitud. Usa APCu (apcu_fetch / apcu_store) para compartirla entre solicitudes. Para un volumen elevado y continuo, consulta los planes de pago en /pricing.
N/AErrores de redondeo al convertir los precios a float para calcularNo conviertas el precio a (float) antes de calcular: los números en coma flotante de PHP pierden precisión al sumar. Conserva la cadena de la API y usa bcadd, bcmul y bccomp con una escala explícita. Activa la extensión bcmath si esas funciones no están definidas.

Más opciones

  • Usa apcu_store / apcu_fetch para compartir la caché estática y atender a los procesos PHP-FPM con una consulta durante los 60 segundos
  • Añade un método bars() para /v1/bars?symbol=XAU-USD-SPOT&interval=1d&from=...&to=... y representa los datos con tu motor de plantillas
  • Encapsula spot() en un servicio sencillo de Laravel o Symfony y regístralo en el contenedor para inyectar dependencias
  • Añade una comprobación If-None-Match / ETag si varios procesos consultan el mismo símbolo, para evitar respuestas con datos sin cambios
  • Usa bcdiv con el factor de conversión de onzas troy a gramos para mostrar precios por gramo al público

Preguntas

¿Cada cuánto se actualiza el precio?

El endpoint al contado se actualiza cada 60 segundos. Free y el acceso sin clave llevan 15 minutos de retraso; los planes de pago ofrecen precios en tiempo real. El TTL de 60 segundos sigue ese ritmo: las llamadas a spot() durante ese intervalo devuelven el array en caché sin otra solicitud HTTP.

¿La actualización automática cabe en el plan gratuito?

Depende del tráfico. Consultar en cada solicitud sin caché puede superar las 5.000 llamadas/mes gratuitas. Comparte la caché con APCu para atender varias solicitudes con una consulta. Los sitios que consultan pocas veces por hora quedan dentro del límite. Para un volumen elevado y continuo, consulta los planes de pago en /pricing.

¿Puedo usarlo comercialmente?

Todos los planes permiten el uso comercial. Los planes de pago no exigen un enlace de atribución. Free requiere un enlace visible a goldprice.dev junto a los precios.

¿Por qué usar BCMath en lugar de float?

Los float de PHP usan doble precisión IEEE-754: 0.1 + 0.2 da 0.30000000000000004. Los errores se acumulan. Los precios tienen 2 decimales; sumar miles con float introduce errores de puntos básicos. BCMath calcula directamente con cadenas decimales y una escala fija para mantener totales exactos.

¿No necesito Composer ni Guzzle?

Correcto. PHP 8 incluye curl y json; solo necesitas configurar la clave. Si ya usas Guzzle, sustituye curl_* por un cliente Guzzle con middleware de reintentos. La solicitud sigue siendo un GET con la cabecera X-API-Key.

¿Qué metales están disponibles?

Puedes consultar oro (XAU), plata (XAG) y cobre (HG). Ningún plan ofrece platino ni paladio. Cambia el código del metal en el símbolo, por ejemplo: $client->spot("XAG-USD-SPOT").

¿Puedo pedirle a Claude que escriba el código?

Sí. Abre Claude Desktop con el servidor MCP de goldprice.dev y pide: Crea un cliente PHP 8 para /v1/spot de goldprice.dev con cURL nativo, sin Composer, caché estática por símbolo de 60 segundos, reintentos ante 429 con esperas exponenciales y precios como cadenas para BCMath. Lee GOLDPRICE_API_KEY. El MCP proporciona el esquema con los campos correctos.

Sigue leyendo

Empieza con una clave API gratis

5.000 solicitudes al mes en el plan gratuito. Sin tarjeta de crédito.

Obtén una clave gratis