Build your first hotel check-in
A conceptual walkthrough — install the SDK, start a session, handle the NFC tap, and process the result.
Add KeyShareCore + KeyShareWallet via CocoaPods, SPM, or Gradle. See the Hotel → Wallet SDK tab for full installation guides.
let keyshare = KeyShareCore(
apiKey: "ks_live_...",
propertyId: "prop_abc123"
)Every write operation requires an idempotency key — a UUID v4, valid for 24 hours. Include it as X-Idempotency-Key in the request header. This is required for payment and key issuance operations.
let session = try await keyshare.checkIn.start(
reservationId: "RES-2026-001",
idempotencyKey: UUID().uuidString // Required — UUID v4, 24-hr validity
) // SLA: < 200ms p95Present the tap UI. The SDK manages the NFC protocol, Puck communication, and credential exchange.
let result = try await session.awaitTap()
switch result {
case .success(let credential):
// Wallet key provisioned, identity verified
print("Room \(credential.roomNumber) — key active")
case .failure(let error):
// See Error Codes in the Reference tab
handle(error)
}All errors return a consistent JSON format:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests",
"details": { "retryAfter": 60 },
"requestId": "req_abc123"
}
}This is a conceptual walkthrough. Full API reference, sandbox access, and integration engineers are available to licensed customers. Request access →
What's new
| Version | Change | |
|---|---|---|
| Wallet SDK 2.0.1 | Added EUDI credential format support to Identity module | Latest |
| Wallet SDK 2.0.0 | Initial SDK release (iOS and Android) | |
| GEP Command API v1 | REST API for property management integration | |
| Connect v1 | Cloud-to-panel integration for Mercury LP/MP series |
What's available
| Vertical | Developer Resources | Access |
|---|---|---|
| Hotel | Wallet SDK (iOS, Android), GEP Command API | SDK access included with GEP license. Request access → |
| Government | Platform REST APIs, Mobile SDKs, Reference Wallet source | Available to deployment partners. Request a briefing → |
| Physical Access | Connect API, Reader Library firmware SDK, VEP API | Available to system integrators. Request access → |
| Hardware | Puck specification and NFC protocol docs | Available under NDA. Request access → |
Wallet SDK
v2.0.1Use the Wallet SDK to add NFC tap-to-collect to your hotel guest app. The SDK handles Puck communication, credential exchange, and wallet provisioning — you control the UI and guest experience.
Platform support
| Platform | Minimum | Language | Distribution | Binary Size |
|---|---|---|---|---|
| iOS | iOS 15.0+ | Swift 5.7+ | CocoaPods, SPM | ~2 MB |
| Android | API 26+ | Kotlin 1.9+ | Maven Central | ~2.5 MB |
SDK modules
| Module | iOS | Android | Function | |
|---|---|---|---|---|
| Core | KeyShareCore | keyshare-core | API client, Puck communication, NFC session | Required |
| Wallet | KeyShareWallet | keyshare-wallet | Key provisioning to native wallet | Required |
| Identity | KeyShareIdentity | keyshare-identity | mDL/EUDI presentation, selective disclosure | Optional |
| UI | KeyShareUI | keyshare-ui | Pre-built check-in screens, tap animation | Optional |
Core + Wallet. Adding identity later means importing Identity — no refactoring.Installation
iOS — CocoaPods
# Podfile — minimum integration (key delivery)
pod 'KeyShareCore', '~> 2.0'
pod 'KeyShareWallet', '~> 2.0'
# Optional modules
pod 'KeyShareIdentity', '~> 2.0' # mDL/EUDI verification
pod 'KeyShareUI', '~> 2.0' # Pre-built check-in screensiOS — Swift Package Manager
// Package.swift
dependencies: [
.package(url: "https://github.com/keyshare/ios-sdk.git", from: "2.0.0")
]Android — Gradle
// build.gradle.kts
dependencies {
implementation("io.keyshare:core:2.0.0")
implementation("io.keyshare:wallet:2.0.0")
// Optional modules
implementation("io.keyshare:identity:2.0.0")
implementation("io.keyshare:ui:2.0.0")
}Quick start
iOS (Swift)
import KeyShareCore
import KeyShareWallet
let keyshare = KeyShareCore(
apiKey: "ks_live_...",
environment: .production
)
// Start a check-in session
let session = try await keyshare.checkIn.start(
reservationId: "RES-2026-001",
idempotencyKey: UUID().uuidString
)
// Await guest tap on Puck
let credential = try await session.awaitTap()
print("Room \(credential.roomNumber) — key active")Android (Kotlin)
import io.keyshare.core.KeyShareCore
import io.keyshare.wallet.KeyShareWallet
val keyshare = KeyShareCore.Builder()
.apiKey("ks_live_...")
.environment(Environment.PRODUCTION)
.build()
// Start a check-in session
val session = keyshare.checkIn.start(
reservationId = "RES-2026-001",
idempotencyKey = UUID.randomUUID().toString()
)
// Await guest tap on Puck
val credential = session.awaitTap()
println("Room ${credential.roomNumber} — key active")Data flow
| Step | From | To | Payload |
|---|---|---|---|
| 1 | Guest App | Puck (NFC) | Session token + credential request |
| 2 | Puck | GEP Local | Signed credential exchange |
| 3 | GEP Local | PMS | Reservation verification |
| 4 | GEP Local | Puck | Wallet key + room assignment |
| 5 | Puck (NFC) | Guest App | Provisioned credential |
Error codes
| Code | HTTP | Meaning | Resolution |
|---|---|---|---|
NFC_SESSION_TIMEOUT | — | Guest didn't tap within the timeout window | Prompt guest to re-tap |
PUCK_NOT_FOUND | — | No Puck detected in NFC range | Check Puck power/positioning |
RESERVATION_NOT_FOUND | 404 | Reservation ID invalid or expired | Verify reservation ID in PMS |
KEY_ALREADY_ISSUED | 409 | Key already provisioned for this reservation | Revoke existing key first |
RATE_LIMIT_EXCEEDED | 429 | Too many requests | Implement exponential backoff |
Integration timeline
| Scope | Modules | Timeline |
|---|---|---|
| Key delivery only | Core + Wallet | 1–2 weeks |
| Key + identity | Core + Wallet + Identity | 3–4 weeks |
| Full integration | All modules + PMS adapter | 4–8 weeks |
GEP Command API
v1Use the Command API to integrate your property management system with KeyShare. Send commands to the Guest Experience Platform — check-in, key issuance, identity verification — and get results via polling or callback.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| POST | /command | Submit a new command (check-in, key issue, ID verify) |
| GET | /command/{id} | Poll command status and result |
| POST | /command/{id}/cancel | Cancel a pending command |
| GET | /health | GEP Local health and Puck connectivity |
Design principles
Authentication
| API Layer | Auth Method | Scope |
|---|---|---|
| GEP Local | JWT (RS256) | Organization-scoped RBAC |
| GEP Cloud | JWT (RS256) | Organization-scoped RBAC |
| Command API | API Key (X-API-Key header) | Per-integration configurable scopes |
PMS adapters
| PMS | Auth | Webhooks | Rate Limit |
|---|---|---|---|
| Opera (OHIP) | OAuth2 | Limited | Property-specific |
| Mews | OAuth2 + Platform Token | Yes (2.0) | 200 req/min |
| Apaleo | OAuth2 | Yes (v2) | Rate limited |
| BookingCenter | API Key | Polling only | 60 req/min |
| Shiji | OAuth2 | Yes | 120 req/min |
| Cloudbeds | OAuth2 | Yes | 100 req/min |
Error model
All API errors use a consistent envelope. Include requestId when contacting support.
{
"error": {
"code": "COMMAND_REJECTED",
"message": "Night audit in progress — write operations paused",
"details": {
"retryAfter": 300,
"auditWindow": "02:00–02:15 UTC"
},
"requestId": "req_abc123"
}
}Digital ID Platform APIs
Use these REST APIs to integrate government systems with credential issuance, verification, and lifecycle management infrastructure. Available to deployment partners.
API surface
| API | Purpose | Authentication |
|---|---|---|
| Credential API | Issue, revoke, suspend, query credential status | Organization attestation token |
| Workflow API | Define, deploy, version, trigger issuance workflows | Organization attestation token |
| Presentation API | Request credential presentations from holders | Verifier attestation token |
| Trust API | Query trust chain, validate attestations, check governance | Platform-scoped token |
| Admin API | Ecosystem management, org onboarding, schema management | Admin token |
Credential formats supported
| Format | Standard | Use Case |
|---|---|---|
| W3C VC | VC Data Model 2.0 | General-purpose credentials |
| ISO 18013-5 (mDL) | ISO/IEC 18013-5:2021 | Mobile driver's licenses, government-issued ID |
| EUDI ARF | EU Digital Identity Architecture v1.4 | EU-wide interoperable credentials |
Integration architecture
Government Authority
│
▼
┌─────────────────────┐
│ Credential API │ ← Issue / revoke / suspend
│ Workflow API │ ← Define issuance flows
│ Trust API │ ← Validate attestation chain
└─────────────────────┘
│
▼
Holder Wallet (SDK)
│
▼
Verifier (Presentation API)Government Mobile SDKs
Use these SDKs to build holder wallets and verifier apps for sovereign digital identity ecosystems. The SDKs handle credential storage, selective disclosure, and NFC/QR presentation.
SDK modules
| Module | iOS | Android | Function |
|---|---|---|---|
| Core | GovIDCore | govid-core | Credential storage, cryptographic operations |
| Presentation | GovIDPresent | govid-present | Selective disclosure, NFC/QR presentation |
| Issuance | GovIDIssue | govid-issue | Credential issuance flow, authority binding |
| Biometric | GovIDBio | govid-bio | Face matching, liveness detection (on-device) |
Connect & Reader Library
Use Connect to link your access control panel to the KeyShare cloud. Use the Reader Library to build NFC readers that accept KeyShare credentials. Both follow OSDP v2.2.
Integration architecture
KeyShare Cloud
│
▼ (Connect API — REST + WebSocket)
┌─────────────────┐
│ Access Panel │ ← Mercury LP/MP series
│ (OSDP v2.2) │
└─────────────────┘
│
▼ (Wiegand / OSDP)
┌─────────────────┐
│ NFC Reader │ ← Reader Library firmware
│ (ARM Cortex) │
└─────────────────┘
│
▼ (NFC)
Guest Phone / PuckConnect API
| Feature | Detail |
|---|---|
| Protocol | REST + WebSocket (real-time events) |
| Authentication | mTLS + API Key |
| Supported Panels | Mercury LP/MP series, HID VertX |
| Credential Types | Mobile key, mDL, employee badge |
| Offline Mode | 72-hour manifest cache |
Reader Library
| Feature | Detail |
|---|---|
| Target | ARM Cortex-M4+ (128KB+ RAM) |
| Language | C (MISRA C:2012 compliant) |
| NFC Stack | ISO 14443-A/B, ISO 18013-5 |
| Crypto | wolfSSL (FIPS 140-2) |
| Communication | OSDP v2.2 (encrypted) |
Communication protocols
| Layer | Protocol | Direction |
|---|---|---|
| Cloud ↔ Panel | REST + WebSocket (TLS 1.3) | Bidirectional |
| Panel ↔ Reader | OSDP v2.2 (AES-128) | Bidirectional |
| Reader ↔ Phone | NFC (ISO 14443) | Reader-initiated |
Performance targets
| Metric | Target |
|---|---|
| NFC tap-to-unlock | < 500ms |
| Cloud credential sync | < 2s |
| Offline credential validation | < 100ms |
| Reader boot time | < 3s |
Puck Specification
The Puck is the NFC hardware device at the center of every KeyShare deployment. It connects to GEP Local via USB and communicates with guest phones via NFC.
Public specifications
| Property | Value |
|---|---|
| Interface | NFC + QR (dual) |
| Secure Element | CC EAL5+ (ATECC608B) |
| Crypto Library | wolfSSL (FIPS 140-2) |
| Identity Standards | ISO 18013-5, EUDI ARF |
| Mobile Compatibility | iOS 16+ / Android 11+ |
| Battery Backup | 30+ min (1500mAh Li-Po) |
| Patents | 4 US patents granted |
Deployment connectivity
Guest Phone (NFC)
↓
KeyShare Puck — no WiFi, no Bluetooth, no Ethernet. NFC + USB only.
↓ USB (power + data)
GEP Local (on-premises server)
↓ TLS 1.3
KeyShare Cloud (optional sync)SLA targets
| Metric | Target |
|---|---|
| NFC response time | < 300ms |
| Uptime (with USB power) | 99.9% |
| Firmware OTA update | < 60s |
| Mean time between failures | > 50,000 hours |
Standards & Security
KeyShare products are built on open standards and audited security practices.
Standards compliance
| Standard | Scope |
|---|---|
| ISO 18013-5 | Identity verification (mDL) — Puck, SDKs, Platform APIs |
| W3C Verifiable Credentials | Credential format — Government Platform, Digital ID SDKs |
| OSDP v2.2 | Reader communication — Reader Library, Connect |
| FIDO2 | Authentication — Platform services |
| FIPS 140-2 | Cryptographic operations (wolfSSL) — Puck |
| MISRA C:2012 | Firmware coding standard — Reader Library |
Security highlights
Rate Limits
All API endpoints are rate-limited using a Redis-backed sliding window algorithm. Limits vary by endpoint category and authentication method.
General API rate limits
| Category | User Limit | API Key Limit | Burst |
|---|---|---|---|
| Authentication | 10/min | N/A | 3 |
| Read Operations | 100/min | 1000/min | 20 |
| Write Operations | 30/min | 300/min | 5 |
| Bulk Operations | 5/min | 50/min | 1 |
| Search/Query | 20/min | 200/min | 5 |
| Export | 2/min | 10/min | 1 |
SDK endpoint limits
| Endpoint | Limit | Window |
|---|---|---|
/check-in/start | 30/min | Per API key |
/identity/verify | 50/min | Per API key |
/keys/provision | 100/min | Per API key |
/profiles/* | 100/min | Per API key |
Rate limit headers
Every API response includes rate limit headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the current window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Retry-After | Seconds to wait before retrying (only on 429 responses) |
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711497600
Retry-After: 45
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded for write operations",
"details": { "retryAfter": 45 }
}
}CORS Policy
Cross-Origin Resource Sharing configuration for browser-based API integrations.
| Setting | Value |
|---|---|
| Allowed Origins | Configured per property (allowlist) |
| Allowed Methods | GET, POST, PUT, DELETE, OPTIONS |
| Allowed Headers | Authorization, Content-Type, X-Request-ID, X-Idempotency-Key |
| Credentials | true |
| Max Age | 86400 (24 hours) |
Authentication & API Key Lifecycle
Auth model, token types, and key rotation procedures.
Auth model
| API | Method | Token Format |
|---|---|---|
| GEP Local / Cloud | JWT (RS256) | Organization-scoped RBAC claims |
| Command API | API Key | X-API-Key header |
| Platform APIs | Attestation token | Organization / Verifier / Admin scopes |
API key rotation procedure
curl -X POST https://{property}.keyshare.io/gep/command/v1/command \
-H "X-API-Key: ks_live_abc123def456" \
-H "X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{"type": "CHECK_IN", "reservationId": "RES-2026-001"}'Troubleshooting
Common integration issues, their root causes, and resolutions.
| Scenario | Behavior | Resolution |
|---|---|---|
| Authentication lockout | Progressive lockout: 3 failures → 1 min, 5 → 15 min, 10 → 1 hr, 15 → 24 hr, 20+ → permanent | Wait for lockout expiry. Contact support for permanent lockout reset. |
| 429 Too Many Requests | Retry-After header returned with seconds to wait | Implement exponential backoff. Check X-RateLimit-Remaining header proactively. |
| Session fixation detected | Session immediately invalidated; new authentication required | Re-authenticate with fresh credentials. Do not reuse session tokens across contexts. |
| Night audit write rejection | Write operations blocked during nightly PMS reconciliation (typically 02:00–02:15 UTC) | Queue writes and retry after the audit window. Error includes auditWindow field. |
| Middleware timeout | PMS adapter timeout (>2 seconds) logged; system falls back to direct adapter | Check PMS connectivity. The adapter will auto-recover when the PMS responds. |
| Webhook delivery failure | Messages enter dead letter queue. Alert triggered after 3 consecutive failures. | Verify endpoint availability. Messages are retained in DLQ for manual replay. |
Get Access
Developer resources — SDK packages, API docs, sandbox environments, and Puck simulators — are available to licensed customers, deployment partners, and qualified evaluators.