---
title: "Resolve a typed user code (console only)"
method: POST
path: "/oauth/device/lookup"
tags: ["OAuth"]
---

# Resolve a typed user code (console only)

`POST /oauth/device/lookup`

## Request

- Base URL: `https://api.infolang.ai`
- URL: `https://api.infolang.ai/oauth/device/lookup`
- Auth: HTTP bearer

Turns a `user_code` a human typed into what approving it would grant: the client's registered name, the scopes the device asked for, and when the code dies. Session-JWT authenticated, exactly like `POST /oauth/consent`.

The code is normalized server-side — uppercased, with every character outside the `BCDFGHJKLMNPQRSTVWXZ23456789` alphabet stripped — so dashes, spaces and pasted whitespace all work. The length check runs afterwards, so a typo that deletes a character is refused rather than silently resolving to a different live code.

**Unknown, expired, already-decided and locked all answer the same 404.** Distinguishing them would make this an oracle that confirms a code exists, and an oracle plus a few thousand requests enumerates every live code on the platform.

## Request body

- object
  - `user_code` string, required

## Response `200`

What approving this code would grant

- object
  - `user_code` string, required
  - `client_id` string, required
  - `client_name` string, nullable, required
  - `scopes` string[], required
  - `expires_at` string, required
  - `expires_in` number, required

## Other responses

- `400`: `too_many_attempts` — five failed entries by this principal
- `401`: Missing or invalid session JWT
- `404`: `not_found` — unknown, expired, already decided, or locked
- `422`: `invalid_request` — the code is not 8 alphabet characters

---

[API](https://skmtc.dev/infolang/apis/infolang-api.md) · [All operations](https://skmtc.dev/infolang/apis/infolang-api/llms.txt) · [OpenAPI document](https://skmtc.dev/infolang/apis/infolang-api/revisions/d04bf6de72c8?raw)
