---
id: "a57e50d3f0adebd7aa38"
url: "https://www.xmcsl.cn/project/feishu-cli-embed/02-one-click-app/03-%E4%B8%80%E9%94%AE%E5%88%9B%E5%BB%BA%E5%BA%94%E7%94%A8%EF%BC%88Python%EF%BC%89.html"
source_url: "https://open.feishu.cn/document/mcp_open_tools/scan-to-create-an-app-in-one-click"
source_date: null
checked_at: "2026-11-05T04:21:48.909937+00:00"
status: "ready"
check_scope: "structure_only; not a factual or human review"
body_sha256: "90b95e3ee0f1ed187f5cffa836ba15ede9a9025e441ca0f113fd196b02f4fe6b"
---

# 一键创建应用（Python） · 飞书 Agent 接入知识库

Python SDK 提供了 <code>register&#95;app</code>（同步）和 <code>aregister&#95;app</code>（异步）方法，基于 OAuth 2.0 Device Authorization Grant（RFC 8628）协议实现一键创建应用。

 

调用该方法会返回一个验证链接，用户在飞书或 Lark 中打开该链接（或扫码）完成授权后，即可自动注册应用并获取凭据（App ID 和 App Secret），无需手动前往开发者后台创建。

 

查看源码：<a href="https://github.com/larksuite/oapi-sdk-python">oapi-sdk-python</a>

 

## 前提条件

 

<ul>&#10;<li>&#10;<p>Python 版本 <code>&gt;= 3.8</code></p>&#10;</li>&#10;<li>&#10;<p>安装或升级 <code>lark-oapi</code> 至 <code>1.5.5</code> 及以上版本：</p>&#10;</li>&#10;</ul>

 

```
  pip install lark-oapi
```

 

## 快速开始示例

 

### 同步版

 

```python
import lark_oapi as lark
def handle_qr(info):
    print(f"请扫码: {info['url']}")
    print(f"有效期 {info['expire_in']} 秒")
def handle_status(info):
    print(f"状态: {info['status']}", info.get("interval", ""))
try:
    result = lark.register_app(
        on_qr_code=handle_qr,
        on_status_change=handle_status,
    )
    print(f"App ID: {result['client_id']}")
    print(f"App Secret: {result['client_secret']}")
    print(f"User Info: {result.get('user_info')}")
except Exception as e:
    print(f"失败: {e}")
```

 

### 异步版

 

```python
import asyncio
import lark_oapi as lark
async def main():
    result = await lark.aregister_app(
        on_qr_code=lambda info: print(f"请扫码: {info['url']}"),
    )
    print(f"App ID: {result['client_id']}")
    print(f"App Secret: {result['client_secret']}")
asyncio.run(main())
```

 

## 自定义权限/事件/回调与更新已有应用

 

创建应用时，可通过 <code>addons</code> 在平台基础模板上增量申请权限、事件订阅和回调。这些配置会预填到用户扫码后的确认页中，用户确认后生效：

 

```python
result = lark.register_app(
    on_qr_code=on_qr_code,
    addons={
        "scopes": {
            "tenant": ["im:message:send_as_bot"],
            "user": ["calendar:calendar:read"],
        },
        "events": {"items": {"tenant": ["im.message.receive_v1"]}},
        "callbacks": {"items": ["card.action.trigger"]},
    },
    create_only=True,
)

lark.register_app(
    on_qr_code=on_qr_code,
    app_id="cli_xxx",
    addons={"scopes": {"tenant": ["drive:drive.metadata:readonly"]}},
)
```

 

<ul>&#10;<li><code>addons</code> 仅支持在基础模板上增量叠加，不支持删减基础权限。</li>&#10;<li><code>addons.preset</code> 控制底座模板：缺省或 <code>True</code> 使用默认底座模板；<code>False</code> 切换为最小基础模板，最终配置只包含 <code>addons</code> 显式声明的内容。传 <code>"preset": False</code> 时，<code>addons</code> 可以不带任何增量条目。</li>&#10;<li>仅支持 5 类公开配置：应用/用户身份权限、应用/用户身份事件、回调。敏感配置（事件请求地址、<code>security.&#42;</code>、加密 key 等）不能通过 <code>addons</code> 传入。</li>&#10;<li>SDK 只校验数据形状，不校验权限点/事件/回调名称是否存在；平台目录中不存在的名称会被确认页忽略。</li>&#10;</ul>

 

如需不使用 mock、真实跑一遍手动 E2E：

 

```bash
python3 samples/registration/app_preset_live_e2e.py --open
```

 

## API 描述

 

### 函数签名

 

