Exchange a code for a key
POST/api/v1/device-auth/token
- Access
- No key
Exchange a connection code for the app’s API key
No authentication: the code and the PKCE verifier are the proof. Once per code, within 5 minutes of approval, while the account keeps the access revision it had then. Issues a key with the client's scopes (windows: account:read and content:write) for 365 days, named «lacuna для Windows · {device}», and revokes the previous working key of the same client and device of the account. A second exchange of a used code is refused, and with the right verifier it also revokes the key that code issued (a lost answer: connect again). At most 20 exchanges per client address per 10 minutes.
Example request
curl -X POST "https://lac.pics/api/v1/device-auth/token" \
-H "Content-Type: application/json" \
-d '{
"code": "Qm3xT7kP9wZ2vL5nR8cB1dF4gH6jK0sA3eY7uI2oM5q",
"verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
}'Request body
application/jsonrequired
codestringrequiredrequest onlyThe one-time code from the address back into the app.
pattern
^[A-Za-z0-9_-]{43}$verifierstringrequiredrequest onlyThe PKCE verifier whose S256 challenge was approved.
pattern
^[A-Za-z0-9_-]{43,128}$
Responses
200Connected; store the token
DeviceAuthTokentokenstringrequiredresponse onlyA Bearer API key, returned once. Keep it like the key form’s tokens (Windows Credential Manager); never in a URL or a log.
pattern
^lac_api_[A-Za-z0-9_-]{43}$keyApiCredentialrequiredApiCredential6 fieldsidstringrequiredThe file or note id.
namestringrequiredKeys of a connection are named «lacuna для Windows · {deviceName}».
length 1–100
scopesarray of stringrequiredvalues:
"content:read""content:write""content:delete""account:read"1–4 items · unique
expiresAtstring · date-timerequiredAfter this moment every request answers 401 API_KEY_EXPIRED; connect again. A connection key lives 365 days and renews itself within 30 days of its end (POST /device-auth/renew).
clientstringrequiredor nullApp of a key issued by a connection; null for keys made in the key form.
values:
"windows"deviceNamestringrequiredor nullNull for keys made in the key form.
length 1–128
userobjectrequired1 field
usernamestringrequired
- 400DEVICE_AUTH_INVALID for every unusable request alike: unknown, used or expired code, wrong verifier, changed account, malformed or extra fields. INVALID_JSON for a body that is not JSON. Start connecting again.DEVICE_AUTH_INVALIDINVALID_JSON
- 413JSON body exceeds 1 MB before authentication; upload and quota limits may also refuse this operation.
- 500Unexpected failure; the code may have been used. Connect again.
- 503The required rate-limit service is unavailable; access fails closed.
Example response
{
"token": "lac_api_NEW_KEY_SHOWN_ONCE",
"key": {
"id": "cmf8a1x2k0001q7lh5b2n8r6t",
"name": "Upload script",
"scopes": [
"content:write"
],
"expiresAt": "2026-12-26T09:30:00.000Z",
"client": null,
"deviceName": null
},
"user": {
"username": "alex"
}
}Error codes
| Code | Status | Message |
|---|---|---|
DEVICE_AUTH_INVALID | 400 | The connection code is invalid or has expired. Start connecting again in the app. |
INVALID_JSON | 400 | The request contains invalid JSON. |
RATE_LIMITED | 429 | Too many requests. Try again later. |