Remote PIN Management#
These endpoints are for managing keypad PIN codes via the API.
Check Lock Type#
GET /locks/:lockID
You'll want to look at the Type field. Type 1 locks are the original Yale Home Smart Locks, and they can only handle accessType: "always". Newer Type locks (like Type: 2) can accept recurring and temporary PINs.
Request Valid PIN#
GET /locks/:lockID/pin
This will generate and reserve a randomly-generated PIN for you. It will be reserved for several minutes (currently 3 minutes). You may call this several times to generate and reserve several PINs. No more than 240 PINs can be set or reserved for a specific lock.
PIN:User is 1:1
For each lock, the relationship of PIN:User is 1:1. That is, you cannot assign the same PIN to two different users on the same lock.
HTTP 409 Error#
Attempts to set the same PIN for a second user will result in an HTTP 409 error. Similarly, if you try to set a "new" pin for a user that already has a PIN, you will also see an HTTP 409 error.
Changing a User's PIN#
To change a user's PIN you must first delete their current PIN and then load the new PIN. Do this in two separate transactions, waiting for the first transaction to complete, to avoid race conditions in the database. We consider this potential race condition to be a bug (internal ID PART-615) but it will be complex to fix and we do not have an ETA yet. Race conditions will lead to Unable to set intent state for pin errors.
Setting New PINs via the REST API#
POST /locks/:lockID/pins
This endpoint takes an array of commands so that you can configure multiple PINs on the same lock at the same time. The commands will be run in the order they appear in the array of commands. For example, if one of your users already has a PIN and you want to update or change the PIN, you must first delete it (including an userID) and then load it again. You can do this in the same POST call with two commands in the same array.
It is cleaner if you do not provide an userID to load a PIN because then the API will automatically create an unverified user ID. Unverified users are a special class of users just for PIN access. They do not get invited to use the Yale Home app and cannot use their phones to operate the lock. Yale Home does not verify the email addresses or phone numbers of unverified users. You can use this id any place we request an userID and our servers will know the type of user.
If you do provide an userID in a command, then the API will try to match
the id to all registered Yale Home users. If there is a match, the API will assign
the PIN to that existing user. If they already have a PIN set on that lock,
you'll get an HTTP 409 error. If the PIN is set successfully and that user has
the Yale Home Application, they will see the PIN. If the user is not a verified
Yale Home user, then they will not receive any indication of the PIN -- in that
case, communicating the PIN is up to you.
For registered users (those using the Yale Home app), Yale Home has verified the
phone number and email address, so we know they are all real. Please do not
generate a "fake" telephone number or email address because you run the risk
that a real Yale Home user will see the PIN in the Yale Home application. If you need
a real Yale Home user UUID then you can get it from the list of PINs. We hope in
the future to be able to offer delete with the partnerUserID but that is not
ready yet, so you must use the Yale Home user UUID associated with the PIN code.
POST /locks/:LockID/pins Payload Example#
userID No Longer Required
userID is no longer required!
You can load and delete using the partnerUserID.
If you provide the userID, ensure that it is a
valid Yale Home user UUID or a real phone number or email address.
{
"commands: [{
"partnerUserID": "uid", /* string: REQUIRED user id which will be used to report upon completion of each pin command */
"pin": "pin", /* string: REQUIRED to load a valid pin, 4-6 digits, ideally obtained with GET locks/:LockID/pin to avoid failures */
"action": "action", /* string: REQUIRED load, delete, disable, enable */
"accessType": "type" /* string: REQUIRED the type of the pin: always, recurring, temporary, onetime */
"userID": "Yale HomeID", /* string: OPTIONAL if partnerUserID provided, either a phone number (tel:...) or an Yale Home internal ID */
"firstName": "firstName", /* string: OPTIONAL the firstName of the user, shows up in lock owner's Yale Home App */
"lastName": "lastName", /* string: OPTIONAL the lastName of the user, shows up in lock owner's Yale Home App */
"accessTimes": "accessTime" /* string: REQUIRED for accessType recurring and temporary. See examples below */
"accessRecurrence": "recurrence" /* string: REQUIRED for access type recurring. See examples below. */
"retry": true | false /* boolean: OPTIONAL if true and the PIN operation fails, the API will retry the PIN operation. Defaults to false. */
}],
"webhook": "url"
}
// Example accessTimes:
// For recurring access type possible values are:
"STARTSEC=<sec from start of day>[;ENDSEC=<sec from start of day>]";
// If timezone of lock is known this is also valid:
"DTSTART=<ISO date in UTC>[;DTEND=<ISO date in UTC>]"
// (end date optional, if not provided is set to 1 hour from start date).
// For temporary times must be ISO date in UTC.
onetime PINs
Locks that contain a "Connected by Yale Home" module (Yale, Emtek, etc.) do not support onetime PINs.
While there is not restriction on getting creating the PIN, we strongly
suggest to call GET /locks/:lockID/pin to receive a PIN without collision.
PINs are unique per lock and per user. Those GET /pins are set aside currently
for 3 minutes. Since we are doing batch processing we are considering to
increase this for partners.
Upon receiving the payload, after the server makes it's usual lock existence and lock ownership checks, it will check for the validity of the payload.
Examples of checks on the payload:
- if the
userIDis a phone number then it must be specified according to RFC3966 (thetelURI for Telephone Numbers). - that each input goes through a format and value validation.
- that for a
temporary-type theaccessTimesfield is provided and valid (we usejsicalto parse). - that for a
recurringtype theaccessTimesandaccessRecurrentare provided and valid. - that the
webhookurl is valid andhttps.- The callbacks will be executed over
https, - the certificate should be valid.
- The callbacks will be executed over
- if a time-based rule is specified and the lock is an ASL-1 lock (first generation) then we will reject the rule because this lock cannot track time well.
tel: versus phone:
Some places in the Yale Home APIs we use tel: for the phone number
identifier, and other places we use phone:. The docs should say which to
use (as tel: above), but if they don't, please let us know and we will
update the docs.
load Examples#
Note that the partnerUserID is a string you define. It must be unique to this
user and must not be reused for any other users by your company. (Internally we
are namespacing these by your OAuth clientID.)
{
"commands": [
{
"partnerUserID": "PINTESTALWAYS",
"firstName": "Test",
"lastName": "PINTOOLA",
"pin": "2358",
"action": "load",
"accessType": "always"
},
{
"partnerUserID": "PINTESTRECUR",
"firstName": "Test",
"lastName": "PINTOOLR",
"pin": "2359",
"action": "load",
"accessType": "recurring",
// This example starts at 1am and ends at 2am in the lock's time zone.
"accessTimes": "STARTSEC=3600;ENDSEC=7200",
"accessRecurrence": "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR"
},
{
"partnerUserID": "PINTESTTEMP",
"firstName": "Test",
"lastName": "PINTOOLT",
"pin": "2360",
"action": "load",
"accessType": "temporary",
// This example starts at midnight on May 24 GMT and ends at the end of the day.
"accessTimes": "DTSTART=2017-05-24T00:00:00.000Z;DTEND=2017-05-24T23:59:59.000Z"
}
],
"webhook": "$WEBHOOK"
}
delete Examples#
Note that the partnerUserID and accessType fields match the fields used in
the load Examples above.
!!! Note "pin" should be required
{
"commands": [
{
"partnerUserID": "PINTESTALWAYS",
"action": "delete",
"accessType": "always",
"pin": "2358"
},
{
"partnerUserID": "PINTESTRECUR",
"action": "delete",
"accessType": "recurring",
"pin": "2359"
},
{
"partnerUserID": "PINTESTTEMP",
"action": "delete",
"accessType": "temporary",
"pin": "2360"
}
],
"webhook": "$WEBHOOK"
}
Response#
Success#
If all is valid the system will respond with a 202 code, and the following payload:
Response Payload#
{
status: 'success',
transactionID: tid, /*string: a uuid */
completionTime: cts, /*integer: an approximate completion time in seconds - optional*/
}
Keep the transactionID
That transactionID is important! The asynchronous callbacks and final
digest will all refer to that ID so that you know which request caused the
callbacks.
Failure and Error Codes#
- 401 If the user is not allowed to perform the operation
- 404 If the lock doesn't exist
- 409 If the payload doesn't validate:
- duplicate PIN code,
- user already has a PIN code,
- payload validation includes checking that the type of lock can handle the access rules requested, e.g. ASL1 can't handle recurring rules but ASL2 can.
- trying to set a
onetimePIN on a "Connected by Yale Home" lock from Yale, Emtek, etc. - trying to set a PIN on a lock with unavailable slots
- 500 if there is some sort of internal error
Processing#
POST :webhook
Successes and failures#
Successes and failures are reported via the webhook, asynchronously.
Yale Home processes each PIN request in the commands array separately and in
order. If during any of the internal steps to fulfill a command fails, then
Yale Home will call the partner-specified webhook with an error code and a
message specifying the error.
The webhook will be called only once for a successful command.
When all the transactions have been completed with or without failures, the system will call back the webhook with a digest.
Success Payload#
{
"step": "commit",
"status": "success",
"transactionID": transactionID, /* the transaction id generated by the system */
"partnerUserID": partnerUserID, /* the partner provided user identifier */
"action": action, /* the action you provided when calling the endpoint */
"pin": pin, /* the pin that failed */
"completedDateTime": completedDateTime, /* Date time in ISO 8601 format */
"syncType": "credential",
}
Conflict Payload#
{
"status": "conflict",
"transactionID": transactionID, /* the transaction id generated by the system */
"partnerUserID": partnerUserID, /* the partner provided user identifier */
"action": action, /* the action you provided when calling the endpoint */
"pin": pin, /* the pin that failed */
"syncType": "credential",
"completedDateTime": completedDateTime, /* Date time in ISO 8601 format */
"error": error, /* the HTTP status code returned by our internal PIN processing service, which will be in the 400-599 range */
"errorName": errorName /* the name of the error */,
"errorMessage": /* A human readable message explaining the nature of the conflict error */
}
Failure Payload#
{
"status": "failure",
"transactionID": transactionID, /* the transaction id generated by the system */
"partnerUserID": partnerUserID, /* the partner provided user identifier */
"action": action, /* the action you provided when calling the endpoint `POST /"locks"/:lockID/pins` endpoint */
"pin": pin, /* the pin that failed */
"syncType": "credential",
"completedDateTime": completedDateTime, /* Date time in ISO 8601 format */
"error": error, /* the HTTP status code returned by our internal PIN processing service, which will be in the 400-599 range */
"errorName": errorName /* the name of the error */,
"errorMessage": errorMessage /* A human readable message explaining the nature of the conflict error */
}
Digest#
When Yale Home has completed processing of all your PIN requests from your original POST /locks/:lockID/pins, we will send you a digest.
The processor retrieves all the records from your transaction and creates a response object of the following format:
Final Response#
{
"step": "digest",
"message": message, /* PinSyncFail on failure, PinSyncComplete on success */
"transactionID": transactionID,
"callingUserID": callingUserID, /* ID of the user who called the `POST /locks/:lockID/pins` endpoint. */
"digest": {
"success": [{
"partnerUserID": partnerUserID, /* the partner provided user identifier */
"commitDate": commitDate, /* Date time in ISO 8601 format */
"action": action, /* the action you provided when calling the endpoint */
"pin": pin
}],
"conflict": [{
"state": "commitFailed",
"action": action, /* the action you provided when calling the endpoint */
"partnerUserID": partnerUserID, /* the partner provided user identifier */
"reason": reason, /* A human readable message explaining the nature of the conflict error */
"error": error, /* the HTTP status code returned by our internal PIN processing service, which will be in the 400-599 range */
"errorType": "rbs",
"errorName": errorName /* the name of the error */
}],
"error": [{
"state": "commitFailed",
"action": action, /* the action you provided when calling the endpoint */
"partnerUserID": partnerUserID, /* the partner provided user identifier */
"reason": reason, /* A human readable message explaining the nature of the conflict error */
"error": error, /* the HTTP status code returned by our internal PIN processing service, which will be in the 400-599 range */
"errorType": "rbs",
"errorName": errorName /* the name of the error */,
}]
},
"commandsProcessed": numCommands, /* The number of PINs that the API tried to process */
"requestTime": requestTime, /* Epoch timestamp */
"completionTime": completionTime /* Epoch timestamp */
}
Recurring PINs#
Recurring PINs have only one recurrence pattern: weekly. That is, whatever times and dates you give access will repeat each week.
Generating Rules
Try out the rrule.js demo to generate
weekly rules. We use this library internally for parsing the
accessRecurrence string. Note that accessRecurrence tells us when to
apply accessTimes.
Example recurring payload.#
Here is what you might set if you wanted to allow your guitar teacher in to your house on every Tuesday and Thursdays any time between 9am and 2pm:
{
"commands": [
{
"partnerUserID": "teacherIDxyz",
"firstName": "Guitar",
"lastName": "Hero",
"pin": "12345",
"action": "load",
"accessType": "recurring",
"accessTimes": "STARTSEC=32400;ENDSEC=50400",
"accessRecurrence": "FREQ=WEEKLY;BYDAY=TU,TH"
}
],
"webhook": "https://example.com/callback/1jzsz7e1"
}
Example temporary payload#
Here is what you would use to give Santa Claus access on Christmas Eve 9pm to 3am Christmas Day:
{
"commands": [
{
"partnerUserID": "HoHoHo",
"firstName": "Santa",
"lastName": "Claus",
"pin": "122425",
"action": "load",
"accessType": "temporary",
"accessTimes": "DTSTART=2016-12-25T05:00:00.000Z;DTEND=2016-12-25T11:00:00.000Z"
}
],
"webhook": "https://example.com/callback/1jzsz7e1"
}
Lock Time Zones
This example assumes that the lock timezone has been set to PST. The lock time zone gets set by the Yale Home app during setup, based on the timezone of the phone at that moment.
Enable MultiCredentials:#
Here is a function to enable multiCredentials for an user to operate a lock such as: pin, finger. When running delete command and multiCredentials option is enabled, you probably shoud delete multiCredential setting as well.