# 请求与错误 > Ora API 的请求和响应采用什么结构,每种错误的含义,以及速率限制。 ### 请求与响应 - **JSON 进,JSON 出。** 有请求体时发送 `Content-Type: application/json`,并且仅在有请求体时发送。 - **响应封装。** 每个响应都带有 `"success": true` 或 `"success": false`。请检查它,而不要只看状态码。 - **代币数量** 是以最小单位表示的原始数值,写成十进制 *字符串*,因为它们会超出 JavaScript 数字的范围:`"250000000000"`。显示时,请除以 10 的代币小数位数次方(大多数 Solana 发射平台代币使用 6 位小数,EVM 代币使用 18 位)。 - **原生币数量。** 名为 `…Sol` 的输入是该链 gas 资产的普通十进制数值(`0.5`)。响应中的原始原生币数量,在 Solana 上以 lamports 计,在 EVM 链上以 wei 计。 - **地址。** Solana 地址为 base58 格式,EVM 地址为 `0x` 开头的十六进制格式。路径中的 `{address}` 和 `{mint}` 是代币的 mint(Solana)或合约(EVM)。 - **请求 ID。** 每个响应都带有 `X-Request-ID` 响应头。你也可以发送自己的 ID(UUID v4),把一次调用与你的日志对应起来;Ora 会把它传递到它经过的每个服务。 - **时间戳** 采用 ISO 8601 格式,使用 UTC 时间。 ### 错误 调用失败时会返回 `"success": false` 和一个 `error`。当 Ora 转发来自其某个服务的失败时,`error` 是一个简短的参考代码(例如 `M4K8T`),`message` 则给出可读的原因。 ```json { "success": false, "error": "M4K8T", "message": "…readable reason…" } ``` | 状态码 | 含义 | 应对方法 | |---|---|---| | `400` | 请求体或某个参数无效。 | 查看 `error` 和 `message`:它们会指出是哪个字段。不要原样重试。 | | `401` | 没有密钥、密钥格式错误,或密钥已被轮换或撤销。 | 检查请求头和密钥。不要循环重试:被拒绝的密钥会按 IP 限速。 | | `403` | 该账户未开通 API 访问权限。 | 请联系 Ora 支持团队开通 API 访问权限。 | | `404` | 未找到,或不属于你。Ora 绝不会透露不属于你的东西是否存在。 | 检查 ID 或地址,并确认它属于你的账户。 | | `409` | 资源当前的状态不允许此操作(尚未发射、已在运行等)。 | 先读取状态,再执行操作。 | | `429` | 已达到速率限制。 | 退避等待:参见[速率限制](#rate-limits)。 | | `502` | API 背后的某个服务出错。 | 退避后重试。如果问题持续,请将 `error` 代码和 `X-Request-ID` 发给 Ora 支持团队。 | | `503` | 暂时不可用(某个依赖服务宕机或繁忙)。 | 退避后重试。 | > **Warning:** **写操作不具备幂等性。** 买入、卖出或发射时遇到 `502` 或超时,并不代表什么都没有发生。在重试写操作之前,请先读取状态(持仓、交易、代币数据流)。 ### 速率限制 | 配额 | 限制 | 计数维度 | 涵盖范围 | |---|---|---|---| | API 请求 | 每分钟 100 次 | 账户 | 使用你的密钥发出的每个请求,包括数据流(每个连接计一次)。与应用自身的配额相互独立:脚本再繁忙也不会拖慢你的应用会话。 | | 被拒绝的密钥 | 每分钟 20 次 | IP 地址 | 密钥格式错误或未知的请求(`401`)。超过后,这些请求会收到 `429`。 | 计数窗口为固定的一分钟窗口。`429` 不带 `Retry-After` 响应头:请先等待,然后以指数退避方式重试,从 1 秒开始,上限为 60 秒。批量任务请分散在一段时间内执行,不要集中突发。 ```js title="retry.mjs" export async function withRetry(fn, tries = 6) { for (let i = 0; ; i++) { try { return await fn(); } catch (err) { const retryable = err.status === 429 || err.status === 502 || err.status === 503; if (!retryable || i + 1 >= tries) throw err; await new Promise((r) => setTimeout(r, Math.min(60_000, 1000 * 2 ** i))); } } } // Reads only. Before retrying a write, check what already happened. ```