{
  "$type": "com.atproto.lexicon.schema",
  "defs": {
    "main": {
      "description": "Begin a device-pairing flow (OAuth 2.0 device-authorization style). Returns a `deviceId` plus a short human-typable `userCode` and the `verificationUri` where a signed-in user approves the pairing. The caller then polls `dev.cocore.devicePair.poll` until approval. The optional input lets an application (rather than a provider machine) say who it is: `appName` is shown on the approve screen, `keyName` names the minted API key so the user can recognise and revoke it, and `returnUrl` is where the approve screen sends the browser afterwards. `returnUrl` is honoured only for hosts the deployment allowlists; anything else is dropped silently, never rejected.",
      "errors": [
        {
          "description": "Too many pairing attempts from this client; retry later.",
          "name": "RateLimited"
        },
        {
          "description": "`appDid` is not a DID, or has no `dev.cocore.app.registration` record (message begins `AppNotRegistered`).",
          "name": "InvalidRequest"
        }
      ],
      "input": {
        "encoding": "application/json",
        "schema": {
          "properties": {
            "appDid": {
              "description": "The requesting application's DID. When present the AppView reads the app's `dev.cocore.app.registration` record: the approve screen shows that record's `name` (the `appName` field is ignored) and `returnUrl` is honoured only if it matches one of the record's `returnUrls` AND the return host proves ownership via `/.well-known/cocore-app.json`. A DID with no registration record is rejected with InvalidRequest (AppNotRegistered).",
              "format": "did",
              "type": "string"
            },
            "appName": {
              "description": "Human name of the requesting application, shown on the approve screen.",
              "maxLength": 40,
              "type": "string"
            },
            "keyName": {
              "description": "Name for the API key minted on approval.",
              "maxLength": 100,
              "type": "string"
            },
            "returnUrl": {
              "description": "Where to send the browser after approval. Must be https and on an allowlisted host.",
              "format": "uri",
              "maxLength": 2000,
              "type": "string"
            }
          },
          "type": "object"
        }
      },
      "output": {
        "encoding": "application/json",
        "schema": {
          "properties": {
            "deviceId": {
              "type": "string"
            },
            "expiresInSecs": {
              "description": "Seconds until this pairing attempt expires.",
              "type": "integer"
            },
            "pollIntervalSecs": {
              "description": "Minimum seconds between poll calls.",
              "type": "integer"
            },
            "userCode": {
              "description": "Short code the user types at the verification URI.",
              "type": "string"
            },
            "verificationUri": {
              "format": "uri",
              "type": "string"
            }
          },
          "required": [
            "deviceId",
            "userCode",
            "verificationUri",
            "pollIntervalSecs",
            "expiresInSecs"
          ],
          "type": "object"
        }
      },
      "type": "procedure"
    }
  },
  "id": "dev.cocore.devicePair.start",
  "lexicon": 1
}
