Skip to content

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/whoami

Returns 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

FieldTypeDescription
principal.typestringAlways apiKey
principal.idstringID of the key making the call
principal.namestringThe name you gave the key, e.g. Claude integration
account.idstringAccount the key belongs to
account.namestringAccount name
account.slugstringAccount slug
organizationobject | null{ id, name } of the linked organization, if any
plan.tierstring | nullActive 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/search

Returns a paginated list of tenders matching the given filters. It reads data, so read-only keys can call it.

Request body — the most common fields. Every filter is optional; see Filtering for the full list (status, CPVs, procedures, amounts, discount rate, prorated budgets and every date range).

FieldTypeDescription
textstringFree-text search query
pagenumberPage number (default: 1)
pageSizenumberResults per page (max 100, default: 10)
sortstringSort field (default: by-published-date) — see Sorting
isDescendentbooleanSort descending (default: true)
statusstring[]Filter by status values
locationsstring[]Location filters: country/<ISO-2> or town/<name>, e.g. ["country/ES", "town/Madrid"]
minBudgetnumberMinimum budget (no taxes)
maxBudgetnumberMaximum 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

ParamDescription
idTender 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}/sheets

Returns all document sheets attached to a tender.

Path params

ParamDescription
idTender ID

Document classification

Every sheet carries a read-only documentType attribute with the procurement document type Tendios resolved for it:

  • code — stable machine-readable value from the closed list below. Safe to compare literally.
  • label — human-readable name (Spanish), ready to display. Do not branch on it.

documentType is always present, but it is null when the document has no classification. Coverage is not guaranteed for older documents, so your integration must handle null. An unclassified document is returned normally and keeps its isPliego value.

codelabel
pcapPCAP
pptPPT
documento_pliegosDocumento de pliegos
annex_pcapAnexo PCAP
annex_pptAnexo PPT
annexAnexo
cuadroCuadro de características
memoriaMemoria justificativa
necesidadesInforme de necesidades
estudio_viabilidadEstudio de viabilidad
aprobacionAprobación del expediente
anuncioAnuncio
actaActa
informe_valoracionInforme de valoración
adjudicacionAdjudicación

If Tendios reclassifies a document, later reads return the updated value. No notification is sent.

Example response

json
[
  {
    "id": "507f1f77bcf86cd799439011",
    "name": "PCAP.pdf",
    "url": "https://contrataciondelestado.es/.../PCAP.pdf",
    "isDownloaded": true,
    "tenderId": "507f1f77bcf86cd799439013",
    "isPliego": true,
    "documentType": { "code": "pcap", "label": "PCAP" },
    "ragProcessed": true
  },
  {
    "id": "507f1f77bcf86cd799439012",
    "name": "Documento_2019.pdf",
    "url": "https://contrataciondelestado.es/.../Documento_2019.pdf",
    "isDownloaded": false,
    "tenderId": "507f1f77bcf86cd799439013",
    "isPliego": false,
    "documentType": null,
    "ragProcessed": false
  }
]

Get tender questions and answers ​

http
GET /v1/tenders/{id}/questions-answers

Returns the PLACE questions and answers (clarifications) for a tender.

Path params

ParamDescription
idTender ID

Query params

ParamTypeDefaultDescription
pagenumber1Page number
pageSizenumber20Results per page (maximum 100)

Response

FieldTypeDescription
questionsAndAnswersActivebooleanWhether PLACE has an active clarifications channel
itemsobject[]Questions and answers for the requested page
items[].idstringStable Tendios identifier for the clarification
items[].questionstringQuestion submitted through PLACE
items[].answerstring?Answer from the contracting authority, if available
items[].publishedAtdate-timePublication timestamp on PLACE
items[].referencestring?PLACE reference; currently always null
items[].attachmentsobject[]Attached files; currently always empty
paginationobject{ total, page, limit, hasPreviousPage, hasNextPage }

Errors — 404 if the tender doesn't exist.


Get tender candidates ​

