Schlage Home API

REST + webhook API for the Schlage Home residential smart-lock platform. Designed for business and commercial integrations (partner apps, smart-home automation platforms) that scale across residential deployments of WiFi-enabled Schlage Encode, Encode Plus, and Encode Lever devices. Uses OAuth 2.0 Authorization Code flow against account.schlage.com, async 202 ACCEPTED command pattern, and webhook subscriptions for device, command, access code, and account events.

Schlage Home API is one of 2 APIs that Allegion publishes on the APIs.io network, described by a machine-readable OpenAPI specification.

This API exposes 3 machine-runnable capabilities that can be deployed as REST, MCP, or Agent Skill surfaces via Naftiko and 4 JSON Schema definitions.

Tagged areas include Smart Lock, Residential, WiFi, OAuth, and Webhooks. The published artifact set on APIs.io includes API documentation, a getting-started guide, best-practice docs, a quickstart, an engineering blog, authentication docs, 3 Naftiko capability specs, and 4 JSON Schemas.

Documentation

Specifications

Examples

Schemas & Data

Other Resources

OpenAPI Specification

schlage-home-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Schlage Home API
  version: '2.0'
  description: |
    Schlage Home API V2 - REST + webhook API for the Schlage Home residential
    smart-lock platform (Schlage Encode, Encode Plus, Encode Lever).

    Designed for business and commercial integrations (partner apps, smart-home
    automation platforms) that scale across residential deployments. Uses OAuth 2.0
    Authorization Code flow against account.schlage.com. Device management commands
    are asynchronous (202 ACCEPTED), with downstream device state surfaced via
    webhook events.

    Generated from public documentation at https://developer.allegion.com/en/products/schlage-home
    (Getting Started, Schlage Home API V2, Best Practices, Access Codes, Release Notes,
    Blog). Path naming and shapes are inferred where docs describe semantics but do
    not publish a verbatim endpoint catalogue.
  contact:
    name: Allegion Developer Support
    url: https://developersupport.allegion.com/hc/en-us
  termsOfService: https://developer.allegion.com/en/index.html
  license:
    name: Allegion Developer Terms
    url: https://developer.allegion.com/en/index.html
servers:
  - url: https://api.allegion.com/schlage-home
    description: Production
  - url: https://api.allegion.com/schlage-home/v2
    description: Production (v2 path prefix)
tags:
  - name: Devices
    description: Manage and read Schlage Home WiFi-enabled smart locks
  - name: Access Codes
    description: Create, schedule, update, and delete numeric access codes per device
  - name: Commands
    description: Track the asynchronous status of lock / unlock and configuration commands
  - name: Webhook Subscriptions
    description: Subscribe partner endpoints to device, command, access code, and account events
security:
  - OAuth2: []
