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. |
| PATCH | /webhooks/:id | webhooks:manage | Change a webhook's URL, events or active flag. |
| DELETE | /webhooks/:id | webhooks:manage | Delete a webhook endpoint. |
| POST | /webhooks/:id/test | webhooks:manage | Send a test event to a webhook now. |
| POST | /webhooks/:id/rotate-secret | webhooks:manage | Issue a new signing secret. |
| 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
Webhooks are part of the Enterprise plan. Events only go to endpoints that belong to the company the event concerns, and endpoints must be public https addresses.
Register an HTTPS endpoint with POST /webhooks (or under Developers → Webhooks in the app) and choose the events you want. The response contains a signing secret, shown only once; POST /webhooks/:id/rotate-secret issues a new one and POST /webhooks/:id/test sends a test event right away.
Events
- tender.new — A newly published tender matches one of your company's alerts (once per tender).
- tender.deadline — A tender in your pipeline has its submission deadline in 7, 3 or 1 days.
- tender.awarded — A contract award was published for a tender in your pipeline.
- bid.submitted — A pipeline entry moved to Submitted.
- bid.status_changed — A pipeline entry changed stage.
- alert.triggered — An alert found new matching tenders.
Verifying signatures
Every delivery is a POST with a JSON body holding id, event, createdAt and data, and the headers X-Tenderen-Event, X-Tenderen-Event-Id, X-Tenderen-Delivery and X-Tenderen-Signature. The signature header has the form t=TIMESTAMP,v1=SIGNATURE, where TIMESTAMP is in Unix seconds and SIGNATURE is the hex HMAC-SHA256 of TIMESTAMP, a dot and the raw body, keyed with your signing secret. Compare it in constant time, reject timestamps more than five minutes old, and use the event id to ignore duplicates.
import crypto from 'node:crypto';
function isValidTenderenSignature(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries((signatureHeader ?? '').split(',').map((p) => p.split('=')));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const a = Buffer.from(parts.v1 ?? '');
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}A delivery that does not get a 2xx answer within 10 seconds is retried after 1 minute, 5 minutes, 30 minutes and 2 hours; redirects are not followed. After 50 failed deliveries in a row the endpoint is turned off and its owner is notified; PATCH /webhooks/:id with active: true turns it back on. The delivery history (30 days) 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