Call a service over the API
Updated 2026-11-13
The address of a published service, how to call it with GET or POST, what a first call looks like, and the short domain. For the answer in detail see The API response.
The address
Every published service has one address:
https://spreadapi.io/api/v1/services/{serviceId}/execute{serviceId} is the ID of your service. Copy it from the service list (three dots, Copy ID or Copy Endpoint) or take the full address from API → Test on the service page.
The service must be published. A draft cannot be called; see Publish, republish and unpublish.
A first call
The fastest way is the app itself: open the service, go to API → Test, enter values and click Run Test. See The API tester.
From a terminal, with a service that has the inputs amount and rate:
curl "https://spreadapi.io/api/v1/services/{serviceId}/execute?amount=20000&rate=0.05"The answer:
{
"service": { "id": "{serviceId}", "name": "Loan", "description": null },
"inputs": [
{ "name": "amount", "title": "Amount", "value": 20000 },
{ "name": "rate", "title": "Rate", "value": 0.05 }
],
"outputs": [
{ "name": "interest", "title": "Interest", "value": 1000 }
],
"metadata": { "executionTime": 12, "totalTime": 15, "timestamp": "2026-11-13T09:00:00.000Z", "version": "v1" }
}GET: inputs in the address
Put each input into the address as name=value. GET fits Excel, Google Sheets, a browser address bar and simple tools.
GET https://spreadapi.io/api/v1/services/{serviceId}/execute?amount=20000&rate=0.05On GET, true and false are read as yes/no values and anything that looks like a number is read as a number. To send a text exactly as written, for example a code with leading zeros, use POST.
POST: inputs as JSON
Send a JSON body with an inputs object. POST is the recommended way for code.
curl -X POST "https://spreadapi.io/api/v1/services/{serviceId}/execute" \
-H "Content-Type: application/json" \
-d '{"inputs": {"amount": 20000, "rate": 0.05}}'GET and POST return the same answer.
Rules for inputs
- Use the name of an input, not its title. Names are not case-sensitive:
Amountandamountare the same. - Required inputs must be sent. An optional input you leave out takes its default, or the value the workbook holds.
- Names the service does not know are ignored.
- Send percentages as decimals:
0.05for 5%. See Percentages and formats. - Types and accepted spellings are in Data types; rules such as minimum, maximum and allowed values are in Input validation.
Token
A public service needs nothing more. A token-protected service needs a token with every call: as the header Authorization: Bearer <token>, or as ?token=<token> on GET. See Tokens and access.
The short domain
The same service also answers at a shorter address:
https://spreadapi.run/{serviceId}It behaves exactly like the long address, for GET and for POST:
https://spreadapi.run/{serviceId}?amount=20000&rate=0.05It is handy in spreadsheet formulas and wherever a long address is in the way. In API → Test you switch between the two under Domain. Everything else, such as batch calls and the OpenAPI file, lives under spreadapi.io.
Limits
- At most 1,000 calls per minute per service, all callers together.
- The calls per month that the plan of the service's account includes. See Call limits.
- A call has up to 30 seconds to answer.
When a call fails
A failed call answers with JSON and an HTTP status. The text in error says what went wrong.
| Status | Typical error | What to do |
|---|---|---|
| 400 | Missing required parameters, Parameter validation failed | Fix the inputs; see Input errors |
| 400 | Authentication required. ..., Invalid token, Token expired | Send a valid token; see Token errors |
| 404 | Not found | Check the ID and that the service is published; see Not found and unpublished |
| 429 | RATE_LIMIT_EXCEEDED, Monthly call limit reached | Wait or upgrade; see Limit errors |
| 500 | Internal server error | Try again; contact support if it stays |
Token problems answer with 400, not 401. Check the text in error, not only the status. The full list is in the Error reference.
Related
For developers and agents
| Item | Value |
|---|---|
| Address | https://spreadapi.io/api/v1/services/{serviceId}/execute |
| Short address | https://spreadapi.run/{serviceId} |
| Methods | GET, POST, OPTIONS |
| GET inputs | Query parameters, one per input name |
| POST body | {"inputs": {"name": value, ...}} with Content-Type: application/json |
| Token | Authorization: Bearer <token>, or ?token=<token> on GET |
| Success | HTTP 200, JSON with service, inputs, outputs, metadata |
Optional parameters:
| Parameter | Where | Effect |
|---|---|---|
_format | GET query | json (default), csv or plain |
_pretty=true | GET query | Indented JSON |
flatten=true | Query | Adds result, the outputs as one object keyed by name |
nocdn=true | GET query, or "nocdn": true in the POST body | Accepted, but no longer needed: answers are not stored by browsers or networks |
nocache=true | GET query, or "nocache": true in the POST body | Skips the stored result and calculates again |
On GET, query parameters whose name starts with _ and the names token, nocdn and nocache are not treated as inputs.
A POST body without an inputs object answers 400 with error: "INVALID_REQUEST" and the message Request body must contain "inputs" object. A service without inputs is called with {"inputs": {}}.
A failed calculation answers 400 with error, message, serviceId, the inputs you sent and details. A call over the per-minute limit answers 429 with the headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset and Retry-After.
FAQ
What is the address of my API?
It is https://spreadapi.io/api/v1/services/{serviceId}/execute with your service ID. In the service list, the three dots and Copy Endpoint copy it.
Should I use GET or POST?
Both return the same answer. GET with inputs in the address fits spreadsheets and quick tests; POST with a JSON body is the recommended way for code.
How do I send the inputs with POST?
Send Content-Type: application/json and a body of the form {"inputs": {"amount": 20000, "rate": 0.05}}. The keys are the input names of your service.
Do input names have to match upper and lower case?
No. Input names are not case-sensitive. Use the name of the input, not its title.
What is spreadapi.run?
It is the short domain for calls: https://spreadapi.run/{serviceId} is the same endpoint as the long execute address. It accepts the same inputs, tokens and methods.
Why do I get 404 when I call my service?
The ID is wrong or the service is not published. A draft cannot be called; publish it first.
How many calls can I make?
At most 1,000 calls per minute per service, and the calls per month of the plan. The numbers per plan are in Call limits.
How do I send 5 percent?
Send the decimal 0.05. Details are in Percentages and formats.
As an agent, how do I find out which inputs a service expects?
Read the OpenAPI file at https://spreadapi.io/api/v1/services/{serviceId}/openapi, or open the discovery address of the service. See OpenAPI and interactive docs and The discovery address.
What happens to an optional input I leave out?
It takes its default value. Without a default, the calculation uses the value the published workbook holds in that cell.
My text value loses its leading zeros on GET. Why?
On GET, a value that looks like a number is read as a number. Send the value with POST as a JSON string, for example "zip": "01234".