paths:
  /devices:
    get:
      tags: [Devices]
      summary: List Devices
      description: Returns the WiFi-enabled Schlage Home devices the authenticated user account has authorized for this integration.
      operationId: listDevices
      responses:
        '200':
          description: Devices returned
          content:
            application/json:
              schema:
                type: object
                properties:
                  devices:
                    type: array
                    items:
                      $ref: '#/components/schemas/Device'
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /devices/{deviceId}:
    get:
      tags: [Devices]
      summary: Get Device
      description: Returns a single device including lock state, battery level, WiFi signal strength, firmware, and connectivity state.
      operationId: getDevice
      parameters:
        - $ref: '#/components/parameters/DeviceId'
      responses:
        '200':
          description: Device returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Device'
        '401': { $ref: '#/components/responses/Unauthorized' }
        '404': { $ref: '#/components/responses/NotFound' }
    put:
      tags: [Devices]
      summary: Update Device
      description: Update device configuration (name, default lock timer, vacation mode). Returns 202 ACCEPTED and emits a command that completes asynchronously.
      operationId: updateDevice
      parameters:
        - $ref: '#/components/parameters/DeviceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeviceUpdate'
      responses:
        '202': { $ref: '#/components/responses/CommandAccepted' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '404': { $ref: '#/components/responses/NotFound' }
  /devices/{deviceId}/lock:
    post:
      tags: [Devices]
      summary: Lock Device
      description: Issue an asynchronous lock command. Returns 202 ACCEPTED with a command id; final state surfaces via webhook.
      operationId: lockDevice
      parameters:
        - $ref: '#/components/parameters/DeviceId'
      responses:
        '202': { $ref: '#/components/responses/CommandAccepted' }
  /devices/{deviceId}/unlock:
    post:
      tags: [Devices]
      summary: Unlock Device
      description: Issue an asynchronous unlock command. Returns 202 ACCEPTED with a command id; final state surfaces via webhook.
      operationId: unlockDevice
      parameters:
        - $ref: '#/components/parameters/DeviceId'
      responses:
        '202': { $ref: '#/components/responses/CommandAccepted' }
  /devices/{deviceId}/access-codes:
    get:
      tags: [Access Codes]
      summary: List Access Codes
      description: List access codes currently stored on the device.
      operationId: listAccessCodes
      parameters:
        - $ref: '#/components/parameters/DeviceId'
      responses:
        '200':
          description: Access codes returned
          content:
            application/json:
              schema:
                type: object
                properties:
                  accessCodes:
                    type: array
                    items:
                      $ref: '#/components/schemas/AccessCode'
    post:
      tags: [Access Codes]
      summary: Create Access Code
      description: Create a numeric access code on the device with an Always, Temporary, or Recurring schedule. Returns 202 ACCEPTED.
      operationId: createAccessCode
      parameters:
        - $ref: '#/components/parameters/DeviceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AccessCodeCreate'
      responses:
        '202': { $ref: '#/components/responses/CommandAccepted' }
  /devices/{deviceId}/access-codes/{accessCodeId}:
    get:
      tags: [Access Codes]
      summary: Get Access Code
      operationId: getAccessCode
      parameters:
        - $ref: '#/components/parameters/DeviceId'
        - $ref: '#/components/parameters/AccessCodeId'
      responses:
        '200':
          description: Access code returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccessCode'
    put:
      tags: [Access Codes]
      summary: Update Access Code
      description: Update an access code name or schedule. The numeric code itself is not changed by name updates.
      operationId: updateAccessCode
      parameters:
        - $ref: '#/components/parameters/DeviceId'
        - $ref: '#/components/parameters/AccessCodeId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AccessCodeUpdate'
      responses:
        '202': { $ref: '#/components/responses/CommandAccepted' }
    delete:
      tags: [Access Codes]
      summary: Delete Access Code
      operationId: deleteAccessCode
      parameters:
        - $ref: '#/components/parameters/DeviceId'
        - $ref: '#/components/parameters/AccessCodeId'
      responses:
        '202': { $ref: '#/components/responses/CommandAccepted' }
  /devices/{deviceId}/commands/{commandId}:
    get:
      tags: [Commands]
      summary: Get Command Status
      description: Retrieve the current status of a previously issued device command. Error messages are populated on failure.
      operationId: getCommand
      parameters:
        - $ref: '#/components/parameters/DeviceId'
        - in: path
          name: commandId
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Command status returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Command'
  /webhooks/subscriptions:
    get:
      tags: [Webhook Subscriptions]
      summary: List Webhook Subscriptions
      operationId: listWebhookSubscriptions
      responses:
        '200':
          description: Subscriptions returned
          content:
            application/json:
              schema:
                type: object
                properties:
                  subscriptions:
                    type: array
                    items:
                      $ref: '#/components/schemas/WebhookSubscription'
    post:
      tags: [Webhook Subscriptions]
      summary: Create Webhook Subscription
      description: |
        Register an HTTPS callback URL for one or more event types. On subscription
        creation an OPTIONS validation request is sent to the URL and must receive
        a 2xx response within 30 seconds or the subscription is not created.
      operationId: createWebhookSubscription
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookSubscriptionCreate'
      responses:
        '201':
          description: Subscription created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscription'
        '400': { $ref: '#/components/responses/BadRequest' }
  /webhooks/subscriptions/{subscriptionId}:
    get:
      tags: [Webhook Subscriptions]
      summary: Get Webhook Subscription
      operationId: getWebhookSubscription
      parameters:
        - in: path
          name: subscriptionId
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Subscription returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookSubscription'
    delete:
      tags: [Webhook Subscriptions]
      summary: Delete Webhook Subscription
      operationId: deleteWebhookSubscription
      parameters:
        - in: path
          name: subscriptionId
          required: true
          schema: { type: string }
      responses:
        '204':
          description: Subscription deleted
components:
  securitySchemes:
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://account.schlage.com/OAuth2/authorize
          tokenUrl: https://account.schlage.com/OAuth2/token
          scopes:
            devices.read: Read device state, battery, connectivity, and firmware
            devices.write: Issue lock, unlock, and configuration commands
            access_codes.read: Read access codes stored on devices
            access_codes.write: Create, update, and delete access codes
            webhooks.manage: Create, list, and delete webhook subscriptions
  parameters:
    DeviceId:
      in: path
      name: deviceId
      required: true
      schema: { type: string }
      description: Unique identifier for a Schlage Home device.
    AccessCodeId:
      in: path
      name: accessCodeId
      required: true
      schema: { type: string }
      description: Unique identifier for an access code on a specific device.
  responses:
    Unauthorized:
      description: Access token missing, expired, or insufficient scope.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    BadRequest:
      description: Request validation failed.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    RateLimited:
      description: Rate limit exceeded.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    CommandAccepted:
      description: |
        Asynchronous command accepted. The response includes a commandId that can
        be polled at GET /devices/{deviceId}/commands/{commandId} or watched for
        via the corresponding command-status webhook event.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Command' }
  schemas:
    Device:
      type: object
      properties:
        deviceId: { type: string }
        name: { type: string }
        model:
          type: string
          enum: [BE489WB, BE499WB, FE789WB]
          description: Schlage Encode Deadbolt, Encode Plus, or Encode Lever
        firmwareVersion: { type: string }
        batteryLevel:
          type: integer
          minimum: 0
          maximum: 100
        wifiSignalStrength:
          type: integer
          description: WiFi RSSI in dBm (added March 6, 2025).
        connectivityState:
          type: string
          enum: [Online, Offline]
        lockState:
          type: string
          enum: [Locked, Unlocked, Unknown]
        timeZone: { type: string }
    DeviceUpdate:
      type: object
      properties:
        name: { type: string }
        autoLockDelaySeconds: { type: integer }
        vacationMode: { type: boolean }
    AccessCode:
      type: object
      properties:
        accessCodeId: { type: string }
        name:
          type: string
          minLength: 1
          maxLength: 12
          pattern: '^[a-zA-Z0-9]+$'
          description: 1-12 character alpha-numeric label. Updating the name does not change the numeric code.
        code:
          type: string
          description: Numeric access code (length is per-device, changed by deleting all codes).
        schedule:
          $ref: '#/components/schemas/Schedule'
        accessorType:
          type: string
          description: Accessor classification (Owner, Guest, etc.). New accessor types added March 25, 2025.
    AccessCodeCreate:
      allOf:
        - $ref: '#/components/schemas/AccessCode'
      required: [name, code]
    AccessCodeUpdate:
      type: object
      properties:
        name: { type: string, maxLength: 12 }
        schedule: { $ref: '#/components/schemas/Schedule' }
    Schedule:
      oneOf:
        - $ref: '#/components/schemas/AlwaysSchedule'
        - $ref: '#/components/schemas/TemporarySchedule'
        - $ref: '#/components/schemas/RecurringSchedule'
      discriminator:
        propertyName: type
        mapping:
          Always: '#/components/schemas/AlwaysSchedule'
          Temporary: '#/components/schemas/TemporarySchedule'
          Recurring: '#/components/schemas/RecurringSchedule'
    AlwaysSchedule:
      type: object
      properties:
        type: { type: string, enum: [Always] }
    TemporarySchedule:
      type: object
      properties:
        type: { type: string, enum: [Temporary] }
        startDateTime:
          type: string
          format: date-time
          description: Includes DST offset since April 14, 2026.
        endDateTime:
          type: string
          format: date-time
          description: Includes DST offset since April 14, 2026.
    RecurringSchedule:
      type: object
      properties:
        type: { type: string, enum: [Recurring] }
        daysOfWeek:
          type: array
          items:
            type: string
            enum: [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]
        startTime: { type: string, example: '08:00' }
        endTime: { type: string, example: '17:00' }
    Command:
      type: object
      properties:
        commandId: { type: string }
        deviceId: { type: string }
        type:
          type: string
          enum: [Lock, Unlock, UpdateDevice, CreateAccessCode, UpdateAccessCode, DeleteAccessCode]
        status:
          type: string
          enum: [Pending, InProgress, Completed, Failed]
        errorMessage:
          type: string
          description: Populated when status is Failed (improved March 6, 2025).
        createdAt: { type: string, format: date-time }
        completedAt: { type: string, format: date-time }
    WebhookSubscription:
      type: object
      properties:
        subscriptionId: { type: string }
        url:
          type: string
          format: uri
          description: HTTPS-only callback URL.
        eventTypes:
          type: array
          items:
            type: string
            enum:
              - DeviceLockStateChanged
              - DeviceConnectivityStateChanged
              - DeviceBatteryLevelChanged
              - DeviceKeypadLockedOut
              - DeviceAlarmTriggered
              - AccessCodeCreated
              - AccessCodeUpdated
              - AccessCodeDeleted
              - AccessCodeUsed
              - InvalidAccessCodeAttempted
              - AccessCodeSynchronized
              - CommandStatusUpdated
              - UserSignedOut
              - IntegrationManagementUpdated
        signingPublicKey:
          type: string
          description: Public key used to verify webhook signatures.
        createdAt: { type: string, format: date-time }
    WebhookSubscriptionCreate:
      type: object
      required: [url, eventTypes]
      properties:
        url: { type: string, format: uri }
        eventTypes:
          type: array
          items: { type: string }
    Error:
      type: object
      properties:
        code: { type: string }
        message: { type: string }
        details: { type: string }