http
GET /v1/tenders/{id}/candidates

Returns the companies Tendios holds as having presented to an awarded tender, which of them won, which lots each winner won and the documents the records were extracted from. Offers, scores and the reasons a company lost are not included.

Coverage

Most awarded tenders have no candidate records. The identities of non-winning bidders are not published as structured data: they only appear in the award board minutes (actas), which are published for roughly a quarter of tenders. In mid-2026 about 6% of the tenders awarded each month have candidate records, and coverage is growing. The number of offers received (offersReceived) is available far more often, so expect a response like "no identities, but eight offers were received" for most tenders.

Path params

ParamDescription
idTender ID

Query params

ParamTypeDefaultDescription
pagenumber1Page number
pageSizenumber20Results per page (maximum 100). Use 1 to read only the counts in the header

Response

FieldTypeDescription
candidatesCountnumberCompanies Tendios holds as having presented. 0 means Tendios holds no record, not that nobody bid
offersReceivednumber?Offers received, from the structured award data. null when unknown; 0 only when nobody bid
adjudicatedAtdate-time?Award date of the tender. null when the tender is not awarded or the source does not publish it
sourcesobject[]Documents the records were extracted from: { sheetId, name, url, date }. See Get tender sheets
itemsobject[]Candidates for the requested page: winners first, then by name
items[].organizationIdstringUnique Tendios organization id. Use it with Get organization to pull its award history
items[].namestring?Legal name
items[].taxIdstring?CIF/NIF
items[].wonbooleanWhether the company won the tender or any of its lots
items[].lotsWonobject[]?Lots won: { id, lotId, name, adjudicatedAt }. null when the company did not win; empty when the tender has no lots
items[].sourceSheetIdsstring[]sheetId of the documents this candidate was extracted from
paginationobject{ total, page, limit, hasPreviousPage, hasNextPage }
  • Identify companies by organizationId, never by slug. Slugs are not unique: clece-sa is shared by three organizations with different tax IDs.
  • Winners are reconciled against the tender. A company is marked as winner when its record says so or when it is the awardee of the tender or of one of its lots. The awardee and award amount of the tender itself are not changed by this endpoint.
  • A company that won several lots appears once, with every lot in lotsWon. Non-winners are never attributed to a lot.
  • There is no lot-level award date in most sources: use the adjudicatedAt of the tender.
  • A tender without an award returns an empty list, not an error.

Errors — 404 if the tender doesn't exist.


Get tender contacts ​

http
GET /v1/tenders/{id}/contacts

Returns contacts of the tender's contracting body, gathered from DIR3 (the Spanish public administration directory), the contacts Tendios holds for that organization, signatures and the text of the tender's documents, plus email candidates inferred from metadata and clearly marked as such.

Path params

ParamDescription
idTender ID

Query params

ParamTypeDefaultDescription
minDir3Relevancenumber30Keep DIR3-only emails whose relevance percentage is strictly greater than this. Unscored DIR3-only emails are excluded; emails with any other source are always kept

Response — an array of contacts:

FieldTypeDescription
emailstringEmail address
namestring | nullContact name; null when unknown
jobTitlestring | nullExplicitly recorded role of the contact; null when unknown
phonestring | nullPhone number; null when unknown
statusstringFOUND: observed in a source. INFERRED: unverified candidate built from a name and an observed address pattern
sourcesobject[]Where the contact was found
inferenceobject | nullWhy the address was inferred, when an inference supports it; null otherwise

Neither status verifies that the mailbox exists.

  • Stored contacts belong to the exact contracting body of the tender. Organizations sharing its tax ID are not combined.
  • DIR3 matches by tax ID and may include other administrative units that share it. DIR3 relevance measures how relevant a unit is to procurement, not a link to this specific contracting body.
  • Emails from the tender's documents are included only when stored contacts or DIR3 show that the contracting body owns the email domain, with no conflicting owner. Shared or unproven domains are excluded.
  • Document names and job titles are persisted for newly processed documents when the text explicitly links a person to an email. They are taken from this tender's documents, so a shared mailbox does not inherit a person from another tender. Unknown or ambiguous details are returned as null. Historical records are not backfilled; querying this endpoint does not trigger extraction.

