Appearance
Keyspace Third-Party API — Getting Started
Version 1.11.1 · The partner "start here" for every Keyspace integration: credentials, authentication, the response envelope, webhooks — and the index of per-module guides. For field-by-field detail see the full API reference; for the machine-readable contract see the OpenAPI spec.
This page is served by each environment — read it from the environment you're integrating against. Base URLs:
| Environment | Base URL |
|---|---|
| Development | https://api.keyspace-dev.com |
| UAT | https://api.keyspace-qat.com |
| Production | https://api.keyspace.tech |
1. Pick your modules
Every integration authenticates the same way (§3) and reads the same envelope. What you build on top depends on what your app does — each module has its own narrative guide with a sandbox and a go-live checklist:
| You want to… | Guide | Reference |
|---|---|---|
| Book meeting rooms and desks from your app — find → book → pay → check-in — and receive booking events | Meeting rooms & desks | §Meeting Rooms … §Meeting Lifecycle |
| Your app is the system of record for its users — push profiles, access-card numbers and face photos; Keyspace enrols the doors | Members & credentials | §5 Provision members |
Modules combine: a condo app typically provisions its residents (members guide) and then books facilities as those residents (act_as, §4 → meeting guide). New modules are added to this table as they open to partners — it is the authoritative list; each guide lives at /docs/guides/<module>.md.
2. Get your credentials
Your Keyspace contact issues you, per environment:
app_id+app_secret— your OAuth client credentials- a
projectId— the property your app is scoped to
Keep app_secret server-side only — never in a mobile app, browser bundle, or repository. Credentials do not cross environments; you get a fresh set for UAT and production.
Confirm they work:
bash
curl -X POST <baseUrl>/auth/accessToken \
-H "Content-Type: application/json" \
-d '{"app_id":"<app_id>","app_secret":"<app_secret>","grant_type":"app_credentials"}'
# → { access_token, expires_in, refresh_token, refresh_token_expires_in }3. Authenticate and read responses
Send every request as Authorization: Bearer <access_token>. Refresh proactively (~5 min before expires_in); on a 401 (KS002), refresh → retry once → re-authenticate. Authenticate once per server process, not per request.
Every response except the token endpoint is wrapped:
json
{ "code": "KS000", "success": true, "message": "…", "data": { … }, "meta": { … } }KS000 is success; errors carry a KSxxx code next to the HTTP status (409 KS012 booking conflict, 409 KS006 duplicate / identity conflict, 429 KS036 rate limited …). Full list and envelope rules: reference §Error Handling · §API Conventions.
To scaffold a typed client fast, hand your coding agent this environment's OpenAPI spec and the full reference.
4. Acting as your users (act_as) — optional
By default your app acts as itself: bookings belong to the app, people on them are attendees. If your users should get Keyspace's per-user scope (member quotas, member-owned bookings, per-member roles), exchange your app credentials for a member-scoped token — same endpoint, grant_type: "act_as", subject: "<your user id>". No Keyspace password or login for the user; the token is short-lived, has no refresh token, and can never exceed your app's own scope.
The subject is the same id you use as externalUserId in the members guide, so a member you provisioned and a member you act as are one person. Coordinate the scope with your Keyspace contact first. Full detail + errors (KS221 / KS223): reference §act_as.
5. (Optional) Receive events via webhooks
Instead of polling, Keyspace can POST lifecycle events to your server as they happen — booking create / cancel / reminders / no-show / payment-lapse — and, for projects using the Visitor Management System, visitor events (VMS_INVITE_SENT, VMS_VISITOR_CHECKED_IN, VMS_HOST_CANCELLED) on the same channel. Note VMS_INVITE_SENT carries the visitor's access QR (qrCardCode) for you to relay to the invitee — treat it as a credential.
Give your Keyspace contact:
- an HTTPS callback URL (a tunnel is fine for development)
- a shared secret you generate (32–256 characters)
- which events you want (catalog in the reference)
- your endpoint's auth scheme + its material:
signature-only— nothing (you verify our HMAC signature)bearer— a static tokencustom-header— one or more{ name, value }headers (e.g.X-Api-Key,X-Client-Id)jwt— nothing; Keyspace mints a short-lived HS256 JWT signed with the shared secret
Every delivery is HMAC-signed regardless — that proves it's from Keyspace. The auth scheme is only the credential your gateway needs. Pick
signature-onlyunless your endpoint genuinely rejects unauthenticated POSTs.
Implement the receiver (details + code in the reference):
- Verify the signature over the raw body (
X-Keyspace-Signature = sha256=HMAC-SHA256(secret, timestamp + "." + rawBody)), and reject a staleX-Keyspace-Timestamp(~5 min). - Ack
2xxwithin 10 seconds; process async. Failures retry; 20 consecutive dead deliveries auto-disable your webhook. - De-duplicate on
X-Keyspace-Delivery; the payload is a change signal — re-fetch the resource (GET /meetings/:id) for authoritative state (it never containspinCode).
6. Test, then go live
Development first. Each guide ends with a sandbox checklist — run the ones for the modules you use against https://api.keyspace-dev.com, and make your test clean up after itself: meeting sandbox · members sandbox.
Go live. Run the matching go-live checklist (meeting · members), then ask your Keyspace contact to issue production credentials and register your production webhook — credentials and webhooks are per-environment.
Found the API behaving differently from these docs? Send your Keyspace contact the endpoint, what you expected, and what you saw — the docs are served from the API and we fix drift at the source.