Documentation
Handshake Documentation
Everything you need to integrate Handshake into your workflow.
Getting Started
Handshake is an API contract testing platform that validates your backend API against its OpenAPI specification on every pull request. It catches breaking changes before they reach production and keeps frontend and backend teams in sync.
Get up and running in four steps:
- Sign up with GitHub — Log in at
handshake.kumizhi-ai.comusing your GitHub account. - Create a team — Teams group your projects and manage member access. Members are assigned one of four roles: owner, admin, member, or viewer.
- Create a project — Each project represents one API service. Upload your OpenAPI spec (YAML or JSON, OpenAPI 3.x or Swagger 2.0) to define the contract.
- Add the GitHub Action — Drop the Handshake action into your CI workflow. It validates your staging API against the contract on every PR.
GitHub Action
The Handshake GitHub Action runs contract validation as part of your CI pipeline. It sends requests to your staging API and compares responses against the contract spec.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
| api-key | Yes | — | Handshake project API key (hsk_...) |
| mode | No | validate | Action mode: "validate" runs live endpoint tests against validation-url. "compatibility" checks spec changes against consumers (requires spec-file and contract-id). |
| validation-url | No | — | Base URL of the API to validate. If omitted, falls back to the project’s default environment configured in the dashboard. |
| base-url | No | https://ci.handshake.kumizhi-ai.com | Handshake CI runner URL |
Outputs
| Output | Description |
|---|---|
| status | Validation result: passed, failed, or error |
| run-id | CI run ID for dashboard reference |
| total | Total endpoints validated |
| passed | Endpoints that passed |
| failed | Endpoints that failed |
Full workflow example
API Keys
Each project has its own API key, used to authenticate CI validation requests. API keys are prefixed with hsk_ and stored as bcrypt hashes — Handshake never stores the raw key.
Your API key
Your project API key is generated automatically when the project is created and shown once — copy it immediately to your CI secrets store. To regenerate a key, navigate to your project settings and click Rotate Key. This invalidates the old key and shows the new one once. Handshake stores only bcrypt hashes and cannot recover the raw value.
After rotating
Update your CI secrets immediately after rotating. The old key is permanently invalidated and cannot be recovered.
Security best practices
- Store keys in GitHub Actions secrets (
Settings → Secrets → Actions) - Never commit API keys to your repository
- Rotate keys if you suspect they've been exposed
- Use separate projects (and keys) for separate API services
CI Configuration
Handshake validates your API by sending real HTTP requests to your staging environment and comparing responses against the contract specification. Each endpoint is tested for status codes, response schema, and required headers.
Triggering validation
The GitHub Action is the simplest way to trigger validation. You can also trigger runs directly via the CI runner API:
Validation results
Each CI run produces a detailed validation report visible in the dashboard. For each endpoint, Handshake checks:
- Status code — Does the response return the expected HTTP status?
- Response schema — Does the body match the OpenAPI schema definition?
- Required fields — Are all required properties present in the response?
Plan limits
| Plan | CI Runs / Month | Rate Limit |
|---|---|---|
| Free | 100 | 60 req/min |
| Pro | 1,000 | 300 req/min |
| Team | 10,000 | 1,000 req/min |
| Enterprise | Unlimited | Unlimited |
CI run counts reset monthly. Validation runs have a 120-second timeout with a 10-second limit per HTTP request.
Mock Server
Handshake can generate a mock server from your contract specification. Frontend teams can build against realistic mock data while the backend is still in development.
Starting the mock server
Enable the mock server from your project's dashboard. Once started, your mock API is available at:
https://{project-slug}.mock.handshake.kumizhi-ai.com
Making requests
Mock data generation
Mock responses are generated using faker.js based on your schema definitions. String formats ( email, uuid, date-time) produce realistic values. Arrays return 1–3 items by default.
On Pro and above, Handshake layers an AI pass on top of faker.js: Claude generates realistic values for fields where faker can't (e.g., stock tickers, product names, bios). AI-enhanced templates are generated once per schema change and cached, so there's no per-request latency cost.
Configuration
The mock server respects your contract's response schemas and status codes. You can configure the mock server from the dashboard to customize response delays and default status codes.
CLI — Local Mock Server
Run a local mock server powered by your Handshake contracts. No Docker or cloud dependency — just install the CLI and start mocking.
Installation
Quick Start
1. Get your API key from your project's Settings page in the Handshake dashboard.
2. Start the mock server:
3. Make requests against your local mock:
mock start flags
| Flag | Default | Description |
|---|---|---|
| --api-key | $HANDSHAKE_API_KEY | Project API key |
| --port | 4010 | Local server port |
| --latency | 0 | Simulated response latency (ms) |
| --error-rate | 0 | Fraction of requests returning 500 (0-1) |
| --watch | false | Re-fetch contracts every 30s |
| --validate | false | Validate requests against OpenAPI schemas |
| --seed <number> | (random) | Faker seed for reproducible responses |
| --cors <origins> | * | CORS origin(s), comma-separated |
| --compose <path> | (none) | Compose file for multi-project setup |
| --verbose | false | Log request/response bodies (truncated) |
| --https | false | Enable HTTPS with self-signed cert |
| --cert <path> | (auto) | Custom TLS certificate path |
| --key <path> | (auto) | Custom TLS key path |
| --no-dashboard | (enabled) | Disable local web dashboard |
| --proxy <url> | (none) | Upstream URL for transparent proxy mode |
| --no-telemetry | false | Disable anonymous usage telemetry |
| --config | .handshake.json | Config file path |
| --api-url | https://api.handshake.kumizhi-ai.com | API base URL |
You can also save configuration in a .handshake.json file:
Offline Mode
The CLI caches your contracts locally. If the API is unreachable, it falls back to the cached version.
To pre-cache for offline use:
Cache is stored in .handshake/cache/. Add this directory to your .gitignore.
Inspecting Cache
Use handshake mock status to print a summary of the local cache without starting the server. It shows the project name, route count, contract count, cache age, and active config (port, validate, seed, cors, proxy).
Exits with a warning if no cache exists for the project. Run handshake mock pull or handshake mock start first to populate it.
Custom Responses
Override any route with a static response using the customResponses config. Keys use exact paths (e.g., GET:/api/users/123), not route templates with parameters:
Request Validation
Enable --validate to check incoming requests against your OpenAPI contract schemas. The mock server validates:
- Request body against
requestBodyschema (JSON Schema validation) - Query parameters — required presence and type checking
- Path parameters — type checking against schema
- Content-Type — expects
application/jsonwhen a body schema is defined
Validation is non-blocking — requests still receive mock responses. Warnings appear in the terminal output and as an X-Mock-Validation-Warnings response header (contains the warning count).
Example output with validation enabled:
You can also enable validation in your config file:
Reproducible Responses
Use --seed to get deterministic mock responses. The same seed with the same schema produces identical output every time — useful for snapshot testing and screenshots.
Or set it in your config file: "seed": 42
CORS Configuration
By default, the mock server allows all origins (*). To restrict CORS to specific origins (required for credentials: 'include' requests):
When specific origins are set, the server adds Access-Control-Allow-Credentials: true and exposes custom headers like X-Mock-Contract.
Multi-Project Setup
Use a compose file to run multiple mock servers with a single command. Each service gets its own port and configuration:
Flags like --watch and --verbose are global and apply to all services. Per-service settings (port, seed, validate, cors) are defined in the compose file.
Local Dashboard
The mock server includes a built-in web dashboard at /_handshake/. It provides three tabs:
- Routes — browse all mocked routes with expandable schemas and a filter
- Requests — live request log with status, latency, validation, and expandable bodies
- Config — server info, feature flags, mock config, and contract list
The dashboard is enabled by default. Disable it with --no-dashboard.
HTTPS
Enable HTTPS with --https. On first use, a self-signed certificate is generated and stored in ~/.handshake/certs/. Subsequent runs reuse the same cert (valid for 365 days).
To use your own certificate (e.g., from mkcert):
Quick Setup with Init
Run handshake init to set up a new project interactively. The wizard validates your API key, creates .handshake.json, updates .gitignore, and optionally adds a mock script to your package.json.
Local Contract Validation
Use handshake ci run to validate a running service against your contract schemas. It makes real HTTP requests and checks responses.
Exit code 0 means all endpoints passed. Exit code 1 means one or more failed. Use --report to post results to the Handshake dashboard:
ci run flags
| Flag | Default | Description |
|---|---|---|
| --base-url <url> | (none) | Target server for contract validation (required) |
| --api-key | $HANDSHAKE_API_KEY | Project API key (also accepts apiKey in .handshake.json) |
| --report | false | Post results to the Handshake dashboard |
| --timeout <ms> | 10000 | Per-request timeout |
| --fail-on-warning | false | Exit 1 when validation warnings are produced |
Proxy Mode
Use --proxy to run the CLI as a transparent contract validation proxy. Instead of generating mock responses, it forwards all requests to a real upstream server and validates both requests and responses against your contract schemas in real-time.
Handshake Proxy Server vX.Y.Z
Project: user-api
Proxy: https://staging-api.example.com
Mode: proxy | validate
10:32:01 GET /api/users → 200 ✓ contract valid
10:32:02 POST /api/users → 201 ◊ request missing "email"
You can also set the proxy target in your config file:
In proxy mode, --latency, --error-rate, --seed, and custom responses are ignored since real upstream responses are used. Validation is passive—it logs warnings but never blocks requests.
Telemetry
The CLI sends anonymous usage events so we can understand which features matter and catch regressions. A random client ID is generated on first run and stored at ~/.handshake/telemetry-id. Events include CLI version, command name, Node version, OS, session duration, request count, and which flags were used. Request bodies, URLs, contracts, API keys, and any project identifiers are never sent.
On first run, the CLI prints a one-line notice. To opt out, pass --no-telemetry or set "noTelemetry": true in .handshake.json. Telemetry failures are silent and never block CLI usage.
Troubleshooting
Invalid API key — verify your key in Project Settings. Pass it via --api-key flag or set the HANDSHAKE_API_KEY environment variable.
No contracts found — upload a contract at handshake.kumizhi-ai.com first, then run the CLI.
Port already in use — use --port <number> to pick a different port.
Cannot reach API (no cache) — run handshake mock pull while online to download contracts for offline use.
Cannot reach API (with cache) — the CLI automatically falls back to cached data. Reconnect to refresh.
For other issues, please open an issue on GitHub.