Rate limit — this endpoint has its own budget of 60 requests per minute per account (or the key's own limit, if lower).

Errors — 404 if the tender doesn't exist, 429 when the rate limit is exceeded (see the Retry-After header).


Download tender sheet ​

http
GET /v1/tenders/sheets/{sheetId}/download

Downloads a single tender document file.

Path params

ParamDescription
sheetIdSheet ID

http
GET /v1/tenders/documents/{token}/download

Downloads 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

ParamDescription
tokenShort-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

ParamDescription
idOrSlugOrganization id (e.g. the contractingOrganizationId of a tender) or slug (e.g. altia-consultores-sa). Both resolve the same organization and response

Response fields

FieldTypeDescription
idstringOrganization ID
namestringOrganization name
typestringbidder or public-contracting-institution
taxIdstring?Tax identification number
activitystring?Business activity description
countrystring?ISO 3166-1 alpha-2 country code
addressobject?{ city, province, postCode, street }
webUrlstring?Website URL
logostring?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}/awards

Returns yearly award statistics and sector breakdown for an organization.

Path params

ParamDescription
idOrSlugOrganization id (e.g. the contractingOrganizationId of a tender) or slug, same as the above

Response fields

FieldTypeDescription
organizationIdstringOrganization ID
organizationNamestringOrganization name
typestringbidder or public-contracting-institution
statsarrayYearly stats: [{ year, count, totalAmount }]
sectorsarrayCPV 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"

Market intelligence ​

Get market awards ​

http
POST /v1/market-awards

Returns the tenders awarded to a curated supplier family (a company and its related entities), by a buyer, or both, within a publication or award date range, with totals. It reads data, so read-only keys can call it.

Supplier families and buyer perimeters are curated by Tendios. Ask support@tendios.com for the IDs you need; MCP clients can list them with the list_market_scopes tool.

Request body

FieldTypeDefaultDescription
supplierFamilyIdstring—Curated supplier family. Omit to count awards to any supplier; then buyerPerimeterId or buyerOrganizationId is required
buyerPerimeterIdstring—Curated buyer perimeter. Omit to include every buyer within the countries your account can access
buyerOrganizationIdstring—Tendios organization ID of a buyer without a curated perimeter. Cannot be combined with buyerPerimeterId
includeBuyerDependentsbooleantrueWith buyerOrganizationId, also count its dependent bodies
countryCodestring—Two-letter tender-location country code, e.g. ES; restricted to the countries your account can access
publishedFromdate—Publication date lower bound, inclusive (YYYY-MM-DD)
publishedTodate—Publication date upper bound, inclusive
awardedFromdate—Award date lower bound, inclusive (YYYY-MM-DD)
awardedTodate—Award date upper bound, inclusive
includeModificationsbooleanfalseAlso include contract modifications
pagenumber1Page number
pageSizenumber50Results per page (maximum 100)
sortBystringpublished_atpublished_at or awarded_at
sortDirectionstringascasc or desc

A publication range or an award range is required, and each range needs both of its bounds.

Response

FieldTypeDescription
itemsobject[]Awarded tenders: { tenderId, title, expedient, buyer, awardee, publishedAt, awardedAt, status, awardAmount, currency, isModification }. buyer and awardee are { id, name }
paginationobject{ page, pageSize, total, hasNextPage }
summaryobject{ totalContracts, awardedAmountByCurrency: [{ currency, amount }] } for every matching award, not only the page
appliedDefinitionobjectWhat was applied: supplierFamilyId, buyerPerimeterId, buyerOrganizationId, includeBuyerDependents, buyerOrganizationCount, published, awarded, countryCode and the version of the curated scopes used

Example

