Appearance
Endpoints
All endpoints are prefixed with https://api-rest.tendios.com/api and require the api-key header.
Context
Get caller context
http
GET /v1/whoamiReturns who the calling API key belongs to. Useful as a first call to confirm a key is wired up correctly and to discover the account and organization it resolves to — you never pass an account id to the other endpoints, so this is how you find out which account you're acting on.
Response
| Field | Type | Description |
|---|---|---|
principal.type | string | Always apiKey |
principal.id | string | ID of the key making the call |
principal.name | string | The name you gave the key, e.g. Claude integration |
account.id | string | Account the key belongs to |
account.name | string | Account name |
account.slug | string | Account slug |
organization | object | null | { id, name } of the linked organization, if any |
plan.tier | string | null | Active Bid plan tier, e.g. tier_2 |
Example
bash
curl https://api-rest.tendios.com/api/v1/whoami \
-H "api-key: tend_your_key"Tenders
Search tenders
http
POST /v1/tenders/searchReturns a paginated list of tenders matching the given filters.
Request body
| Field | Type | Description |
|---|---|---|
text | string | Free-text search query |
page | number | Page number (default: 1) |
pageSize | number | Results per page (max 100, default: 20) |
sort | string | by-published-date | by-submission-date | by-budget |
isDescendent | boolean | Sort descending (default: true) |
status | string[] | Filter by status values |
locations | string[] | Location filters e.g. ["country/ES", "province/28"] |
minBudget | number | Minimum budget (no taxes) |
maxBudget | number | Maximum budget (no taxes) |
Example
bash
curl -X POST https://api-rest.tendios.com/api/v1/tenders/search \
-H "api-key: tend_your_key" \
-H "Content-Type: application/json" \
-d '{ "text": "IT services", "pageSize": 10, "locations": ["country/ES"] }'Response — see Pagination for the envelope shape.
Get tender by ID
http
GET /v1/tenders/{id}Returns the full detail of a single tender.
Path params
| Param | Description |
|---|---|
id | Tender ID (e.g. 507f1f77bcf86cd799439011) |
Example
bash
curl https://api-rest.tendios.com/api/v1/tenders/507f1f77bcf86cd799439011 \
-H "api-key: tend_your_key"Get tender sheets
http
GET /v1/tenders/{id}/sheetsReturns all document sheets attached to a tender.
Path params
| Param | Description |
|---|---|
id | Tender ID |
Download tender sheet
http
GET /v1/tenders/sheets/{sheetId}/downloadDownloads a single tender document file.
Path params
| Param | Description |
|---|---|
sheetId | Sheet ID |
Download via short-lived link
http
GET /v1/tenders/documents/{token}/downloadDownloads a tender document using a short-lived, pre-signed token instead of a sheet id. This is the form the MCP get_tender_sheets tool hands back, so an assistant can surface a working download link without streaming bytes through a tool result.
Path params
| Param | Description |
|---|---|
token | Short-lived token identifying the file |
Organizations
Get organization profile
http
GET /v1/organizations/{idOrSlug}Returns the public profile of an organization (bidder or contracting body).
Path params
| Param | Description |
|---|---|
idOrSlug | Organization id (e.g. the contractingOrganizationId of a tender) or slug (e.g. altia-consultores-sa). Both resolve the same organization and response |
Response fields
| Field | Type | Description |
|---|---|---|
id | string | Organization ID |
name | string | Organization name |
type | string | bidder or public-contracting-institution |
taxId | string? | Tax identification number |
activity | string? | Business activity description |
country | string? | ISO 3166-1 alpha-2 country code |
address | object? | { city, province, postCode, street } |
webUrl | string? | Website URL |
logo | string? | Logo image URL |
Example
bash
# By slug
curl https://api-rest.tendios.com/api/v1/organizations/altia-consultores-sa \
-H "api-key: tend_your_key"
# By id — e.g. the contractingOrganizationId returned by the tender endpoints
curl https://api-rest.tendios.com/api/v1/organizations/507f1f77bcf86cd799439012 \
-H "api-key: tend_your_key"Get organization award statistics
http
GET /v1/organizations/{idOrSlug}/awardsReturns yearly award statistics and sector breakdown for an organization.
Path params
| Param | Description |
|---|---|
idOrSlug | Organization id (e.g. the contractingOrganizationId of a tender) or slug, same as the above |
Response fields
| Field | Type | Description |
|---|---|---|
organizationId | string | Organization ID |
organizationName | string | Organization name |
type | string | bidder or public-contracting-institution |
stats | array | Yearly stats: [{ year, count, totalAmount }] |
sectors | array | CPV sector breakdown: [{ divisionCode, divisionNameEn, divisionNameEs, emoji, count, percentage }] |
Example
bash
curl https://api-rest.tendios.com/api/v1/organizations/altia-consultores-sa/awards \
-H "api-key: tend_your_key"
# Or by id
curl https://api-rest.tendios.com/api/v1/organizations/507f1f77bcf86cd799439012/awards \
-H "api-key: tend_your_key"CPV codes
Get CPV details
http
GET /v1/cpv/{code}Returns details for a CPV code including names in 7 EU languages.
Path params
| Param | Description |
|---|---|
code | CPV code (e.g. 72000000) |
Response fields
| Field | Type | Description |
|---|---|---|
code | string | CPV code |
type | string | division | group | class | category |
nameEn | string? | Name in English |
nameEs | string? | Name in Spanish |
nameFr | string? | Name in French |
nameDe | string? | Name in German |
nameIt | string? | Name in Italian |
nameCa | string? | Name in Catalan |
namePt | string? | Name in Portuguese |
emoji | string? | Emoji representing the category |
fontAwesomeIcon | string? | Font Awesome icon name |
Example
bash
curl https://api-rest.tendios.com/api/v1/cpv/72000000 \
-H "api-key: tend_your_key"Alerts
Alerts belong to the account that owns the API key. You never pass an account id — it is resolved from the key.
List alerts
http
GET /v1/alertsReturns a paginated list of every alert configured for the account, with a total count.
Query params
| Param | Type | Default | Description |
|---|---|---|---|
text | string | — | Filter alerts by title |
isArchived | boolean | — | Filter archived or non-archived |
page | number | 1 | Page number |
pageSize | number | 20 | Alerts per page (max 100) |
sort | string | by-update-date | See alert sort values |
sortDirection | string | desc | asc or desc |
Get an alert
http
GET /v1/alerts/{alertId}Returns the full configuration of one alert.
Path params
| Param | Description |
|---|---|
alertId | Alert ID |
Response
| Field | Type | Description |
|---|---|---|
id | string | Alert ID |
title | string | Alert title |
description | string? | Optional description |
platformUrl | string | URL to open the alert in Bid |
criteria | object | Tender matching criteria (see below) |
notificationConfig | object | Schedule and delivery configuration |
responsibles | object[] | Users responsible for the alert |
isActive | boolean | Whether the alert is running |
isPublic | boolean | Whether all account users can access it |
isArchived | boolean | Whether the alert is archived |
isAutoConfigured | boolean | Whether Tendios generated the configuration |
createdBy | string | ID of the creator |
createdAt | date-time | Creation timestamp |
updatedAt | date-time | Last update timestamp |
lastNotifiedAt | date-time | Last time the alert matched |
lastNotificationSentAt | date-time? | Last time an email went out |
Create an alert
http
POST /v1/alertsCreates an alert and returns it. Responds 201.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Alert title |
windowsSearch | object[] | Yes | Events that trigger the alert (min 1) — see below |
description | string | No | Free-text description |
criteria | object | No | Tender matching criteria — see below |
notificationConfig | object | No | Schedule and delivery — see below |
responsibles | object[] | No | { id, receiveEmails } per recipient |
isActive | boolean | No | Start active (default true) |
isPublic | boolean | No | Visible to all account users (default true) |
windowsSearch[] — which tender event the alert watches:
| Field | Type | Description |
|---|---|---|
field | string | expedientPublishedAt, expedientAdjudicationDate, or expedientExpirationDate |
expirationOffset | number | Days before expiry to notify — only for expedientExpirationDate (min 1) |
withExtension | boolean | Use the extended deadline — only for expedientExpirationDate |
criteria — every field optional:
| Field | Type | Description |
|---|---|---|
keywords | object | { include: string[], exclude: string[] } |
cpvCodes | object | { include: string[], exclude: string[] } |
locations | object | { country: {include,exclude}, province: {include,exclude} } |
budget | object | { min, max } |
statuses | string[] | Tender status values, e.g. ["Publicada"] (min 1 when present) |
contractTypes | string[] | Contract type values |
procedures | string[] | Procedure type values |
inDeadline | boolean | Only tenders still open for submission |
notificationConfig — every field optional:
| Field | Type | Description |
|---|---|---|
frequency | object | { type: "daily", weekdays: number[] } or { type: "weekly", dayOfWeek: number } — 1 = Monday, 7 = Sunday |
hour | number | Delivery hour, 0–23 |
timezone | string | IANA zone, e.g. Europe/Madrid |
attachments | object | { hasPdf, hasCsv, hasXlsx } |
includeModifications | boolean | Include modified tenders, not just new ones |
sendWithoutItems | boolean | Send the email even when nothing matched |
Example
bash
curl -X POST https://api-rest.tendios.com/api/v1/alerts \
-H "api-key: tend_your_key" \
-H "Content-Type: application/json" \
-d '{
"title": "IT services in Madrid",
"windowsSearch": [{ "field": "expedientPublishedAt" }],
"criteria": {
"keywords": { "include": ["software"] },
"locations": { "province": { "include": ["28"] } },
"budget": { "min": 50000 }
},
"notificationConfig": {
"frequency": { "type": "daily", "weekdays": [1, 2, 3, 4, 5] },
"hour": 8,
"timezone": "Europe/Madrid"
}
}'Update an alert
http
PATCH /v1/alerts/{alertId}Updates selected fields and returns the alert. Responds 200. Every field is optional — omitted fields are left unchanged.
Path params
| Param | Description |
|---|---|
alertId | Alert ID |
Request body — the same fields as Create an alert, all optional, plus:
| Field | Type | Description |
|---|---|---|
isArchived | boolean | Archive or unarchive |
Get alert tender results
http
POST /v1/alerts/{alertId}/resultsReturns tenders that match a saved alert.
Path params
| Param | Description |
|---|---|
alertId | Alert ID |
Alert sort values
Accepted by sort on List alerts. Default by-update-date.
| Value | Sorts by |
|---|---|
by-name | Alert title |
by-update-date | Last update date |
by-creation-date | Creation date |
by-last-notified-date | Last time the alert matched |
by-last-notification-sent-date | Last time an email was sent |
by-status | Active/inactive state |
Pipelines
List pipelines
http
GET /v1/pipelinesReturns the opportunity pipelines configured for the account, each with its stages. Call this first to get the pipelineId and statusId values the Kanban and Opportunities endpoints need.
Query params
| Param | Type | Default | Description |
|---|---|---|---|
page | number | 1 | Page number |
pageSize | number | 20 | Pipelines per page (max 100) |
Response — paginated list of:
| Field | Type | Description |
|---|---|---|
id | string | Pipeline ID |
name | string | Pipeline name |
statuses | object[] | Stages — see below |
statuses[]
| Field | Type | Description |
|---|---|---|
id | string | Stage ID |
name | string | Stage name |
isInitial | boolean | Whether new opportunities land here |
isTerminal | boolean | Whether reaching this stage closes the opportunity |
outcomeType | string | Outcome the stage represents |
sortPoints | number | Board ordering weight |
showInKanban | boolean | Whether the stage renders as a column |
description | string? | Optional stage description |
Kanban
These endpoints expose the CRM pipeline kanban board. They require the API key of the account that owns the pipeline.
Get pipeline status totals
http
GET /v1/kanban/{pipelineId}/statusReturns opportunity counts and total amounts grouped by pipeline status — used to render kanban column headers.
Path params
| Param | Description |
|---|---|
pipelineId | Pipeline ID |
Query params
| Param | Type | Description |
|---|---|---|
responsible | string[] | Filter by responsible user IDs |
teamResponsible | string[] | Filter by responsible team IDs |
Response — array of:
| Field | Type | Description |
|---|---|---|
status | object | { id, name, isInitial, isTerminal, pipelineId, outcomeType, sortPoints, showInKanban, backgroundColor?, textColor?, description? } |
opportunityCount | number | Number of opportunities in this status |
totalAmount | number | Sum of opportunity amounts |
currency | string | Currency code (e.g. EUR) |
Get opportunities by status
http
GET /v1/kanban/{pipelineId}/status/{statusId}/opportunitiesReturns paginated opportunities for a single kanban column.
Path params
| Param | Description |
|---|---|
pipelineId | Pipeline ID |
statusId | Pipeline status ID |
Query params
| Param | Type | Default | Description |
|---|---|---|---|
page | number | 1 | Page number |
pageSize | number | 10 | Results per page |
sort | string | — | Sort order |
Search kanban opportunities
http
GET /v1/kanban/{pipelineId}/searchSearches opportunities across all statuses in a pipeline. Returns a map of statusId → opportunities[].
Path params
| Param | Description |
|---|---|
pipelineId | Pipeline ID |
Query params
| Param | Type | Default | Description |
|---|---|---|---|
search | string | — | Text search term |
limit | number | 10 | Max opportunities per status (max 50) |
responsible | string[] | — | Filter by responsible user IDs |
teamResponsible | string[] | — | Filter by responsible team IDs |
sort | string | — | Sort order |
Opportunities
These endpoints act on individual opportunities in the account's CRM pipeline. Get the IDs they need from List pipelines and the Kanban endpoints.
Move an opportunity to another status
http
PUT /v1/opportunities/{opportunityId}/statusMoves an opportunity to a different stage of its current pipeline. Responds 204 — including when the opportunity is already in the requested stage, which makes the call safe to retry.
Path params
| Param | Description |
|---|---|
opportunityId | Opportunity ID |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
targetStatusId | uuid | Yes | Target pipeline stage ID |
Moving to a terminal stage closes the opportunity
Stages with isTerminal: true (see List pipelines) end the opportunity's lifecycle. There is no undo through the API — check isTerminal before moving if that isn't what you intend.
Errors — 403 if the opportunity belongs to another account, 404 if the opportunity or stage doesn't exist.
Get workflow actions
http
GET /v1/opportunities/{opportunityId}/workflow-actionsReturns the current workflow action records for an opportunity, grouped by workflow step. Use it to see which qualification steps have been completed and which are outstanding.
Path params
| Param | Description |
|---|---|
opportunityId | Opportunity ID |
Response — array of:
| Field | Type | Description |
|---|---|---|
id | string | Action ID |
workflowStepId | string | Step the action belongs to |
workflowStepName | string? | Step name |
workflowStepPosition | number? | Step position in the workflow |
name | string | Action name |
targetType | string | What the action targets |
targetId | string? | ID of the target, when applicable |
status | string | Action status |
position | number | Position within the step |
completedAt | date-time? | When it was completed |
createdAt | date-time | Creation timestamp |
updatedAt | date-time | Last update timestamp |
Errors — 403 if the opportunity belongs to another account, 404 if it doesn't exist.
List opportunity tasks
http
GET /v1/opportunities/{opportunityId}/tasksReturns a paginated list of tasks attached to an opportunity.
Path params
| Param | Description |
|---|---|
opportunityId | Opportunity ID |
Query params
| Param | Type | Default | Description |
|---|---|---|---|
status | string | — | Filter by to-do, in-progress, or done |
page | number | 1 | Page number |
pageSize | number | 20 | Tasks per page (max 100) |
Create an opportunity task
http
POST /v1/opportunities/{opportunityId}/tasksCreates a task on an opportunity. Responds 201 with the new task's id.
Path params
| Param | Description |
|---|---|
opportunityId | Opportunity ID |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Task title |
description | string | No | Task description |
status | string | No | to-do (default), in-progress, or done |
priority | string | No | high, medium (default), or low |
userIds | string[] | No | Account user IDs assigned to the task |
deadlineAt | date-time | No | ISO 8601 deadline |
Example
bash
curl -X POST https://api-rest.tendios.com/api/v1/opportunities/{opportunityId}/tasks \
-H "api-key: tend_your_key" \
-H "Content-Type: application/json" \
-d '{ "title": "Prepare technical proposal", "priority": "high", "deadlineAt": "2026-09-01T09:00:00.000Z" }'Errors — 404 if the opportunity doesn't exist.
List opportunity summaries
http
GET /v1/opportunities/{opportunityId}/summariesReturns the AI-generated summaries for an opportunity.
Path params
| Param | Description |
|---|---|
opportunityId | Opportunity ID |
Response — array of:
| Field | Type | Description |
|---|---|---|
id | string | Summary ID |
name | string | Summary name |
status | string | pending, in_progress, completed, or failed |
result | string? | Rendered content in Markdown, present once completed |
generatedAt | date-time? | When the summary finished generating |
createdAt | date-time | Creation timestamp |
updatedAt | date-time | Last update timestamp |
Errors — 404 if the opportunity doesn't exist.
Download a summary PDF
http
GET /v1/opportunities/{opportunityId}/summaries/{summaryId}/pdfDownloads a summary as a PDF. Only available once the summary's status is completed.
Path params
| Param | Description |
|---|---|
opportunityId | Opportunity ID |
summaryId | Summary ID |
Response — binary application/pdf, streamed with Content-Disposition: attachment.
Example
bash
curl https://api-rest.tendios.com/api/v1/opportunities/{opportunityId}/summaries/{summaryId}/pdf \
-H "api-key: tend_your_key" \
--output summary.pdfErrors — 404 if the opportunity or summary doesn't exist, 409 (code SUMMARY_NOT_READY) if the summary hasn't finished generating yet.
API Key
Get API key info
http
GET /v1/api-keyReturns metadata about the API key in use — rate limit, expiry, last usage.
Example
bash
curl https://api-rest.tendios.com/api/v1/api-key \
-H "api-key: tend_your_key"