<table>&#10;<thead>&#10;<tr>&#10;<th><strong>函数</strong></th>&#10;<th><strong>签名</strong></th>&#10;<th><strong>说明</strong></th>&#10;</tr>&#10;</thead>&#10;<tbody>&#10;<tr>&#10;<td><code>register&#95;app</code></td>&#10;<td><code>(on&#95;qr&#95;code, on&#95;status&#95;change=None, source=None, cancel&#95;event=None, domain=..., lark&#95;domain=...) -&gt; dict</code></td>&#10;<td>同步版，阻塞当前线程直到完成</td>&#10;</tr>&#10;<tr>&#10;<td><code>aregister&#95;app</code></td>&#10;<td><code>async (on&#95;qr&#95;code, on&#95;status&#95;change=None, source=None, domain=..., lark&#95;domain=...) -&gt; dict</code></td>&#10;<td>异步版，返回 coroutine</td>&#10;</tr>&#10;</tbody>&#10;</table>

 

### register\_app 参数

 

<table>&#10;<thead>&#10;<tr>&#10;<th>参数</th>&#10;<th>描述</th>&#10;<th>类型</th>&#10;<th>必填</th>&#10;<th>默认值</th>&#10;</tr>&#10;</thead>&#10;<tbody>&#10;<tr>&#10;<td><code>on&#95;qr&#95;code</code></td>&#10;<td>验证链接就绪时的回调，参数为 <code>&#123;"url": str, "expire&#95;in": int&#125;</code></td>&#10;<td>function</td>&#10;<td>是</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>on&#95;status&#95;change</code></td>&#10;<td>轮询状态变化回调，状态包括 <code>polling</code>、<code>slow&#95;down</code>、<code>domain&#95;switched</code></td>&#10;<td>function</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>source</code></td>&#10;<td>来源标识，会拼入二维码 URL 的 <code>source</code> 参数，格式为 <code>python-sdk/&#123;source&#125;</code></td>&#10;<td>string</td>&#10;<td>否</td>&#10;<td><code>python-sdk</code></td>&#10;</tr>&#10;<tr>&#10;<td><code>cancel&#95;event</code></td>&#10;<td>用于取消同步轮询的 <code>threading.Event</code></td>&#10;<td>threading.Event</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>domain</code></td>&#10;<td>自定义飞书账号域名 base URL</td>&#10;<td>string</td>&#10;<td>否</td>&#10;<td><code>https://accounts.feishu.cn</code></td>&#10;</tr>&#10;<tr>&#10;<td><code>lark&#95;domain</code></td>&#10;<td>自定义 Lark 账号域名 base URL，检测到 Lark 租户时使用</td>&#10;<td>string</td>&#10;<td>否</td>&#10;<td><code>https://accounts.larksuite.com</code></td>&#10;</tr>&#10;<tr>&#10;<td><code>app&#95;preset</code></td>&#10;<td>创建页预填信息。所有字段都是选填，用户扫码后仍可在页面手动修改。调用方传原始值，SDK 自动 URL Encode</td>&#10;<td>dict</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>app&#95;preset.avatar</code></td>&#10;<td>应用头像 URL，支持 1-6 个；传多个时默认选中第一个。图片格式由 Web 页面处理：png / jpg / jpeg / webp / gif</td>&#10;<td>string 或 list&#91;string&#93;</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>app&#95;preset.name</code></td>&#10;<td>应用名称，支持 <code>&#123;user&#125;</code> 占位符，由 Web 页面替换为扫码用户名称</td>&#10;<td>string</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>app&#95;preset.desc</code></td>&#10;<td>应用描述，支持 <code>&#123;user&#125;</code> 占位符</td>&#10;<td>string</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>addons</code></td>&#10;<td>增量权限/事件/回调配置，预填到扫码后的确认页，用户确认后生效</td>&#10;<td>dict</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>addons.preset</code></td>&#10;<td>底座模板开关。缺省或 <code>True</code> 使用默认底座模板；<code>False</code> 切换为最小基础模板，应用配置完全由 <code>addons</code> 显式声明</td>&#10;<td>bool</td>&#10;<td>否</td>&#10;<td><code>True</code></td>&#10;</tr>&#10;<tr>&#10;<td><code>addons.scopes.tenant</code></td>&#10;<td>应用身份权限列表，如 <code>im:message:send&#95;as&#95;bot</code></td>&#10;<td>list&#91;string&#93;</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>addons.scopes.user</code></td>&#10;<td>用户身份权限列表，如 <code>calendar:calendar:read</code></td>&#10;<td>list&#91;string&#93;</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>addons.events.items.tenant</code></td>&#10;<td>应用身份事件列表，如 <code>im.message.receive&#95;v1</code></td>&#10;<td>list&#91;string&#93;</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>addons.events.items.user</code></td>&#10;<td>用户身份事件列表，如 <code>calendar.calendar.event.changed&#95;v4</code></td>&#10;<td>list&#91;string&#93;</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>addons.callbacks.items</code></td>&#10;<td>回调列表，如 <code>card.action.trigger</code></td>&#10;<td>list&#91;string&#93;</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>create&#95;only</code></td>&#10;<td>为 <code>True</code> 时落地页仅允许创建新应用，隐藏「选择已有应用」入口。与 <code>app&#95;id</code> 同时传入时优先级更高</td>&#10;<td>bool</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;<tr>&#10;<td><code>app&#95;id</code></td>&#10;<td>已有应用的 App ID（<code>cli&#95;</code> 开头）。传入后流程变为更新该应用配置；二维码 URL 上使用平台参数 <code>clientID</code></td>&#10;<td>string</td>&#10;<td>否</td>&#10;<td>-</td>&#10;</tr>&#10;</tbody>&#10;</table>

 

