# Ask TerraLab to add data it does not have

> Index of the TerraLab docs for agents: [llms.txt](https://terra-lab.ai/docs/llms.txt). Every docs page is also served as markdown: add .md to its URL.

Ask TerraLab to add geographic data the catalogue does not have yet, with what you need and up to five places where you need it.

| | |
| --- | --- |
| REST | `POST https://mcp.terra-lab.ai/v1/tools/request_data` |
| MCP tool | `request_data` on `https://mcp.terra-lab.ai/mcp` |
| Group | Data catalog |

## Request

```bash
curl -X POST https://mcp.terra-lab.ai/v1/tools/request_data \
  -H "Authorization: Bearer $TERRALAB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"description":"Official flood zones of Morocco","example_locations":["Fes, Morocco"]}'
```

```python
import os
import requests

response = requests.post(
    "https://mcp.terra-lab.ai/v1/tools/request_data",
    headers={"Authorization": f"Bearer {os.environ['TERRALAB_API_KEY']}"},
    json={
        "description": "Official flood zones of Morocco",
        "example_locations": ["Fes, Morocco"],
    },
    timeout=120,
)
response.raise_for_status()
print(response.json()["structuredContent"])
```

```javascript
const response = await fetch('https://mcp.terra-lab.ai/v1/tools/request_data', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TERRALAB_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "description": "Official flood zones of Morocco",
    "example_locations": [
      "Fes, Morocco"
    ]
  }),
});
const data = await response.json();
console.log(data.structuredContent);
```

Other valid request bodies:

```json
{"description":"Noise maps of Lyon","example_locations":["Lyon"],"idempotency_key":"noise-lyon-1"}
```

## Parameters

A JSON object in the request body; in an MCP client, the arguments of the tool call.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `description` | string | No | The data needed, in the user's words: "official flood zones of Morocco". Up to 2000 characters. |
| `example_locations` | array of string or object | No | Up to 5 places where the data is needed: each a place name, {"place": name}, or {"latitude", "longitude"}; never both a place and coordinates. 0 to 5 items. |
| `use_case` | string | No | What the user wants to do with it, when they said so. Up to 500 characters. |
| `file_anyway` | boolean | No | File the request even when a hosted dataset seems to answer it (the user said it does not). Default `false`. |
| `idempotency_key` | string | No | Any string that stays the same if this call is sent again; the same key and description return the first request. Up to 80 characters. |

## Response

`structuredContent` holds the result, `content` the same result as text for a model, and `isError` is `true` when the tool refused the request or failed; then `structuredContent.code`, `message` and `hint` say what to change.

```json
{
  "structuredContent": {
    "sources": [{ "name": "...", "licence": "...", "url": "..." }],
    "downloads": [{ "label": "...", "format": "...", "url": "...", "name": "..." }]
  },
  "content": [{ "type": "text", "text": "..." }],
  "isError": false
}
```

Every result lists its `sources` with their licence. File results come as `downloads`: each link builds its file when opened.

## Errors

A missing key answers `401`, an empty balance `402`, too many calls `429`. A call that fails or finds nothing is not counted. See [Errors and rate limits](https://terra-lab.ai/docs/errors).

## Description for agents

The text the server gives an agent to decide when to call this tool:

> Use this when the user needs geographic data that find_datasets did not find, and wants TerraLab to add it: "you don't have the official flood zones of Morocco? Can you ask TerraLab to add them?". Give description (what data, in the user's words) and up to 5 example_locations (places or coordinates where it is needed). The catalogue is searched first: when a hosted dataset already answers, the answer is matched_existing with the call that gets it and nothing is filed (file_anyway true files it all the same, for data the user says is different). Otherwise the request is filed and gets a request_id (dr_ and 10 characters) to quote to the user; find_datasets with request_id gives its status later. Someone at TerraLab reads every request once a week; no date is promised, so never promise one. The same idempotency_key with the same description returns the first request instead of filing it twice. Only for data TerraLab could host (maps, layers, statistics by place), not for questions or bugs. Never use the user's current location unless they type it.


Source: https://terra-lab.ai/docs/api/request_data · Updated 2026-10-27
