Run a scheduled data pull into a sheet or database with n8n, Zapier or Make

To pull data on a schedule without code, set up a GET request to the Narwhal API with an Authorization header in n8n, Zapier or Make, then write the fields it returns to a sheet or a database table on each run.

The request every tool sends

n8n, Zapier and Make all do the same thing at each run: a GET request to a URL with one header, followed by a step that reads fields from the JSON. The first request asks for the US dollar against the euro and the rupiah. The response has a rates list with one entry per currency.

curl, USD to EUR and IDR
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
  "https://api.narwhalapi.com/v1/fx/rates/USD?currencies=EUR,IDR"
Response
{
  "base": "USD",
  "market_session": "open",
  "rates": [
    {"currency": "EUR", "rate": "0.89432", "timestamp": "2026-11-03T02:30:26.386063Z", "stale": false},
    {"currency": "IDR", "rate": "18135.2", "timestamp": "2026-11-03T02:30:26.386063Z", "stale": false}
  ]
}

A flow that stores one row per currency has to split the rates list into separate items. The second request, the gold spot price, returns a single object, so its fields map directly to one row.

curl, the gold spot price
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
  "https://api.narwhalapi.com/v1/commodities/spot/XAU/USD"
Response
{
  "symbol": "XAU-USD",
  "commodity_key": "gold",
  "price": "3947.2646",
  "currency": "USD",
  "unit": "troy_ounce",
  "unit_key": "troy_ounce",
  "timestamp": "2026-11-03T02:30:00Z",
  "stale": false
}

Set the header and keep the key out of the URL

The only header a data request needs is Authorization, with the value Bearer followed by your key. Put it in the credential store of the tool, so the key is not visible in the flow or copied with it.

SettingValue
MethodGET
URLhttps://api.narwhalapi.com/v1/fx/rates/USD, with currencies as a query parameter set to EUR,IDR
Header nameAuthorization
Header valueBearer YOUR_KEY
Response formatJSON, parsed by the tool

Put query parameters in the tool's own parameter list rather than building the string by hand. The path, such as /v1/commodities/spot/XAU/USD, goes in the URL field.

Build the flow in each tool

  1. n8n Add a Schedule Trigger, then an HTTP Request node set to GET with the URL and query parameter above. For authentication choose Generic Credential Type and Header Auth, with the name Authorization and the value Bearer YOUR_KEY. Add a Split Out node on the field rates, then a Google Sheets node to append a row or a Postgres node to insert one. Read the fields as {{ $json.currency }}, {{ $json.rate }} and {{ $json.timestamp }}.
  2. Zapier Use Schedule by Zapier as the trigger and Webhooks by Zapier with Custom Request as the action. Choose GET, enter the URL and add the Authorization header. Webhooks by Zapier is a premium app, so check that your Zapier plan includes it. Add a Looping or Formatter step for the rates list, then a Google Sheets action to create a spreadsheet row for each item.
  3. Make Set the schedule on the first module with its clock icon. Add the HTTP module, choose Make a request, set the method to GET, enter the URL and the header, and set Parse response to Yes. The parsed list appears under data, so add an Iterator on data.rates, then a Google Sheets Add a Row module or a database module.

For the gold request there is no list to split. Read price and timestamp from the response object, which is data.price in Make.

Choose the schedule and count the requests

Each run sends one request for every URL in the flow, and each successful request costs one call. A flow that calls the two URLs above once a day sends 2 requests a day, 62 over a 31-day month. The same flow run every hour sends 48 a day, or 1,488 over 31 days. Pick the interval from how often you read the numbers, not from how often the tool allows.

The schedule a daily data pull guide covers daily timing and a script version of the same job. If your flow needs more than a daily sample, the stream guide covers a WebSocket, which these tools do not provide. They poll.

Store the result

A sheet or a table needs the same few columns whichever tool writes it. Keep the time of the price beside the price, because the time the flow ran is not the time the rate was set.

ColumnSourceWhy keep it
currencyrates[].currencyNames the quote currency
raterates[].rateThe value, kept as the text the API sent
quoted_atrates[].timestampWhen the rate was set
stalerates[].staleLets a later query leave out rows marked out of date
pulled_atThe tool's run timeWhen your flow ran

In a database, add a unique key on currency and quoted_at and make the insert skip a row that exists. A run that repeats, or a retry after a failure, then writes nothing new. In a sheet, append one row per run and filter the duplicates later.

Can I put the API key in the URL?

Keep it in the header, stored in the tool's credential. The request on this page sends the key only as Authorization: Bearer YOUR_KEY, and the URL carries just the endpoint and its parameters. The same key and credit serve every one of the Narwhal data APIs, so one credential covers every request the flow makes.

What should the flow do on a 429?

Read the code in the problem body. A 429 with rate_limit_exceeded includes a Retry-After header, so add a delay of that length and try again. A 402 with insufficient_credits means your balance is used up, so a retry will not help until you add credit. Neither response is charged. In n8n turn on retry on fail for the HTTP node, and in Zapier or Make add a delay step and an error route. The 429 guide explains both codes.

Published .

Next steps