### on\_qr\_code 回调参数

 

<table>&#10;<thead>&#10;<tr>&#10;<th><strong>字段</strong></th>&#10;<th><strong>类型</strong></th>&#10;<th><strong>说明</strong></th>&#10;</tr>&#10;</thead>&#10;<tbody>&#10;<tr>&#10;<td><code>url</code></td>&#10;<td><code>str</code></td>&#10;<td>完整的二维码 URL（已拼好 <code>from</code>、<code>tp</code>、<code>source</code> 参数）</td>&#10;</tr>&#10;<tr>&#10;<td><code>expire&#95;in</code></td>&#10;<td><code>int</code></td>&#10;<td>二维码有效期（秒）</td>&#10;</tr>&#10;</tbody>&#10;</table>

 

### on\_status\_change 回调参数

 

<table>&#10;<thead>&#10;<tr>&#10;<th><strong>字段</strong></th>&#10;<th><strong>类型</strong></th>&#10;<th><strong>说明</strong></th>&#10;</tr>&#10;</thead>&#10;<tbody>&#10;<tr>&#10;<td><code>status</code></td>&#10;<td><code>str</code></td>&#10;<td>状态：<code>polling</code> / <code>slow&#95;down</code> / <code>domain&#95;switched</code></td>&#10;</tr>&#10;<tr>&#10;<td><code>interval</code></td>&#10;<td><code>int</code>（可选）</td>&#10;<td>当前轮询间隔（秒），<code>slow&#95;down</code> 时有值</td>&#10;</tr>&#10;</tbody>&#10;</table>

 

### 返回值

 

返回一个 <code>dict</code>，包含： \| <strong>字段</strong> \| <strong>类型</strong> \| <strong>说明</strong> \| \| \-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \| \-\-\-\-\-\-\-\-\-\- \| \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- \| \| <code>client&#95;id</code> \| <code>str</code> \| App ID \| \| <code>client&#95;secret</code> \| <code>str</code> \| App Secret \| \| <code>user&#95;info</code> \| <code>dict</code>（可选） \| 扫码用户信息，含 <code>open&#95;id</code>、<code>tenant&#95;brand</code>（<code>feishu</code> 或 <code>lark</code>） \|

 

### 异常类型

 

<table>&#10;<thead>&#10;<tr>&#10;<th><strong>异常</strong></th>&#10;<th><strong>触发条件</strong></th>&#10;</tr>&#10;</thead>&#10;<tbody>&#10;<tr>&#10;<td><code>AppAccessDeniedError</code></td>&#10;<td>用户主动拒绝授权</td>&#10;</tr>&#10;<tr>&#10;<td><code>AppExpiredError</code></td>&#10;<td>二维码过期或轮询超时</td>&#10;</tr>&#10;<tr>&#10;<td><code>RegisterAppError</code></td>&#10;<td>其他错误（携带 <code>code</code>、<code>description</code> 属性）</td>&#10;</tr>&#10;<tr>&#10;<td>&#42; &#42; &#42;</td>&#10;<td></td>&#10;</tr>&#10;</tbody>&#10;</table>

 

## 进阶用法

 

### 同步版：取消轮询

 

```python
import threading
import lark_oapi as lark
cancel_event = threading.Event()

# 另一个线程里可以随时取消

# cancel_event.set()

result = lark.register_app(
    on_qr_code=handle_qr,
    cancel_event=cancel_event,
)
```

 

### 异步版：取消任务

 

```python
import asyncio
import lark_oapi as lark
async def main():
    task = asyncio.create_task(lark.aregister_app(on_qr_code=handle_qr))
    # 某个时刻取消

task.cancel()
    try:
        result = await task
    except asyncio.CancelledError:
        print("已取消")
asyncio.run(main())
```

 

### 拿到凭据后初始化 Client

 

```python
result = lark.register_app(on_qr_code=handle_qr)
client = lark.Client.builder() \
    .app_id(result['client_id']) \
    .app_secret(result['client_secret']) \
    .build()
```

 

---
