REST API
JSON over HTTPS. Base URL:
https://portal-demo.tender-lock.co/api/v1
Authentication
Send your organisation API key as a Bearer token on every request. Keys start with tl_live_ and are created in Settings → API & MCP.
Authorization: Bearer tl_live_YOUR_KEY
Errors
Errors return a non-2xx status and a JSON body:
{ "error": { "type": "not_found", "message": "Tender not found." } }
| Status | Meaning |
|---|---|
| 401 | Missing, invalid, expired or revoked key |
| 402 | Not included in your plan |
| 403 | Key lacks write access, or bids are still sealed |
| 404 | Not found in your organisation |
| 409 | Not allowed in the tender's current state |
| 422 | Invalid input |
| 429 | Rate limit: 120 requests per minute per key |
Endpoints
/meWho you are: organisation, key name, scopes and plan.
/tendersList your organisation's tenders, newest first. Optional status filter: draft, pending_approval, live, closed, awarded, no_award, cancelled.
Query: status limit
/tenders/{id}Full detail of one tender: scope, dates, requirements, evaluation criteria and invited suppliers.
/tenders needs write accessCreate a DRAFT tender (never published). A person must review, run checks and publish it in TenderLock. closes_at is ISO 8601 in your organisation's time zone, e.g. 2026-11-30T12:00.
| Field | Type | |
|---|---|---|
title | string | required |
description | string | required |
closes_at | string | required |
category | string | optional |
estimated_value | number | optional |
requirements | array | optional |
criteria | array | optional |
/tenders/{id}/suppliers needs write accessAdd a supplier to a DRAFT tender. Nothing is sent: invitations go out only when a person publishes the tender.
| Field | Type | |
|---|---|---|
supplier_name | string | required |
email | string | required |
/tenders/{id}/clarificationsClarification questions and answers for a tender.
/tenders/{id}/submissionsSubmitted bids for a tender, with prices and weighted scores. Only available after the closing date; bids stay sealed until then.
/tenders/{id}/auditThe append-only audit trail for a tender.
Query: limit
/suppliersSearch your supplier address book by company, email or category.
Query: q limit
/suppliers needs write accessAdd a supplier to your address book.
| Field | Type | |
|---|---|---|
company_name | string | required |
email | string | required |
contact_name | string | optional |
category | string | optional |
/suppliers/{id}One supplier from your address book with Companies House rating, latest Creditsafe credit check (score, band, limit, turnover, profit, CCJs) and the tenders they were invited to.
/suppliers/{id}/credit-check needs write accessRun a Creditsafe credit check on a supplier (Business plan and above). Uses credits; you are not charged if the check fails.
| Field | Type | |
|---|---|---|
supplier_id | string | required |
/tenders/{id}/blue-teamBlue Team items for a tender: gaps found, suggested fixes and whether each was applied or dismissed.
/tenders/{id}/red-teamThe latest Red Team stress test for a tender: readiness, summary and every finding with severity, explanation and status.
/tenders/{id}/reviewWho is on the Blue and Red review teams for a tender and the sign-offs recorded.
/entitiesThe companies (entities) in your group, with tender and people counts.
/teamYour team: roles, super admin and owner flags, entities, 2FA, invite status and last sign-in. Key must be created by an owner, super admin or team admin. Optional status: active, invited, disabled.
Query: status
/team/{id}Full audit of one team member: details, roles, entities, 2FA devices, signed-in devices, failed sign-ins, tender stats and recent activity.
Query: limit
/team needs write accessInvite someone to your team with one or more roles (role keys or names, e.g. "Evaluator"). Emails the invitation and returns the invite link. Key must be created by an owner, super admin or team admin. Super admin can only be given in TenderLock.
| Field | Type | |
|---|---|---|
email | string | required |
roles | array | required |
/templatesYour saved tender templates.
/reports/summaryHeadline reporting numbers: tenders by status, created, published, awarded value, submissions and credits used. Optional days (default 90).
Query: days
/creditsYour organisation's plan and current credit balance.
Examples
Create a draft tender (curl)
curl -X POST https://portal-demo.tender-lock.co/api/v1/tenders \
-H "Authorization: Bearer tl_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Office cleaning, Manchester HQ",
"description": "Daily office cleaning for a 4,000 sq ft office...",
"closes_at": "2026-11-30T12:00",
"estimated_value": 24000,
"requirements": [
{"text": "Confirm you hold public liability insurance of at least £5m", "kind": "mandatory"}
],
"criteria": [
{"name": "Quality", "weight": 60},
{"name": "Price", "weight": 40, "is_price": true}
]
}'
List live tenders (Python)
import requests
r = requests.get("https://portal-demo.tender-lock.co/api/v1/tenders", params={"status": "live"},
headers={"Authorization": "Bearer tl_live_YOUR_KEY"})
for t in r.json()["data"]:
print(t["title"], t["closes_at"])
Results after close (JavaScript)
const res = await fetch("https://portal-demo.tender-lock.co/api/v1/tenders/TENDER_ID/submissions", {
headers: { Authorization: "Bearer tl_live_YOUR_KEY" }
});
const { data } = await res.json(); // ranked bids with weighted scores
