The discovery address
Updated 2026-11-13
The discovery address is one web address that describes a service and also calculates with it over plain HTTP. This page explains what an agent finds there, how it calls the service, and how tokens work.
What it is
The discovery address describes the service in words and JSON. An agent reads it with GET and calculates with GET or POST. It needs no MCP support and no documentation: everything needed for a correct call is in the answer.
It is also the address the n8n and Zapier integrations use. See n8n and Zapier.
Find the address
- Open the service and select AI → Connect (KI → Verbinden).
- Under Any agent that can open an address (Jeder Agent, der eine Adresse öffnen kann) click Copy (Kopieren).
The address has the form https://spreadapi.io/d/<service_id>.
The service must be published; the address of a draft does not answer.
Give it to an agent
Paste the address into the conversation with your agent and ask your question, for example: "Use this service to calculate the monthly payment for 150,000 over 15 years at 4.5%: https://spreadapi.io/d/<service_id>".
The agent opens the address, reads which inputs exist and what is allowed, and calls the service.
Protected services
For a service that requires a token, append ?token=… with a token from API → Access (API → Zugriff). The page shows this hint when the service is protected.
Anyone who has the address with the token can call the service, so share it like a password. See Tokens and access.
What the agent reads
The answer of a GET holds:
- the service: name, description, your guidance ("When the AI should use it"), category and tags;
- instructions in plain sentences: how to call, whether a token is needed, that every reported number should be calculated by the service, how percentages are sent, how to compare options, how to show results;
- a quick-start address that works as it stands;
- every input with its type, whether it is required, description, default, minimum, maximum and allowed values;
- every output with its title, type, description, display format and an example value;
- the two actions with examples for GET and POST;
- the service's MCP address, for clients that support MCP;
- your example questions, if you added any.
The texts come from AI → Definition. See AI → Definition.
Limits
- Each calculation counts as one call of the service; in a batch every scenario counts. See Call limits.
- A batch holds 2 to 20 scenarios.
- After you change the service, publish again; callers get the published version.
For developers and agents
Read the description
GET https://spreadapi.io/d/<service_id>
Answer (shortened):
{
"api": "SpreadAPI",
"version": "1.0",
"endpoint": "https://spreadapi.io/d/<service_id>",
"service": { "name": "Loan calculator", "description": "…", "guidance": "…" },
"instructions": ["…"],
"quickStart": ["https://spreadapi.io/d/<service_id>?action=calculate&loan_amount=200000&annual_rate=0.04&years=20"],
"parameters": {
"note": "Parameter names are case-insensitive. Use the \"name\" field (not \"title\") as the key in your requests.",
"inputs": [{ "name": "annual_rate", "title": "Annual Rate", "type": "number", "required": true, "format": "percentage", "max": 0.25, "currentValue": 0.04 }],
"outputs": [{ "name": "monthly_payment", "title": "Monthly Payment", "type": "number", "example": 1211.96 }]
},
"actions": { "calculate": { "…": "…" }, "batch": { "…": "…" } },
"mcp": { "url": "https://spreadapi.io/api/mcp/service/<service_id>", "transport": "streamable-http" },
"usageExamples": ["…"]
}currentValueon an input andexampleon an output are what the spreadsheet held when it was published: a sample, not a result.- An output that is a range has
type"array"or"table", ashape(rows,cols) and anote. format: "percentage"on an input means: send a decimal, 0.05 for 5%.
Calculate
With GET, inputs are query parameters:
GET https://spreadapi.io/d/<service_id>?action=calculate&loan_amount=150000&annual_rate=0.045&years=15
With POST:
{ "action": "calculate", "inputs": { "loan_amount": 150000, "annual_rate": 0.045, "years": 15 } }Answer:
{
"success": true,
"service": { "id": "…", "name": "…" },
"inputs": [{ "name": "loan_amount", "title": "Loan Amount", "value": 150000 }],
"outputs": [{ "name": "monthly_payment", "title": "Monthly Payment", "value": 1147.49 }],
"metadata": { "executionTime": 12, "cached": false }
}An output carries formatString when its cell has a number format.
Compare scenarios
POST only:
{ "action": "batch", "scenarios": [
{ "label": "15 years", "inputs": { "loan_amount": 150000, "annual_rate": 0.045, "years": 15 } },
{ "label": "20 years", "inputs": { "loan_amount": 150000, "annual_rate": 0.045, "years": 20 } }
] }The answer holds scenarios (each with label, success and either inputs and outputs or error) and metadata.scenarioCount.
Token
For a protected service send the token in one of three ways: ?token=<token> in the address, the header Authorization: Bearer <token>, or "token": "<token>" in the POST body.
Errors
Every error answer has "success": false and a text in error.
| HTTP | When | What to do |
|---|---|---|
| 400 | a required input is missing or a value is not allowed; the text names the input and what is allowed | correct the input and call again |
| 400 | Unknown action; fewer than 2 or more than 20 scenarios in a batch | use calculate or batch with 2 to 20 scenarios |
| 401 | the service requires a token and none or a wrong one was sent | add a valid token |
| 404 | Service not found or not published | check the id; a draft cannot be called |
| 429 | Monthly call limit reached (code CALL_LIMIT_REACHED) | tell the user; calls work again on the 1st (UTC) or on a larger plan |
| 500 | an error on our side | try again later |
A GET without a token on a protected service answers 401 with the service's name and the note that a token is needed, and nothing else.
FAQ
What is the discovery address?
It is https://spreadapi.io/d/<service_id>, an address that describes the service in words and JSON and also calculates with it. Any agent that can open a web address can use the service through it.
Where do I find the discovery address of my service?
On the service's AI → Connect page, under Any agent that can open an address. Click Copy to copy it.
How do I use the discovery address with a protected service?
Append ?token=… with a token from API → Access. An agent can also send the token as the header Authorization: Bearer <token>.
What is the difference between the discovery address and the REST API?
Both calculate the same service. The discovery address additionally describes the service in its GET answer, so an agent needs nothing else; the REST API is the plain endpoint for code. See Call a service over the API.
Does opening the discovery address count as a call?
Reading the description does not calculate anything. A calculation with action=calculate counts as one call, and each scenario of a batch counts as one.
My agent says the address returns "Service not found or not published". Why?
The service is a draft or the id is wrong. Publish the service and copy the address again from AI → Connect.
As an agent, how do I call a service from its discovery address?
GET the address, read parameters.inputs, then call ?action=calculate&name=value for each input, or POST {"action": "calculate", "inputs": {…}}. The first entry of quickStart is a call that works as it stands.
As an agent, my fetch tool refuses an address I built myself. What now?
Use a shell request instead, for example curl -s "https://spreadapi.io/d/<service_id>?action=calculate&name=value". The instructions in the discovery answer say the same.
As an agent, how do I compare several options?
POST {"action": "batch", "scenarios": [...]} with 2 to 20 scenarios, each with a label and inputs. You get one result per scenario in the same order.
Are parameter names case-sensitive?
No. Use the name of each input as the key (not its title); upper and lower case do not matter.