Create or update one of YOUR users as a Keyspace member
Idempotent on externalUserId. Resolves WHICH Keyspace member you mean before writing, in this order (first hit wins): (1) the member already linked to this externalUserId; (2) email → an existing Keyspace user (case-insensitive); (3) phone → an existing user after normalization (Thai numbers, +66 default); (4) employeeId → a member of the project carrying that employee id; (5) nothing matched → a new member is created. A matched user that is not yet a member of your project is added as one. A key that resolves to a DIFFERENT member than the one already linked to this externalUserId — or to a member this app already manages under another externalUserId — is rejected 409 (data.conflictKey names the key); Keyspace never silently re-links. unit is a BINDING, never an identity: it places the member in the condo unit (first resident = reservation owner, later ones = participants) but never picks the person. First call links the member to your app and adds it to the access groups fixed at app provisioning (partnerAccessGroupIds) — devices only ever receive credentials through those groups (credential ≠ permission). Later calls update the profile. A previously offboarded member is re-activated by this call (same memberId, groups restored). Requires an app_credentials token (a delegated act_as token is rejected 403) and a single-project app.
Authorization
bearerAuth Access token from POST /auth/accessToken
In: header
Path Parameters
YOUR stable identifier for the user (opaque to Keyspace). Bound to exactly one Keyspace member per app on first PUT.
length <= 128Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X PUT "https://example.com/partner/members/string" \ -H "Content-Type: application/json" \ -d '{ "firstName": "string", "lastName": "string" }'{ "code": "KS000", "success": true, "message": "string", "data": { "memberId": "string", "externalUserId": "string", "projectId": "string", "created": true, "matchedBy": "link", "accessGroupIds": [ "string" ], "employeeId": "string", "unit": { "roomId": "string", "addressNo": "string", "groupId": "string", "role": "owner" } }}Offboard one of your members DELETE
Deactivates the member in the project: every card (physical AND the auto-generated one) is revoked, device access is withdrawn, and the member is removed from your access groups. The link between your externalUserId and the member is KEPT, so a later PUT re-activates the same member rather than creating a duplicate. Idempotent.
Declaratively set the member’s cards and face PUT
Applies, in order: face (set / erase), the physical card set (enroll missing, revoke absent), then the auto-generated card rule — if the member now has a face and ZERO active physical cards, Keyspace mints ONE virtual card with a random unique number and returns it with generated: true so you can print/label a card. Card numbers default to Hikvision decimal-reversed. Supplying a face REQUIRES faceConsentAt. The member must be active (409 if offboarded — PUT the member first). Devices receive the credentials only through the access groups your app was provisioned with.