bash
curl -X POST https://api-rest.tendios.com/api/v1/market-awards \
  -H "api-key: tend_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "supplierFamilyId": "your-supplier-family-id",
    "countryCode": "ES",
    "publishedFrom": "2025-01-01",
    "publishedTo": "2025-12-31",
    "sortBy": "awarded_at",
    "sortDirection": "desc"
  }'

CPV codes ​

Get CPV details ​

http
GET /v1/cpv/{code}

Returns details for a CPV code including names in 7 EU languages.

Path params

ParamDescription
codeCPV code (e.g. 72000000)

Response fields

FieldTypeDescription
codestringCPV code
typestringdivision | group | class | category
nameEnstring?Name in English
nameEsstring?Name in Spanish
nameFrstring?Name in French
nameDestring?Name in German
nameItstring?Name in Italian
nameCastring?Name in Catalan
namePtstring?Name in Portuguese
emojistring?Emoji representing the category
fontAwesomeIconstring?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/alerts

Returns a paginated list of every alert configured for the account, with a total count.

Query params

ParamTypeDefaultDescription
textstring—Filter alerts by title
isArchivedboolean—Filter archived or non-archived
pagenumber1Page number
pageSizenumber20Alerts per page (max 100)
sortstringby-update-dateSee alert sort values
sortDirectionstringdescasc or desc

Get an alert ​

http
GET /v1/alerts/{alertId}

Returns the full configuration of one alert.

Path params

ParamDescription
alertIdAlert ID

Response

FieldTypeDescription
idstringAlert ID
titlestringAlert title
descriptionstring?Optional description
platformUrlstringURL to open the alert in Bid
criteriaobjectTender matching criteria (see below)
notificationConfigobjectSchedule and delivery configuration
responsiblesobject[]Users responsible for the alert
isActivebooleanWhether the alert is running
isPublicbooleanWhether all account users can access it
isArchivedbooleanWhether the alert is archived
isAutoConfiguredbooleanWhether Tendios generated the configuration
createdBystringID of the creator
createdAtdate-timeCreation timestamp
updatedAtdate-timeLast update timestamp
lastNotifiedAtdate-timeLast time the alert matched
lastNotificationSentAtdate-time?Last time an email went out

Create an alert ​

http
POST /v1/alerts

Creates an alert and returns it. Responds 201.

Request body

FieldTypeRequiredDescription
titlestringYesAlert title
windowsSearchobject[]YesEvents that trigger the alert (min 1) — see below
descriptionstringNoFree-text description
criteriaobjectNoTender matching criteria — see below
notificationConfigobjectNoSchedule and delivery — see below
responsiblesobject[]No{ id, receiveEmails } per recipient
isActivebooleanNoStart active (default true)
isPublicbooleanNoVisible to all account users (default true)

windowsSearch[] — which tender event the alert watches:

FieldTypeDescription
fieldstringexpedientPublishedAt, expedientAdjudicationDate, or expedientExpirationDate
expirationOffsetnumberDays before expiry to notify — only for expedientExpirationDate (min 1)
withExtensionbooleanUse the extended deadline — only for expedientExpirationDate

criteria — every field optional:

FieldTypeDescription
keywordsobject{ include: string[], exclude: string[] }
cpvCodesobject{ include: string[], exclude: string[] }
locationsobject{ country: {include,exclude}, province: {include,exclude} }
budgetobject{ min, max }
statusesstring[]Tender status values, e.g. ["Publicada"] (min 1 when present)
contractTypesstring[]Contract type values
proceduresstring[]Procedure type values
inDeadlinebooleanOnly tenders still open for submission

notificationConfig — every field optional:

FieldTypeDescription
frequencyobject{ type: "daily", weekdays: number[] } or { type: "weekly", dayOfWeek: number } — 1 = Monday, 7 = Sunday
hournumberDelivery hour, 0–23
timezonestringIANA zone, e.g. Europe/Madrid
attachmentsobject{ hasPdf, hasCsv, hasXlsx }
includeModificationsbooleanInclude modified tenders, not just new ones
sendWithoutItemsbooleanSend 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

