Developer docs
Tenderen API (v1)
The Tenderen API is a JSON REST API for searching tenders, managing saved tenders, bids, alerts, teams and documents, and running AI analysis. It is available on the Enterprise plan and authenticated with API keys.
Base URL
All endpoints are versioned under /api/v1. Requests and responses are JSON over HTTPS.
https://api.tenderen.com/api/v1Authentication
Send your API key as a Bearer token in the Authorization header. Keys are created in the app under Developers → API keys by a company Owner or Admin on the Enterprise plan. The full key is shown once; Tenderen stores only a SHA-256 hash of it. Keys can have an expiry date and can be revoked at any time.
curl "https://api.tenderen.com/api/v1/tenders?q=software&cpvCodes=72000000&limit=20" \
-H "Authorization: Bearer $TENDEREN_API_KEY"Scopes
Each key carries a list of scopes. New keys default to read-only (tenders:read). Calling an endpoint whose scope the key lacks returns 403 INSUFFICIENT_SCOPE.
Endpoints
Paths are relative to the base URL. The scope column shows the permission the key needs.
Tenders
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /tenders | tenders:read | Search tenders with filters and pagination. |
| GET | /tenders/:id | tenders:read | Get one tender. |
| GET | /tenders/:id/documents | tenders:read | List the documents attached to a tender. |
| GET | /tenders/:id/requirements | tenders:read | List the requirements extracted from a tender. |
| GET | /tenders/saved | tenders:read | List your company's saved tenders. |
| POST | /tenders/saved | tenders:write | Save a tender. |
| PATCH | /tenders/saved/:id | tenders:write | Update a saved tender. |
Bids
| Method | Path | Scope | What it does |
|---|---|---|---|
| POST | /bids | bids:write | Create a bid for a tender. |
| GET | /bids | bids:read | List bids. |
| GET | /bids/:id | bids:read | Get one bid. |
| PATCH | /bids/:id | bids:write | Update a bid. |
| POST | /bids/:id/submit | bids:write | Mark a bid as submitted. |
AI analysis
| Method | Path | Scope | What it does |
|---|---|---|---|
| POST | /analysis/tender/:id | analysis:write | Run an AI analysis of a tender. |
| POST | /analysis/risk/:id | analysis:write | Run an AI risk analysis of a tender. |
| POST | /analysis/match/:id | analysis:write | Score how well a tender matches your company. |
| POST | /analysis/gaps/:id | analysis:write | Find gaps between the requirements and your company profile. |
Market data
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /market/insights | market:read | Market statistics. |
| GET | /market/awards | market:read | Search contract awards. |
| GET | /market/competitors | market:read | Competitors seen in contract awards. |
Alerts and notifications
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /alerts | alerts:read | List alerts. |
| POST | /alerts | alerts:write | Create an alert. |
| GET | /alerts/:id | alerts:read | Get one alert. |
| PATCH | /alerts/:id | alerts:write | Update an alert. |
| DELETE | /alerts/:id | alerts:write | Delete an alert. |
| GET | /alerts/notifications/list | alerts:read | List notifications. |
| PATCH | /alerts/notifications/:id/read | alerts:write | Mark a notification as read. |
Teams
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /teams | teams:read | List teams. |
| POST | /teams | teams:write | Create a team. |
| GET | /teams/:id | teams:read | Get one team. |
| PATCH | /teams/:id | teams:write | Update a team. |
| GET | /teams/:id/members | teams:read | List team members. |
| POST | /teams/:id/members | teams:write | Add a team member. |
| DELETE | /teams/:id/members/:memberId | teams:write | Remove a team member. |
Consortiums
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /consortiums | tenders:read | List consortiums. |
| POST | /consortiums | tenders:write | Create a consortium for a tender. |
| GET | /consortiums/:id | tenders:read | Get one consortium. |
| GET | /consortiums/:id/members | tenders:read | List consortium members. |
| POST | /consortiums/:id/members | tenders:write | Invite a partner company. |
| GET | /consortiums/:id/responsibilities | tenders:read | List who is responsible for what. |
Documents (assets)
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /assets | assets:read | List documents in your library. |
| POST | /assets | assets:write | Create a document record. |
| GET | /assets/:id | assets:read | Get one document. |
| DELETE | /assets/:id | assets:write | Delete a document. |
| POST | /assets/:id/upload | assets:write | Upload a file to a document record. |
| GET | /assets/:id/download | assets:read | Download a document. |
Compliance
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /compliance/:tenderId | compliance:read | Compliance matrix for a tender. |
| POST | /compliance/espd | compliance:read | Generate an ESPD response. |
| GET | /compliance/certifications/list | compliance:read | List your company's certifications. |
Chat with a tender
| Method | Path | Scope | What it does |
|---|---|---|---|
| POST | /chat | chat:write | Ask a question about a tender. |
| GET | /chat/:sessionId/messages | chat:read | Get the messages in a chat session. |
Webhooks
| Method | Path | Scope | What it does |
|---|---|---|---|
| POST | /webhooks | webhooks:manage | Register a webhook endpoint. |
| GET | /webhooks | webhooks:manage | List webhook endpoints. |
| DELETE | /webhooks/:id | webhooks:manage | Delete a webhook endpoint. |
| GET | /webhooks/:id/deliveries | webhooks:manage | Delivery history for a webhook. |
Account
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /me | account:read | The user and company the key belongs to. |
| GET | /me/usage | account:read | API usage for the key. |
| GET | /health | none | Health check (no authentication). |
Pagination and filtering
List endpoints accept page (starting at 1) and limit (1–100, default 20) and return a pagination object with page, limit, total and pages. GET /tenders also accepts q, cpvCodes and regions (comma-separated), status, source, minValue, maxValue, deadlineBefore, deadlineAfter, sort (publishedAt, deadline or estimatedValue) and order (asc or desc).
{
"success": true,
"data": [ { "id": "…", "title": "…", "deadline": "…" } ],
"pagination": { "page": 1, "limit": 20, "total": 412, "pages": 21 }
}Errors
Errors return success: false with a human-readable error and a machine-readable code.
{
"success": false,
"error": "Insufficient permissions. Required scope: bids:write",
"code": "INSUFFICIENT_SCOPE"
}| Code | HTTP status | Meaning |
|---|---|---|
| INVALID_AUTH | 401 | Missing, malformed or unknown API key. |
| KEY_INACTIVE | 401 | The key has been revoked. |
| KEY_EXPIRED | 401 | The key has passed its expiry date. |
| INSUFFICIENT_SCOPE | 403 | The key lacks the scope this endpoint needs. |
| INVALID_DATA | 400 | The request body failed validation; see details. |
| INVALID_PARAMS | 400 | A query or path parameter is invalid. |
| FORBIDDEN | 403 | You are not allowed to change this resource. |
| NOT_FOUND | 404 | The resource does not exist or belongs to another company. |
| RATE_LIMIT_EXCEEDED | 429 | Too many requests in the current hour. |
| INTERNAL_ERROR | 500 | Something failed on our side; retry later. |
Rate limits
Each API key may make 1,000 requests per hour by default (the limit is stored per key). Going over returns 429 RATE_LIMIT_EXCEEDED; wait for the hourly window to reset. The MCP endpoint has its own limit of 1,000 requests per hour per token.
Webhooks
Status: you can register, list and delete webhook endpoints today, but event delivery is not live yet — no events are sent to registered endpoints at the moment. The format below is what deliveries will use. Poll the REST API (for example GET /alerts/notifications/list) until delivery ships.
Register an HTTPS endpoint with POST /webhooks and choose the events you want. The response contains a signing secret, shown only once.
Events
- tender.new — A new tender matches one of your alerts.
- tender.deadline — A followed tender's deadline is approaching.
- tender.awarded — A followed tender has been awarded.
- bid.submitted — A bid was marked as submitted.
- bid.status_changed — A bid changed status.
- alert.triggered — An alert produced new matches.
Verifying signatures
Every delivery is a POST with the JSON body {event, data, timestamp, webhookId} and the headers X-Tenderen-Event, X-Tenderen-Delivery and X-Tenderen-Signature. The signature is sha256= followed by the hex HMAC-SHA256 of the raw request body, keyed with your signing secret. Compare it in constant time before you trust the payload.
import crypto from 'node:crypto';
function isValidTenderenSignature(rawBody, signatureHeader, secret) {
const expected =
'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(signatureHeader ?? '');
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}A delivery that fails, or does not answer with a 2xx status within 10 seconds, is retried up to two more times: after 1 minute and after 5 minutes. The delivery history is available from GET /webhooks/:id/deliveries.
MCP connector for AI assistants
Tenderen runs a remote Model Context Protocol server, so AI assistants such as Claude, ChatGPT and Cursor can search tenders, assess fit, track a pipeline, draft bids and ask the tender documents on your behalf — 18 capability tools, with read access granted by default and writes, submissions and deletions as separate grants on the consent screen. Connect with OAuth (authorization code with PKCE; dynamic client registration is supported) or with an API key as a Bearer token. Tools that cannot be undone preview first and need confirmation. Every call is listed under Developers → AI connections, where connections can be tested and revoked.
MCP endpoint (Streamable HTTP)
https://tenderen.com/api/mcpLegacy endpoint (HTTP+SSE)
https://tenderen.com/api/mcp/sseOAuth discovery
https://tenderen.com/.well-known/oauth-authorization-server
https://tenderen.com/.well-known/oauth-protected-resourceSupport
Questions about the API or a specific integration: [email protected].
Last reviewed 4 October 2026