Bullion API prices in n8n
Import a workflow that reads hourly weekday metal prices from Bullion API and appends each price, with its observation time, to a Google Sheet.
Prices refresh hourly on weekdays. Every price carries its own UTC observation time, and the workflow writes that time next to the price.
The sample reads gold in USD per troy ounce. Change the metal, currency or unit in the HTTP Request node.
The row the workflow appends
Placeholders show the shape. The values come from the API response at run time.
| metal | currency | unit | price | observed_at |
|---|---|---|---|---|
| gold | USD | troy_oz | <decimal string> | <UTC timestamp> |
What the workflow does
Schedule Trigger
Runs at 15 minutes past each hour, Monday to Friday, in UTC, after the hourly refresh is due.
Bullion API price
An HTTP Request calls
/v1/gold/pricewith the key in anX-API-Keyheader, taken from a Header Auth credential.Shape row
A Code node reads the observation's value and date and keeps both as text.
Append to Google Sheets
Adds one row per run. Columns are matched by name: metal, currency, unit, price and observed_at.
How fresh the prices are
Prices refresh hourly on weekdays. A run that falls between refreshes, such as the weekday 22:00 UTC hour or a manual run at the weekend, returns the newest stored observation.
Its observed_at value shows when that price was taken. If the same price and time appear on several rows, no newer observation existed when the workflow ran.
Set up n8n
- Download the workflow file and import it into n8n with its import-from-file option. It starts inactive.
- Create a Header Auth credential. Set the name to
X-API-Keyand the value to your key. Select that credential in the Bullion API price node. - Connect a Google Sheets credential. In the Append node, choose your spreadsheet and a tab named
Prices. Put the headers metal, currency, unit, price and observed_at in row 1. After the first run, check that the price cell holds a number, not text. If it holds text, set the Append node's Cell Format option to Let Google Sheets format, then run the workflow again. Then format the price column to two decimal places. - Run the workflow once and check the new row, then activate it.
Keep the key in n8n's credential store. Do not paste it into a Code node, an expression, a workflow you share, or code that runs in a browser. Until you add your key, the placeholder is bullion_YOUR_API_KEY.
Code node: keep prices as text
The Shape row node copies the API's decimal string without converting it. Round only when you display it, to two decimals.
const observation = $input.first().json.series[0].observations[0];
return [
{
json: {
metal: 'gold',
currency: 'USD',
unit: 'troy_oz',
price: observation.value,
observed_at: observation.date,
},
},
];Try the endpoints from a terminal
Set BULLION_KEY to your key first, so the key stays out of each command. The price and change endpoints return decimal strings in the requested unit. The carat endpoint returns an eight-place decimal string per gram for each karat.
export BULLION_KEY=<your key>
curl "https://api.bullionapi.dev/v1/gold/price?currency=USD&unit=troy_oz" \
-H "X-API-Key: $BULLION_KEY"
curl "https://api.bullionapi.dev/v1/silver/change?period=1w¤cy=USD&unit=troy_oz" \
-H "X-API-Key: $BULLION_KEY"
curl "https://api.bullionapi.dev/v1/gold/carat?currency=USD" \
-H "X-API-Key: $BULLION_KEY"A trimmed price response looks like this:
{
"status": "success",
"metric": "price",
"metal": "gold",
"currency": "USD",
"unit": "troy_oz",
"series": [
{
"id": "gold_price",
"observations": [{ "date": "<UTC timestamp>", "value": "<decimal string>" }]
}
]
}Errors the workflow can see
| Status | Code | What it means | What to do |
|---|---|---|---|
| 401 | missing_api_key or invalid_api_key | The header is missing, or the key is invalid or revoked. | Check the Header Auth credential. |
| 404 | not_found | No API operation exists at the URL. | Check the URL, such as the metal name. |
| 429 | rate_limited | The key has used its rolling request window. | Let the next scheduled run try again. |
| 429 | quota_exceeded | The monthly usage limit has been reached. | Check your plan on the pricing page. |
An error body has this form. The n8n node shows the status and code.
{
"status": "error",
"error": {
"code": "invalid_api_key",
"message": "Invalid or revoked API key"
}
}Building your own integration?
Use the API directly in your application.