ParamDescription
alertIdAlert ID

Request body — the same fields as Create an alert, all optional, plus:

FieldTypeDescription
isArchivedbooleanArchive or unarchive

Get alert tender results ​

http
POST /v1/alerts/{alertId}/results

Returns tenders that match a saved alert. It reads data, so read-only keys can call it.

Path params

ParamDescription
alertIdAlert ID

Request body — every field is optional and narrows the alert's own criteria.

FieldTypeDefaultDescription
pagenumber1Page number (1-based)
pageSizenumber10Results per page (maximum 100)
textstring—Extra full-text filter on top of the alert criteria
minPublicationDatedate-time—Published on or after
maxPublicationDatedate-time—Published on or before
minLastSignificantChangeDatedate-time—Last significant change on or after
maxLastSignificantChangeDatedate-time—Last significant change on or before
sortstringby-published-dateAny tender sort value
isDescendentbooleantrueSort in descending order

The response is the same paginated tender list as Search tenders.


Alert sort values ​

Accepted by sort on List alerts. Default by-update-date.

ValueSorts by
by-nameAlert title
by-update-dateLast update date
by-creation-dateCreation date
by-last-notified-dateLast time the alert matched
by-last-notification-sent-dateLast time an email was sent
by-statusActive/inactive state

Pipelines ​

List pipelines ​

http
GET /v1/pipelines

Returns 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

ParamTypeDefaultDescription
pagenumber1Page number
pageSizenumber20Pipelines per page (max 100)

Response — paginated list of:

FieldTypeDescription
idstringPipeline ID
namestringPipeline name
statusesobject[]Stages — see below

statuses[]

FieldTypeDescription
idstringStage ID
namestringStage name
isInitialbooleanWhether new opportunities land here
isTerminalbooleanWhether reaching this stage closes the opportunity
outcomeTypestringOutcome the stage represents
sortPointsnumberBoard ordering weight
showInKanbanbooleanWhether the stage renders as a column
descriptionstring?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}/status

Returns opportunity counts and total amounts grouped by pipeline status — used to render kanban column headers.

Path params

ParamDescription
pipelineIdPipeline ID

Query params

ParamTypeDescription
responsiblestring[]Filter by responsible user IDs
teamResponsiblestring[]Filter by responsible team IDs

Response — array of:

FieldTypeDescription
statusobject{ id, name, isInitial, isTerminal, pipelineId, outcomeType, sortPoints, showInKanban, backgroundColor?, textColor?, description? }
opportunityCountnumberNumber of opportunities in this status
totalAmountnumberSum of opportunity amounts
currencystringCurrency code (e.g. EUR)

Get opportunities by status ​

http
GET /v1/kanban/{pipelineId}/status/{statusId}/opportunities

Returns paginated opportunities for a single kanban column.

Path params

ParamDescription
pipelineIdPipeline ID
statusIdPipeline status ID

Query params

ParamTypeDefaultDescription
pagenumber1Page number
pageSizenumber10Results per page
sortstring—Sort order: custom, by-update-date, by-due-date, by-budget, by-prorated-budget
sortDirectionstringascasc or desc

Search kanban opportunities ​

http
GET /v1/kanban/{pipelineId}/search

Searches opportunities across all statuses in a pipeline. Returns a map of statusId → opportunities[].

Path params

ParamDescription
pipelineIdPipeline ID

Query params

ParamTypeDefaultDescription
searchstring—Text search term
limitnumber10Max opportunities per status (max 50)
responsiblestring[]—Filter by responsible user IDs
teamResponsiblestring[]—Filter by responsible team IDs
sortstring—Sort order: custom, by-update-date, by-due-date, by-budget, by-prorated-budget
sortDirectionstringascasc or desc

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}/status

Moves 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

ParamDescription
opportunityIdOpportunity ID

Request body

