REST API

JSON over HTTPS. Base URL:

https://tenderlock.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." } }
StatusMeaning
401Missing, invalid, expired or revoked key
402Not included in your plan
403Key lacks write access, or bids are still sealed
404Not found in your organisation
409Not allowed in the tender's current state
422Invalid input
429Rate limit: 120 requests per minute per key

Endpoints

GET/me

Who you are: organisation, key name, scopes and plan.

GET/tenders

List your organisation's tenders, newest first. Optional status filter: draft, pending_approval, live, closed, awarded, no_award, cancelled.

Query: status limit

GET/tenders/{id}

Full detail of one tender: scope, dates, requirements, evaluation criteria and invited suppliers.

POST/tenders needs write access

Create 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.

FieldType
titlestringrequired
descriptionstringrequired
closes_atstringrequired
categorystringoptional
estimated_valuenumberoptional
requirementsarrayoptional
criteriaarrayoptional
POST/tenders/{id}/suppliers needs write access

Add a supplier to a DRAFT tender. Nothing is sent: invitations go out only when a person publishes the tender.

FieldType
supplier_namestringrequired
emailstringrequired
GET/tenders/{id}/clarifications

Clarification questions and answers for a tender.

GET/tenders/{id}/submissions

Submitted bids for a tender, with prices and weighted scores. Only available after the closing date; bids stay sealed until then.

GET/tenders/{id}/audit

The append-only audit trail for a tender.

Query: limit

GET/suppliers

Search your supplier address book by company, email or category.

Query: q limit

POST/suppliers needs write access

Add a supplier to your address book.

FieldType
company_namestringrequired
emailstringrequired
contact_namestringoptional
categorystringoptional
GET/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.

POST/suppliers/{id}/credit-check needs write access

Run a Creditsafe credit check on a supplier (Business plan and above). Uses credits; you are not charged if the check fails.

FieldType
supplier_idstringrequired
GET/tenders/{id}/blue-team

Blue Team items for a tender: gaps found, suggested fixes and whether each was applied or dismissed.

GET/tenders/{id}/red-team

The latest Red Team stress test for a tender: readiness, summary and every finding with severity, explanation and status.

GET/tenders/{id}/review

Who is on the Blue and Red review teams for a tender and the sign-offs recorded.

GET/entities

The companies (entities) in your group, with tender and people counts.

GET/team

Your 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

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

POST/team needs write access

Invite 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.

FieldType
emailstringrequired
rolesarrayrequired
GET/templates

Your saved tender templates.

GET/reports/summary

Headline reporting numbers: tenders by status, created, published, awarded value, submissions and credits used. Optional days (default 90).

Query: days

GET/credits

Your organisation's plan and current credit balance.

GET/billing

Your plan, billing interval, status, current period, next bill date and amount, cancellation and account credit.

GET/contacts

Search your shared contact book (people at suppliers and buyers). Respects the key creator's role: without "see everyone's contacts" only their own contacts are returned. Optional q (name, email, job title), company_id, owner_id, limit.

Query: q company_id owner_id limit

GET/contacts/{id}

One contact with phones, all email addresses, owner, creator, linked companies, recent emails and call/SMS/WhatsApp logs.

POST/contacts needs write access

Add a person to your contact book, optionally linked to a company. The key creator becomes the owner.

FieldType
emailstringrequired
namestringoptional
job_titlestringoptional
mobilestringoptional
work_phonestringoptional
company_idstringoptional
GET/companies

Search your companies. Each company can be a Supplier, a Buyer or both. Optional type: supplier, buyer or both; q; limit.

Query: type q limit

POST/companies/{id}/type needs write access

Mark a company as a Supplier, a Buyer or both.

FieldType
company_idstringrequired
is_supplierbooleanoptional
is_buyerbooleanoptional
GET/emails

Email conversations sent or received through TenderLock, newest first, with unread counts and tracking. Optional contact_id, company_id, tender_id, unread_only.

Query: contact_id company_id tender_id unread_only limit

GET/emails/{thread_id}

Every message in one email conversation, with delivery, open and click events.

POST/emails needs write access

Send an email to a contact from TenderLock, as the key creator. Goes from their connected mailbox if they have one, otherwise from TenderLock. body is plain text or simple HTML. Pass thread_id to reply in an existing conversation. Optional company_id and tender_id to link it.

FieldType
contact_idstringrequired
subjectstringrequired
bodystringrequired
thread_idstringoptional
company_idstringoptional
GET/phone/usage

Phone numbers on the account, call minutes used and available this month, and whether minutes top up automatically.

GET/comm-logs

Logged calls, SMS and WhatsApp messages for a contact, company or tender: date, time, who, direction, outcome, note, duration, linked tender and AI call summary. Use get_call for the full transcript.

Query: contact_id company_id tender_id channel limit

GET/comm-logs/{id}

One logged call or message with duration, transcript, AI summary, linked tender and the follow-up tasks created from it.

POST/comm-logs/{id}/tender needs write access

Link a logged call or message to a tender (or pass an empty tender_id to unlink). Writes a line on the tender's audit trail and moves its follow-up tasks with it.

FieldType
log_idstringrequired
POST/comm-logs needs write access

Log a call, SMS or WhatsApp against a contact or company. Date, time and author are recorded automatically. outcome is for calls: connected, no_answer, voicemail, busy, wrong_number.

FieldType
contact_idstringoptional
company_idstringoptional
channelstringrequired
directionstringoptional
outcomestringoptional
notestringrequired
GET/tasks

The key creator's tasks: follow-ups the AI pulled from their calls and tasks created by the team. Optional status (open, done or all; default open), tender_id, contact_id, company_id, limit.

Query: status tender_id contact_id company_id limit

POST/tasks needs write access

Create a task linked to a contact or company. Optional assignee_id (a team member, default the key creator), due_on (YYYY-MM-DD) and tender_id. It is noted on the contact or company, and on the tender's audit trail if a tender is given. supplier contacts and companies by default; set scope to buyer-contact for buyer-side contacts.

FieldType
titlestringrequired
detailstringoptional
contact_idstringoptional
company_idstringoptional
assignee_idintegeroptional
due_onstringoptional
scopestringoptional
GET/tasks/{id}

One task with its linked contact, company, tender, source call and every note.

POST/tasks/{id}/notes needs write access

Add a note to one of the key creator's tasks. The note is copied to the contact, the company and the linked tender's audit trail.

FieldType
task_idstringrequired
notestringrequired
POST/tasks/{id}/complete needs write access

Mark one of the key creator's tasks as done. Completion is logged on the contact, company and tender.

FieldType
task_idstringrequired
GET/phone-numbers

Phone numbers on your account: number, type (mobile or landline), who it is assigned to, team line flag and capabilities.

GET/audit-log

Organisation-wide audit log: who did what, when, from which IP and location. Key must be created by an owner or team admin. Optional type (login or action), user_id, since (ISO date), limit.

Query: type user_id since limit

Examples

Create a draft tender (curl)

curl -X POST https://tenderlock.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://tenderlock.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://tenderlock.co/api/v1/tenders/TENDER_ID/submissions", {
  headers: { Authorization: "Bearer tl_live_YOUR_KEY" }
});
const { data } = await res.json(); // ranked bids with weighted scores

Before you renew. Before you appoint. Before you buy.
TenderLock it.

Run your first live tender free. No card required.