arrowup

Developers

321GoCheck MCP server for UK background checks

Add UK background checks to your HR system, ATS or AI agent. Our remote MCP server lets any Model Context Protocol client price, order and track checks for a 321GoCheck client account. Start with a free test key: the sandbox prices real orders but never places them.

Endpoint (Streamable HTTP)https://api.321gocheck.com/mcp

At a glance

  • Transport: Streamable HTTP, JSON responses, stateless (no session id). Protocol versions 2025-11-25, 2025-06-18, 2025-03-26.
  • Auth for assistants: OAuth 2.1 with PKCE (S256) and dynamic client registration. Discovery from the 401 challenge via https://api.321gocheck.com/.well-known/oauth-protected-resource.
  • Auth for your own systems: the client's API key as Authorization: Bearer GC_live_…. GC_test_… keys are a sandbox.
  • Scopes: orders:read (packages, quotes, orders, status) and orders:write (place, cancel, resend).
  • Limits: 60 tool calls a minute per account; up to 10 candidates per order; quotes last 30 minutes.
  • Data: candidates' names, emails and progress only. Documents, report contents and referee answers are never returned; completed checks return a link to the report in the client app.

How an order works

  1. list_packages returns package ids such as fixed:4 (our packages) and saved:12 (the client's own), with prices.

  2. quote_order validates the candidates and returns the exact price and a quote_id. Nothing is ordered.

  3. Show the quote to the user. Only after they confirm, call create_order with the quote_id and confirm: true. It is idempotent: the same quote never orders twice.

  4. Each candidate gets an email invitation and completes their part on their phone. Follow progress with list_orders and get_order_status.

Tools

list_packages read

The background check packages the client can order: 321GoCheck's fixed packages and the client's own saved packages, with the checks in each, the price per candidate and the optional criminal record check levels.

client_type"employer" | "landlord"Only packages for employers (staff) or landlords (tenants)

quote_order read

Check and price an order before placing it: a package, optionally a basic criminal record check, and one or more candidates. Nothing is ordered and nobody is contacted. Returns a quote_id that create_order needs; quotes last 30 minutes.

package_id *stringFrom list_packages, e.g. 'fixed:4' or 'saved:12'
candidates *array of objectEach: first_name, last_name, email, phone_code, phone_number
criminal_check"E & W - Basic" | "Scotland - Basic" | "NI - Basic"Optional basic criminal record check (England & Wales, Scotland or Northern Ireland)
notestringOptional note on the order, e.g. the role or a reference

create_order write

Place an order from a quote. Only call this after showing the quote (package, candidates, total including VAT) to the user and getting their explicit confirmation. The order is invoiced to the client's account and each candidate is emailed an invitation. Calling it again with the same quote_id does not order twice.

quote_id *string
confirm *booleantrue: the user has confirmed this quote

list_orders read

The client's orders, newest first, with each candidate's stage.

status"all" | "in progress" | "completed" | "cancelled"
limitinteger

get_order_status read

One order in detail: for each candidate and each check, the stage (with the candidate, waiting for referees, being checked, completed), the expected completion date, whether it is overdue, and a link to the report in the client app once completed.

order_id *integer

resend_invite write

Email (and text, if a phone number was given) a candidate their invitation again, for a candidate who hasn't started yet.

order_id *integer
candidate_email *string

cancel_order destructive

Cancel an order: checks stop and the candidates' links stop working. Only call this after the user has explicitly confirmed. It cannot be undone.

order_id *integer
reason *stringWhy the order is cancelled

* required. Tool errors come back as a normal result with isError: true and a message you can show the user.

Examples

VS Code / GitHub Copilot (.vscode/mcp.json)

{
  "servers": {
    "321gocheck": { "type": "http", "url": "https://api.321gocheck.com/mcp" }
  }
}

List the tools with curl

curl -s https://api.321gocheck.com/mcp \
  -H "Authorization: Bearer GC_test_YOUR_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Price an order

curl -s https://api.321gocheck.com/mcp \
  -H "Authorization: Bearer GC_test_YOUR_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{
        "name":"quote_order",
        "arguments":{"package_id":"fixed:4","criminal_check":"E & W - Basic",
          "candidates":[{"first_name":"Jane","last_name":"Smith","email":"[email protected]"}]}}}'

Python (official MCP SDK)

# pip install mcp
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import create_mcp_http_client, streamable_http_client

async def main():
    headers = {"Authorization": "Bearer GC_test_YOUR_TEST_KEY"}
    async with create_mcp_http_client(headers=headers) as http, \
            streamable_http_client("https://api.321gocheck.com/mcp", http_client=http) as (read, write, *_):
        async with ClientSession(read, write) as session:
            await session.initialize()
            packages = await session.call_tool("list_packages", {"client_type": "employer"})
            print(packages.content[0].text)

asyncio.run(main())

REST API (without MCP)

The same steps as plain HTTPS calls with the API key as Authorization: Bearer GC_live_… (or GC_test_… for the sandbox).

  • GET https://api.321gocheck.com/packages?client_type=employer: packages and prices.
  • POST https://api.321gocheck.com/background-check/quote with package_id, candidates (first_name, last_name, email), optional criminal_check and note: the price and a quote_id.
  • POST https://api.321gocheck.com/background-check with quote_id: places the order once the user agrees. The same quote never orders twice.
  • GET https://api.321gocheck.com/background-check/{order_id}: each candidate's progress.

Webhooks

Instead of polling, your system is told when something changes. Add an endpoint on the API dashboard or with POST https://api.321gocheck.com/webhooks (a live key): url and the events you want.

  • order.placed, order.completed, order.cancelled: the order.
  • candidate.updated: a candidate moves from invited to filling in, being checked, completed.
  • check.completed: one check of a candidate is done. report.ready: all of them are, with the report link.

Every delivery is signed: X-GoCheck-Signature is the SHA-256 HMAC of timestamp.body with the endpoint's secret, and X-GoCheck-Timestamp lets you reject old requests. Answer 2xx within 10 seconds; otherwise we retry for 12 hours. Payloads carry names, emails and stages only, never documents or results.

OAuth endpoints

  • Authorisation server metadata: https://api.321gocheck.com/.well-known/oauth-authorization-server
  • Registration (public clients, token_endpoint_auth_method: none): https://api.321gocheck.com/oauth/register
  • Authorise: https://api.321gocheck.com/oauth/authorize. The user signs in to 321GoCheck and approves your app.
  • Token (authorisation code with PKCE, refresh token rotation): https://api.321gocheck.com/oauth/token
  • Revoke: https://api.321gocheck.com/oauth/revoke. Clients can also disconnect apps on their API dashboard.

Building an integration for many 321GoCheck clients, or need help? Email [email protected].