Calling from a web page

Updated 2026-11-13

How to call a service from JavaScript that runs in a visitor's browser, what the service answers to the browser's cross-origin check, and why a token must stay on your server.

The short version

  • A public service can be called straight from a web page.
  • A token-protected service should be called from your server. A token placed in page code is visible to every visitor.
  • If you only want a calculator on your site, you may not need code at all: see Web snippets.

Calling a public service from a page

Browsers only let a page read an answer from another domain when that answer allows it. A successful answer of a service carries the header Access-Control-Allow-Origin: *, so a page on any domain can read it.

async function calculate(inputs) {
  const response = await fetch('https://spreadapi.io/api/v1/services/{serviceId}/execute', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ inputs }),
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data.message || data.error || 'Request failed');
  return Object.fromEntries(data.outputs.map((output) => [output.name, output.value]));
}

A POST with a JSON body makes the browser send a check first, an OPTIONS request. The service answers it and allows the methods GET and POST and the headers Content-Type and Authorization. You do not have to do anything for this.

A GET with the inputs in the address works too:

const response = await fetch('https://spreadapi.io/api/v1/services/{serviceId}/execute?amount=20000&rate=0.05');

Why a token does not belong in page code

Everything a page sends can be read by the person using it: in the page source, in the browser's developer tools, in the network log. A token in front-end code is therefore known to every visitor, who can then call your service directly with it.

For a token-protected service, put a small endpoint on your own server between the page and SpreadAPI:

  1. The page calls your server, for example /api/quote, with the input values.
  2. Your server adds the token and calls the service.
  3. Your server returns the outputs to the page.
// On your server (Node.js 18+). Load the token from a server-side secret, never from page code.
const TOKEN = loadSecret('spreadapi-token');

async function quote(inputs) {
  const response = await fetch('https://spreadapi.io/api/v1/services/{serviceId}/execute', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Bearer ' + TOKEN,
    },
    body: JSON.stringify({ inputs }),
  });
  return response.json();
}

This keeps the token secret, and it lets you check or limit what your visitors send before it reaches the service.

Public or protected for a website

A public service is fine when anyone may use the calculation: callers only ever get the outputs for the inputs they send, never the workbook or its formulas. Keep in mind that every call counts toward your plan's calls, whoever makes it.

Protect the service and call it from your server when only your own site or your customers should use it. See Tokens and access and the Security overview.

When a call fails in the browser

Successful answers carry the cross-origin header. Error answers of the calculate address, such as 400, 404 and 429, are sent without it, so the browser reports a failed request instead of showing the error text to your script.

To see the real reason:

  1. Open the browser's developer tools and look at the request in the network log. It shows the status and the answer.
  2. Or repeat the same call in API → Test or with cURL; see The API tester.
  3. Look the error up in the Error reference.

In your page, treat a failed fetch as "the calculation could not be done" and show a neutral message. When you call through your own server, your server sees the full error and can pass on what the visitor should know.

Tips

  • Check the inputs in the page before sending: required fields filled, numbers as numbers, percentages as decimals.
  • Do not call on every keystroke. Wait until the visitor pauses or presses a button; each call counts.
  • Identical calls may be answered from a stored result; see Caching and performance.
  • The service allows at most 1,000 calls per minute, all visitors together.

For developers and agents

RequestCross-origin headers in the answer
OPTIONS on the execute addressAccess-Control-Allow-Origin: *, Access-Control-Allow-Methods: GET, POST, OPTIONS, Access-Control-Allow-Headers: Content-Type, Authorization
Successful GET or POST on the execute address (JSON, CSV, plain text)Access-Control-Allow-Origin: *
Successful POST on the batch addressAccess-Control-Allow-Origin: *
OPTIONS on the batch addressAccess-Control-Allow-Origin: *, Access-Control-Allow-Methods: POST, OPTIONS, Access-Control-Allow-Headers: Content-Type, Authorization
Error answers on the execute and batch addressesNo Access-Control-Allow-Origin header
The discovery address https://spreadapi.io/d/{serviceId}Access-Control-Allow-Origin: * on every answer, errors included

The allowed request headers are Content-Type and Authorization. A request with other custom headers does not pass the browser's check. Send browser calls without credentials (the fetch default for another domain).

FAQ

Can I call my service from JavaScript on my website?

Yes, for a public service: use fetch with the execute address, as in the JavaScript snippet under API → Code. For a token-protected service, call it from your server instead.

Does the API support CORS?

Successful answers carry Access-Control-Allow-Origin: *, and the browser's OPTIONS check is answered for GET and POST with the headers Content-Type and Authorization. Pages on any domain can read successful answers.

Is it safe to put my token into front-end code?

No. Every visitor can read it in the page source or the network log and use it. Keep the token on your server and let the page call your server.

My fetch fails with a CORS error. What is wrong?

Most often the call itself failed, for example a missing input or a refused token, and error answers do not carry the cross-origin header. Look at the request in the browser's network log or repeat it in API → Test to see the real error.

How do I hide my token when my site needs a protected service?

Add a small endpoint on your own server that receives the inputs from the page, adds the token and calls the service. The token then never reaches the browser.

Can I restrict my service to my own domain?

A service is either public or token-protected; there is no setting for allowed domains. To limit use to your site, protect the service with a token and call it from your server.

Do I need code to put a calculator on my website?

No. A web snippet embeds a ready-made calculator for your service; see Web snippets.

Can I send custom headers from the browser?

The service allows the request headers Content-Type and Authorization in the browser's check. Leave other custom headers out of browser calls.

As an agent building a front end, where should the token live?

In a server-side setting of the user's own backend, never in code that is delivered to the browser. Generate a server endpoint that forwards the inputs and adds Authorization: Bearer <token>.

Do calls from my website visitors count toward my plan?

Yes. Every call to the service counts, whoever makes it; see Call limits.