概览
Manilo API 是一套 JSON REST API,用于以编程方式管理你在 iOS 应用里使用的同一份账本——账户、分类、预算、共享群组和交易。你可以用它来构建导入工具、导出工具、同步桥接、仪表盘,或者驱动你自己的自动化流程。
- 基础 URL:
https://api.manilo.app——此前的基础 URLapi.ledgy.app仍可继续使用。 - 版本前缀:本文档中的所有端点都挂载在
/api/v1/下。 - 传输:仅支持 HTTPS,不接受 HTTP 请求。
- 编码:请求体与响应体均为 JSON,UTF-8 编码。属性名使用
camelCase。 - 身份验证:
Authorization: Bearer …——每个请求都必须携带。 - Cloud 订阅:每个 v1 端点都需要。参见订阅校验。
https://api.manilo.app/mcp 的模型上下文协议端点——详见集成。本文档介绍的 REST API,面向你自己编写的代码。
快速开始
三步完成你的第一个带身份验证的请求。
1. 生成个人访问令牌
- 登录你的 Manilo 仪表盘,打开设置 → API 访问。
- 点击 + 新建令牌。
- 给令牌起一个有描述性的名字(例如“Zapier — 每周导出”),选择你需要的权限范围(参见权限范围),也可以选填一个过期时间。
- 复制该令牌。它只显示一次。令牌以前缀
lgpat_开头,后跟 64 个十六进制字符。
同一页面会列出你的活跃令牌及其最后使用时间和权限数量,给出“30 天内过期”的提醒,并可通过垃圾桶图标随时撤销任意令牌。每个账户同时最多可持有 25 个活跃令牌。
2. 发起请求
# Replace lgpat_… with your token curl "https://api.manilo.app/api/v1/accounts" \ -H "Authorization: Bearer lgpat_a1b2c3d4e5…"
3. 查看响应
{
"items": [
{
"id": "acc_01HK8V…",
"name": "Wise EUR",
"currencyCode": "EUR",
"initialBalance": 1240.50,
"icon": "wallet",
"color": "#4A90E2",
"order": 0,
"createdAt": "2026-04-12T08:13:09Z",
"updatedAt": "2026-05-01T17:02:31Z"
}
],
"totalCount": 1
}
身份验证
发往 /api/v1/ 的每个请求都必须携带 Authorization 请求头。支持两种令牌类型:
- 个人访问令牌(PAT)——长期有效的 Bearer 令牌,在仪表盘的设置 → API 访问页面创建。格式为
lgpat_+ 64 个十六进制字符。可限定权限范围、可撤销,并可选择设置过期时间。推荐所有第三方集成使用。 - 会话 JWT——签发给第一方应用(iOS、仪表盘)的短期令牌,不受权限范围限制。如果你能从已登录的会话中提取到一个,可以用它做一次性测试,但 PAT 才是官方支持的方式。
请求头格式
Authorization: Bearer lgpat_a1b2c3d4e5f6…
令牌限制
- 每个 Manilo 账户最多可拥有 25 个活跃 PAT。
- 创建时可以选填一个过期时间。已过期的令牌会返回
401 Unauthorized。 - 被撤销的令牌会立即失效——Manilo 只保存令牌的 SHA-256 哈希,绝不保存令牌本身,因此泄露的令牌无法找回,只能撤销并重新创建。
常见的身份验证失败
- 401
- 令牌缺失、格式错误、已过期或已被撤销。
- 403
- 令牌有效,但所请求的端点需要你的 PAT 不具备的权限范围,或者你的 Cloud 订阅未处于有效状态。
权限范围
PAT 采用默认拒绝模型。令牌只能调用它持有对应权限范围的端点;其余一律返回 403 Forbidden。请只授予你的集成确实需要的最小权限范围。
可用的权限范围:
accounts:read
accounts:write
categories:read
categories:write
budgets:read
budgets:write
groups:read
groups:write
transactions:read
transactions:write
tags:read
tags:write
recurring:read
recurring:write
settings:read
settings:write
下面列出的每个端点,都会用一个紫色小标签标出它所需的权限范围。:write 权限范围并不隐含 :read——两者都需要时,请同时申请。
订阅校验
所有 v1 端点——包括只读端点——都要求调用方持有有效的 Manilo Cloud 订阅。如果订阅已中断、已过期或从未开通,API 将返回:
HTTP/1.1 403 Forbidden
X-Subscription-Required: true
Content-Type: application/json
{ "error": "Active cloud subscription required" }
通过 X-Subscription-Required 响应头,客户端可以把订阅拦截与一般的权限拒绝区分开。在 iOS 应用中或在 dashboard.manilo.app/upgrade 重新激活 Cloud,即可恢复访问。
错误
错误使用标准 HTTP 状态码。响应体是一个只含单个字段的 JSON 对象:
{ "error": "Human-readable message" }
你应当处理的状态码:
- 200
- OK——已返回资源,或已返回列表。
- 201
- Created——已创建新资源。
Location响应头指向该资源的规范 URL。 - 204
- No Content——删除成功;无响应体。
- 400
- 校验失败——缺少必填字段、取值超出范围,或 JSON 格式错误。
- 401
- 身份验证失败——参见身份验证。
- 403
- 权限被拒——权限范围不足,或订阅未生效。
- 404
- 资源不存在,或因授权原因被隐藏。
- 409
- 冲突——例如违反唯一性约束。
- 5xx
- 服务端故障。幂等的读取请求可以配合指数退避安全重试。
分页与筛选
列表端点默认返回所有匹配项。交易是唯一可能变得很大的资源,它支持基于游标的分页。
交易游标
curl "https://api.manilo.app/api/v1/transactions?limit=50&type=expense&dateFrom=2026-01-01" \ -H "Authorization: Bearer lgpat_…"
响应中包含 nextCursor。把它作为 cursor 查询参数回传,即可获取下一页;当 nextCursor 为 null 时,说明已经到达末尾。
limit——页面大小,取值被限制在1..200。默认50。cursor——不透明的令牌,请把它当作黑盒处理。type,dateFrom,dateTo,categoryId,accountId,groupId——可选筛选条件;参见列出交易端点。
类型与格式
- ID——不透明字符串。请勿解析,把它们视为区分大小写的 UTF-8 标识符。
- 时间戳——UTC 时区的 ISO-8601,以
Z结尾,例如"2026-05-13T10:30:00Z"。 - 日期(例如交易的
date)——同样是 ISO-8601 格式,但只有日期部分有意义。 - 金额——以主单位表示的 JSON 数字,最多 4 位小数(例如
12.50)。绝不使用最小货币单位。始终与currencyCode成对出现。 - 货币代码——ISO-4217,恰好三个大写字母(例如
"EUR","USD","GBP")。 - 删除——所有删除操作都是软删除。被删除的条目不再出现在列表或获取响应中;共享成员与历史小票会被保留。
- 连带影响——删除账户、分类或群组时,依赖它们的交易保持不变,只是引用关系被解除。删除账户端点接受一个显式的处理策略。
账户
账户是承载余额的容器——银行账户、信用卡、现金钱包、券商账户。每笔交易都关联到一个账户(转账则关联两个)。
/api/v1/accounts
accounts:read
返回已认证用户拥有或有权访问的每一个账户。
/api/v1/accounts/{id}
accounts:read
按 id 获取单个账户。未找到时返回 404。
/api/v1/accounts
accounts:write
创建新账户。返回 201,响应体为创建出的对象,并带有 Location 响应头。
| 字段 | 类型 | 说明 |
|---|---|---|
| name | string | 必填显示名称。最多 100 个字符。 |
| currencyCode | string | 必填ISO-4217,恰好 3 个字母。 |
| initialBalance | number | 必填以 currencyCode 计的期初余额。 |
| order | integer | 必填排序位置。数值越小越靠前。 |
| icon | string | 可选来自 /api/v1/icons 的图标标识符。最多 50。 |
| color | string | 可选十六进制颜色,例如 "#4A90E2"。最多 20。 |
| iconColor | string | 可选覆盖图标的着色。 |
POST /api/v1/accounts
{
"name": "Cash",
"currencyCode": "EUR",
"initialBalance": 50.00,
"order": 2,
"icon": "wallet",
"color": "#22C55E"
}
{
"id": "acc_01HK8V…",
"name": "Cash",
"currencyCode": "EUR",
"initialBalance": 50.00,
"order": 2,
"icon": "wallet",
"color": "#22C55E",
"iconColor": null,
"shareInviteToken": null,
"createdAt": "2026-05-13T10:30:00Z",
"updatedAt": "2026-05-13T10:30:00Z"
}
/api/v1/accounts/{id}
accounts:write
软删除一个账户。通过 action 查询参数决定它名下的交易如何处理。
| 字段 | 类型 | 说明 |
|---|---|---|
| action | enum | 可选Detach(默认):清除每笔交易上的账户引用。Move:把交易改挂到 moveTargetAccountId 指定的账户。DeleteAll:软删除你拥有的每一笔关联交易。 |
| moveTargetAccountId | string | 可选当 action=Move 时必填。目标账户 id。 |
分类
分类用来标注一笔交易的用途(日用杂货、房租、自由职业收入)。系统分类为只读,所有用户共用;用户分类由你自行管理。分类组则把相关的分类归到一起。
/api/v1/categories/system-categories
categories:read
返回 Manilo 精选的“常用”分类集——也就是 iOS 应用自带的初始分类。它们在全局范围内做版本管理,可以安全地按 version 缓存。
用户分类
/api/v1/categories
categories:read
列出所有用户自定义的分类。
/api/v1/categories/{id}
categories:read
按 id 获取单个用户分类。
/api/v1/categories
categories:write
创建一个用户分类。
| 字段 | 类型 | 说明 |
|---|---|---|
| name | string | 必填显示名称。最多 100。 |
| type | string | 必填"income" 或 "expense"。 |
| order | integer | 必填在所属分类组中的排序位置。 |
| isPinned | boolean | 必填置顶到选择器的最前面。 |
| categoryGroupId | string | 可选父分类组的 id;未分组时为 null。 |
| icon | string | 可选图标标识符。 |
| color | string | 可选十六进制颜色。 |
/api/v1/categories/{id}
categories:write
软删除一个用户分类。交易不会被删除,只会清空它们的 categoryId。
分类组
/api/v1/categories/groups
categories:read
列出你的分类组。
/api/v1/categories/groups/{id}
categories:read
获取单个分类组。
/api/v1/categories/groups
categories:write
创建一个分类组。
| 字段 | 类型 | 说明 |
|---|---|---|
| name | string | 必填显示名称。最多 100。 |
| order | integer | 必填排序位置。 |
| icon | string | 可选图标标识符。 |
| color | string | 可选十六进制颜色。 |
/api/v1/categories/groups/{id}
categories:write
替换一个分类组。
/api/v1/categories/groups/{id}
categories:write
软删除一个分类组。子分类会保留下来——只会清空它们的 categoryGroupId。
预算
预算在一个周期性的时间窗内,为某个分类的支出设定上限(当 categoryId 为 null 时,则针对整个账本)。设置 groupId 即可把预算共享给某个群组。
/api/v1/budgets
budgets:read
列出所有预算。
/api/v1/budgets/{id}
budgets:read
获取单个预算。
/api/v1/budgets
budgets:write
创建一个预算。
| 字段 | 类型 | 说明 |
|---|---|---|
| amount | number | 必填每个周期的上限。必须大于 0。 |
| currencyCode | string | 必填ISO-4217。 |
| period | integer | 必填0 每周 · 1 每月 · 2 每季度 · 3 每年。 |
| startDate | string (ISO-8601) | 必填第一个周期的开始时间。 |
| isActive | boolean | 必填该预算当前是否生效。 |
| endDate | string (ISO-8601) | 可选在此日期之后停止跟踪。 |
| name | string | 可选标签。最多 200。 |
| categoryId | string | 可选要跟踪的分类。省略则对全部支出做预算。 |
| groupId | string | 可选要共享到的群组。省略则为个人预算。 |
/api/v1/budgets/{id}
budgets:write
替换一个预算。
/api/v1/budgets/{id}
budgets:write
软删除一个预算。
群组
群组就是共享账本——一个家庭、一次旅行、一间合租公寓。每位成员看到的都是同一批交易;所有权仍然归个人。成员与邀请在 iOS 应用中管理;这里的 API 只覆盖群组资源本身。
/api/v1/groups
groups:read
列出你拥有或参与的群组。
/api/v1/groups/{id}
groups:read
获取单个群组。
/api/v1/groups
groups:write
创建一个群组。你将成为它的所有者;请在 iOS 应用中邀请成员。
| 字段 | 类型 | 说明 |
|---|---|---|
| name | string | 必填显示名称。最多 100。 |
| description | string | 可选自由文本。最多 500。 |
| icon | string | 可选图标标识符。 |
| color | string | 可选十六进制颜色。 |
/api/v1/groups/{id}
groups:write
替换群组的元数据。
/api/v1/groups/{id}
groups:write
软删除一个群组。成员将失去可见性;底层交易恢复为个人所有。
交易
交易是账本里的动词。它们共有四种形态:income, expense, transfer(账户之间),以及 adjustment(一次性的余额校正)。基础端点用于创建收入和支出;转账有自己的端点;面向大批量导入的场景还提供了批量变体。
/api/v1/transactions
transactions:read
列出交易,支持游标分页与筛选。
| 字段 | 类型 | 说明 |
|---|---|---|
| limit | integer | 可选页面大小。1..200。默认 50。 |
| cursor | string | 可选上一次响应返回的不透明续传令牌。 |
| type | string | 可选"income", "expense", "transfer",或 "adjustment"。 |
| dateFrom | string (ISO-8601) | 可选下界,含该值。 |
| dateTo | string (ISO-8601) | 可选上界,含该值。 |
| categoryId | string | 可选筛选到某一个分类。 |
| accountId | string | 可选筛选到某一个账户。 |
| groupId | string | 可选筛选到某个共享群组。 |
{
"items": [ /* TransactionDto[] */ ],
"totalCount": 317,
"nextCursor": "eyJrIjoiMjAyNi0wNS0xM1QxMDoz…"
}
/api/v1/transactions/{id}
transactions:read
获取单笔交易。
| 字段 | 类型 | 说明 |
|---|---|---|
| type | string | 必填"income" 或 "expense"。 |
| amount | number | 必填以 currencyCode 计的正数金额。 |
| currencyCode | string | 必填ISO-4217。 |
| date | string (ISO-8601) | 必填交易发生的时间(UTC)。 |
| accountId | string | 可选来源或目标账户。 |
| categoryId | string | 可选分类标签。 |
| payee | string | 可选商家或交易对方。最多 200。 |
| note | string | 可选自由格式备注。最多 2000。 |
| groupId | string | 可选共享给某个群组。 |
| exchangeRate | number | 可选当 currencyCode ≠ 用户主货币时使用的汇率。 |
| convertedAmount | number | 可选以用户主货币计的金额。 |
POST /api/v1/transactions
{
"type": "expense",
"amount": 8.50,
"currencyCode": "EUR",
"date": "2026-05-12T09:14:00Z",
"accountId": "acc_01HK8V…",
"categoryId": "cat_food_drinks",
"payee": "Pret",
"note": "Flat white"
}
/api/v1/transactions/{id}
transactions:write
软删除单笔交易。
/api/v1/transactions/transfer
transactions:write
在两个账户之间创建一笔转账。没有分类。跨币种转账时,请提供 exchangeRate,以及以目标货币计的 convertedAmount。
| 字段 | 类型 | 说明 |
|---|---|---|
| fromAccountId | string | 必填来源账户。 |
| toAccountId | string | 必填目标账户。必须与来源账户不同。 |
| amount | number | 必填转出金额,以 currencyCode 计。 |
| currencyCode | string | 必填来源货币,ISO-4217。 |
| date | string (ISO-8601) | 必填转账日期。 |
| exchangeRate | number | 可选当来源货币与目标货币不同时必填。 |
| convertedAmount | number | 可选记入目标账户的金额,以其自身货币计。 |
| note | string | 可选最多 2000。 |
批量操作
专为导入工具设计。每批最多 100 条,并以尽力而为的方式执行:单条数据有误不会回滚其余条目。成功的条目和逐条的错误会分开返回,方便你只重试失败的部分。
/api/v1/transactions/bulk
transactions:write
一次调用创建最多 100 笔交易。
{
"items": [ /* successful TransactionDto[] */ ],
"errors": [
{ "index": 3, "error": "Invalid currency code" }
]
}
/api/v1/transactions/bulk
transactions:write
一次调用更新最多 100 笔交易。每一条除完整的交易体外,还必须附带它的 id。
/api/v1/transactions/bulk-delete
transactions:write
一次调用软删除最多 100 笔交易。这里使用 POST 而非 DELETE,以确保所有 HTTP 客户端都接受请求体。
| 字段 | 类型 | 说明 |
|---|---|---|
| ids | string[] | 必填1 到 100 个交易 id。 |
{
"deleted": 97,
"notFound": [ "tx_old1", "tx_old2", "tx_old3" ]
}
交易对象
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 不透明标识符。 |
| type | string | income · expense · transfer · adjustment. |
| amount | number | 以 currencyCode 计。 |
| currencyCode | string | ISO-4217。 |
| exchangeRate | number | null | 在跨币种条目上会设置该值。 |
| convertedAmount | number | null | 以用户主货币表示的同一笔金额。 |
| date | string | ISO-8601 UTC。 |
| accountId | string | null | 对转账而言,这里是来源账户。 |
| toAccountId | string | null | 仅转账才有的目标账户。 |
| categoryId | string | null | 转账时为 null。 |
| groupId | string | null | 共享给群组时会设置该值。 |
| payee | string | null | 商家或交易对方。 |
| note | string | null | 自由文本。 |
| receiptImagePath | string | null | 所附小票的路径。通过小票端点获取(独立于 v1)。 |
| recurringTransactionId | string | null | 如果这条记录由周期性规则生成,则会设置该值。 |
| source | string | 来源标记——api, mobile, web, import 等。 |
| createdAt | string | ISO-8601 UTC。 |
| updatedAt | string | ISO-8601 UTC。 |
图标
Manilo 内置了一套精选图标和配色,在账户、分类、群组中通用。把目录取回一次并缓存起来,创建资源时复用这些标识符即可。
/api/v1/icons
返回完整的图标库(按类别分组),以及受支持的配色。带版本号——可以安全地按 version 字段缓存。
{
"version": "2026.05.10",
"library": "font-awesome-6",
"categories": [
{
"id": "finance",
"name": "Finance",
"icons": [ "wallet", "credit-card", "piggy-bank" ]
}
],
"colors": [
{ "name": "Blue", "hex": "#4A90E2" },
{ "name": "Green", "hex": "#22C55E" }
]
}
版本策略
- v1 内不会有破坏性变更。我们只会新增端点、新增可选字段和新增枚举值。字段的类型、可空性或必填性都不会改变。
- 新增枚举值不算破坏性变更。遇到无法识别的
type,source或action取值时,请按“不渲染”处理,而不要直接崩溃——随着产品成长,我们会继续新增这些取值。 - 带日期标记的破坏性变更(如果确有必要)将发布在
/api/v2/之下,并至少提供 6 个月的并行可用期,同时在 v1 响应中加上弃用响应头。
支持
发现了 bug、希望增加某个端点,或者遇到了文档未覆盖的情况?请打开帮助中心,或发邮件至 support@manilo.app——报告问题时,请附上请求 id(会在 X-Request-Id 响应头中回显)。
涉及安全的披露(令牌泄露、权限绕过、未经授权的读取),请写信至 security@manilo.app。