FieldTypeRequiredDescription
targetStatusIduuidYesTarget 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 opportunity questions and answers ​

http
GET /v1/opportunities/{opportunityId}/questions-answers

Returns the PLACE questions and answers (clarifications) for the tender linked to an opportunity. The opportunity must belong to the account associated with the API key.

Path params

ParamDescription
opportunityIdOpportunity ID

Query params

ParamTypeDefaultDescription
pagenumber1Page number
pageSizenumber20Results per page (maximum 100)

Response

FieldTypeDescription
questionsAndAnswersActivebooleanWhether PLACE has an active clarifications channel
itemsobject[]Questions and answers for the requested page
items[].idstringStable Tendios identifier for the clarification
items[].questionstringQuestion submitted through PLACE
items[].answerstring?Answer from the contracting authority, if available
items[].publishedAtdate-timePublication timestamp on PLACE
items[].referencestring?PLACE reference; currently always null
items[].attachmentsobject[]Attached files; currently always empty
paginationobject{ total, page, limit, hasPreviousPage, hasNextPage }

Errors — 403 if the opportunity belongs to another account, 404 if it doesn't exist.


Get opportunity candidates ​

http
GET /v1/opportunities/{opportunityId}/candidates

Returns the candidates of the tender linked to an opportunity, with the same response and coverage caveats as Get tender candidates. An opportunity on a lot returns the candidates of its whole tender. An opportunity not linked to a tender returns an empty response. The opportunity must belong to the account associated with the API key.

Path params

ParamDescription
opportunityIdOpportunity ID

Query params — same as Get tender candidates.

Errors — 404 if the opportunity doesn't exist or belongs to another account.


Get workflow actions ​

http
GET /v1/opportunities/{opportunityId}/workflow-actions

Returns 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

ParamDescription
opportunityIdOpportunity ID

Response — array of:

FieldTypeDescription
idstringAction ID
workflowStepIdstringStep the action belongs to
workflowStepNamestring?Step name
workflowStepPositionnumber?Step position in the workflow
namestringAction name
targetTypestringWhat the action targets
targetIdstring?ID of the target, when applicable
statusstringAction status
positionnumberPosition within the step
completedAtdate-time?When it was completed
createdAtdate-timeCreation timestamp
updatedAtdate-timeLast 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}/tasks

Returns a paginated list of tasks attached to an opportunity.

Path params

ParamDescription
opportunityIdOpportunity ID

Query params

ParamTypeDefaultDescription
statusstring—Filter by to-do, in-progress, or done
pagenumber1Page number
pageSizenumber20Tasks per page (max 100)

Create an opportunity task ​

http
POST /v1/opportunities/{opportunityId}/tasks

Creates a task on an opportunity. Responds 201 with the new task's id.

Path params

ParamDescription
opportunityIdOpportunity ID

Request body

FieldTypeRequiredDescription
titlestringYesTask title
descriptionstringNoTask description
statusstringNoto-do (default), in-progress, or done
prioritystringNohigh, medium (default), or low
userIdsstring[]NoAccount user IDs assigned to the task
deadlineAtdate-timeNoISO 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}/summaries

Returns the AI-generated summaries for an opportunity.

Path params

ParamDescription
opportunityIdOpportunity ID

Response — array of:

FieldTypeDescription
idstringSummary ID
namestringSummary name
statusstringpending, in_progress, completed, or failed
resultstring?Rendered content in Markdown, present once completed
generatedAtdate-time?When the summary finished generating
createdAtdate-timeCreation timestamp
updatedAtdate-timeLast update timestamp

Errors — 404 if the opportunity doesn't exist.


Download a summary PDF ​

http
GET /v1/opportunities/{opportunityId}/summaries/{summaryId}/pdf

Downloads a summary as a PDF. Only available once the summary's status is completed.

Path params

ParamDescription
opportunityIdOpportunity ID
summaryIdSummary 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.pdf

Errors — 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-key

Returns 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"

© Tendios