ErisPulse API Action Standard
This document defines the unified interface specification for OneBot12-standard API actions in ErisPulse adapters, enabling module developers to program against standard interfaces, with adapters responsible for mapping to native platform APIs.
Scope: In the OneBot12 standard actions,
ApiDSLprovides strongly-typed methods for user/group/channel (Guild)/message management/meta general interfaces (send_messageis handled bySendDSL.Raw_ob12). File resource actions (upload_file/get_file/chunking) are only retained for backward compatibility and degraded pass-through, see §3.5 for details. Platform extension actions are called via the escape hatchApi.call("prefix.action", ...). Action parameters and return structures are based on the OneBot12 specification (located in the repository atonebot/specs/interface/).
1. Design Background
In ErisPulse, message segments (message sending and receiving) and event formats have fully followed the OneBot12 standard, but API action calls (such as getting user information, getting group lists, recalling messages, etc.) were not unified previously—module developers had to write different call_api calls for each platform.
ApiDSL solves this issue by providing strongly-typed standard action methods:
Module Code (Cross-platform Consistency) Adapter Implementation (Platform-specific)
───────────────────────────────── ──────────────────────────────────
adapter.Api.get_user_info("123") → Adapter call_api / Override
adapter.Api.get_group_list() → Adapter call_api / Override
adapter.Api.delete_message("id") → Adapter call_api / Override
2. Three-layer DSL Parallel Structure
The ErisPulse adapter has three parallel DSL inner classes, each with its own responsibilities:
BaseAdapter
├── Send(SendDSL) ← Message sending (Text/Image/Raw_ob12)
├── Request(RequestDSL) ← Request handling (accept/reject)
└── Api(ApiDSL) ← Standard API actions (user/group/channel/message management/files/metadata) ★
| DSL | Responsibility | Method Style | Return Value |
|---|---|---|---|
Send |
Sending messages | Chainable + asyncio.Task |
Standard response |
Request |
Handling request events | asyncio.Task |
Standard response |
Api |
Query/management operations | async methods |
Standard response |
3. Standard Action List
3.1 User-related
| Method | OB12 Action | Parameters | data Return |
|---|---|---|---|
get_self_info() |
get_self_info |
None | user_id, user_name, user_displayname |
get_user_info(user_id) |
get_user_info |
user_id: str |
user_id, user_name, user_displayname, user_remark |
get_friend_list() |
get_friend_list |
None | list[get_user_info response] |
3.2 Group-related
| Method | OB12 Action | Parameters | data Return |
|---|---|---|---|
get_group_info(group_id) |
get_group_info |
group_id: str |
group_id, group_name |
get_group_list() |
get_group_list |
None | list[get_group_info response] |
get_group_member_info(group_id, user_id) |
get_group_member_info |
group_id: str, user_id: str |
user_id, user_name, user_displayname |
get_group_member_list(group_id) |
get_group_member_list |
group_id: str |
list[get_group_member_info response] |
set_group_name(group_id, group_name) |
set_group_name |
group_id: str, group_name: str |
None |
leave_group(group_id) |
leave_group |
group_id: str |
None |
3.3 Message Management
| Method | OB12 Action | Parameters | Description |
|---|---|---|---|
delete_message(message_id) |
delete_message |
message_id: str |
Recall/Delete message |
Sending Messages (handled by
SendDSL.Raw_ob12) is not duplicated inApiDSL.
3.4 Guild-related
OneBot12 guild system consists of two levels: guild and channel.
| Method | OB12 Action | Parameters | data Return |
|---|---|---|---|
get_guild_info(guild_id) |
get_guild_info |
guild_id: str |
guild_id, guild_name |
get_guild_list() |
get_guild_list |
None | list[get_guild_info response] |
set_guild_name(guild_id, guild_name) |
set_guild_name |
guild_id: str, guild_name: str |
None |
get_guild_member_info(guild_id, user_id) |
get_guild_member_info |
guild_id: str, user_id: str |
user_id, user_name, user_displayname |
get_guild_member_list(guild_id) |
get_guild_member_list |
guild_id: str |
list[get_guild_member_info response] |
leave_guild(guild_id) |
leave_guild |
guild_id: str |
None |
get_channel_info(guild_id, channel_id) |
get_channel_info |
guild_id: str, channel_id: str |
channel_id, channel_name |
get_channel_list(guild_id, *, joined_only) |
get_channel_list |
guild_id: str, joined_only: bool=false |
list[get_channel_info response] |
set_channel_name(guild_id, channel_id, channel_name) |
set_channel_name |
guild_id, channel_id, channel_name |
None |
get_channel_member_info(guild_id, channel_id, user_id) |
get_channel_member_info |
guild_id, channel_id, user_id |
user_id, user_name, user_displayname |
get_channel_member_list(guild_id, channel_id) |
get_channel_member_list |
guild_id, channel_id |
list[get_channel_member_info response] |
leave_channel(guild_id, channel_id) |
leave_channel |
guild_id, channel_id |
None |
The guild system is independent from the group system: platforms such as Discord, QQ Guild, and Kook implement the guild interface, while traditional platforms like QQ and WeChat implement the group interface. Both may coexist or exist independently.
3.5 File Resource Operations
[!WARNING] The file resource model (two-segment file_id) is "downgraded" in ErisPulse: ErisPulse does not use the "upload first, get file_id, then reference" model for file transfer—modules send files using
SendDSL.File(file, filename)(direct upload of URL/path/bytes at send time, see Send Method Specification). The actionsupload_file,get_file, and segmented actions in this section depend on platform-specificfile_idfile resource capabilities, which are not universally compatible; only when the adapter backend naturally supports this capability can it be passed through. The framework's built-in adapters do not implement or recommend implementing this, and calls typically returnretcode=10002. When modules need to transfer files across platforms, please useSendDSL.File, and do not rely on file_id.Outlook: Standardizing the
file_idresource model to the framework layer is a future direction, but it is not provided in the current version.
Bulk transfer (small files):
| Method | OB12 Action | Parameters | data Return |
|---|---|---|---|
upload_file(*, type, name, ...) |
upload_file |
type, name, url/path/data, headers?, sha256? |
file_id |
get_file(file_id, type) |
get_file |
file_id: str, type: str |
name, url/path/data |
The type parameter for upload_file:
"url": Upload via URL (requiresurl)"path": Upload via local path (requirespath)"data": Upload via binary data (requiresdata)
3.5.1 Segmented Transfer (Large Files, within the above degraded scope)
OneBot12 segmented actions are distinguished by stage. ApiDSL splits the three or two stages of the same action into separate methods (offset is byte offset, data in JSON is Base64); the following table is retained for reference only, and adapters should neither implement nor enforce it:
Three-step segmented upload: prepare → transfer (loop through each segment) → finish
| Method | Corresponding stage | Parameters | data Return |
|---|---|---|---|
upload_file_fragmented_prepare(name, total_size) |
prepare |
name: str, total_size: int |
file_id (used during transfer) |
upload_file_fragmented_transfer(file_id, offset, data) |
transfer |
file_id, offset: int, data: bytes |
None |
upload_file_fragmented_finish(file_id, sha256) |
finish |
file_id, sha256: str (file-wide checksum) |
file_id |
total = os.path.getsize(path)
r = await adapter.Api.upload_file_fragmented_prepare(os.path.basename(path), total)
fid = r["data"]["file_id"]
offset = 0
with open(path, "rb") as f:
while chunk := f.read(65536):
await adapter.Api.upload_file_fragmented_transfer(fid, offset, chunk)
offset += len(chunk)
sha256 = hashlib.sha256(open(path, "rb").read()).hexdigest()
await adapter.Api.upload_file_fragmented_finish(fid, sha256)
Two-step segmented download: prepare → transfer (loop to retrieve segments)
| Method | Corresponding stage | Parameters | data Return |
|---|---|---|---|
get_file_fragmented_prepare(file_id) |
prepare |
file_id |
name, total_size, sha256 |
get_file_fragmented_transfer(file_id, offset, size) |
transfer |
file_id, offset: int, size: int |
data (bytes of this segment) |
3.6 Meta Actions
Meta actions are not specific to a particular account and do not require Using() to specify a Bot.
| Method | OB12 Action | Parameters | data Return |
|---|---|---|---|
get_latest_events(limit, timeout) |
get_latest_events |
limit: int=0, timeout: int=0 |
Array of event objects (excluding meta events) |
get_supported_actions() |
get_supported_actions |
None | list[str] supported action names |
get_status() |
get_status |
None | good: bool, bots: list[{self, online, ...}] |
get_version() |
get_version |
None | impl, version, onebot_version |
3.7 General Extension Actions
| Method | Description |
|---|---|
call(action, **params) |
Escape hatch for platform extension actions, following the OB12 extension naming convention {prefix}.{action} |
4. Usage
4.1 Basic Invocation
from ErisPulse import adapter
# Get user information (cross-platform unified)
result = await adapter.myplatform.Api.get_user_info("123456")
if result["status"] == "ok":
user_name = result["data"]["user_name"]
print(f"Username: {user_name}")
# Get group list
result = await adapter.myplatform.Api.get_group_list()
groups = result["data"]
# Recall message
await adapter.myplatform.Api.delete_message("msg_123456")
4.2 Specify Bot Account (Multi-account Mode)
# Execute operations using a specified Bot account
info = await adapter.myplatform.Api.Using("bot1").get_self_info()
4.3 Platform Extension Actions
# Call platform-specific extension actions (it is recommended to use the {prefix}.{action} naming convention)
result = await adapter.telegram.Api.call(
"telegram.send_sticker",
sticker_id="CAACAgIAAxkBAA...",
)
4.4 Using in Event Handlers
from ErisPulse.Core.Event import message
@message()
async def handle(event):
# Get sender's detailed information
user_id = event.get_user_id()
platform = event.get_platform()
result = await getattr(adapter, platform).Api.get_user_info(user_id)
if result["status"] == "ok":
user_name = result["data"]["user_name"]
await event.reply(f"Hello, {user_name}!")
5. Adapter Implementation
5.1 Default Behavior (Zero Configuration)
The default implementation of ApiDSL passes the standard action name directly as endpoint to adapter.call_api():
# The default implementation of ApiDSL is equivalent to:
async def get_user_info(self, user_id: str) -> dict:
return await self._adapter.call_api("get_user_info", user_id=user_id, account_id=self._account_id)
Applicable Scenarios: When the adapter's underlying backend itself follows the OneBot12 standard action protocol, call_api naturally supports standard action names (such as directly connecting to a service that follows this protocol).
5.2 Overriding Standard Methods (Mapping to Platform Native API)
The adapter can override individual standard methods, mapping them to the platform's native API:
class MyAdapter(BaseAdapter):
class Api(BaseAdapter.Api):
"""Standard API action implementation for MyPlatform"""
async def get_user_info(self, user_id: str) -> dict:
# Maps to the platform's native API
raw = await self._adapter._request("GET", f"/users/{user_id}")
if raw.get("code") != 0:
return self._adapter.make_error(retcode=34600, message="User does not exist")
user = raw["data"]
return self._adapter.make_response(
data={
"user_id": str(user["id"]),
"user_name": user.get("nick", ""),
"user_displayname": user.get("display_name", ""),
"user_remark": user.get("remark", ""),
},
raw=raw,
)
async def get_friend_list(self) -> dict:
raw = await self._adapter._request("GET", "/friends")
friends = [
{
"user_id": str(u["id"]),
"user_name": u.get("nick", ""),
"user_displayname": u.get("display_name", ""),
"user_remark": u.get("remark", ""),
}
for u in raw.get("data", [])
]
return self._adapter.make_response(data=friends, raw=raw)
5.3 Unsupported Actions
Standard methods not overridden by the adapter use the default implementation (delegated to call_api). If call_api does not support the action, it should return a standard error response:
async def call_api(self, endpoint: str, **params):
if endpoint not in self._supported_endpoints:
return self.make_error(retcode=10002, message=f"Unsupported action: {endpoint}")
# ... platform API call
Module developers can determine support by checking the retcode in the returned value:
result = await adapter.myplatform.Api.get_friend_list()
if result["retcode"] == 10002:
print("This platform does not support retrieving friend list")
6. Response Format
All ApiDSL methods return a standard API response format (see API Response Standard):
{
"status": "ok",
"retcode": 0,
"data": { ... },
"message_id": "",
"message": "",
"myplatform_raw": { ... }
}
Note: For information query actions,
message_idis an empty string (only message sending actions have amessage_id).
7. Relationship with SendDSL / RequestDSL
| Scenario | Use DSL | Example |
|---|---|---|
| Send message | Send |
adapter.Send.To("group", "123").Text("hi") |
| Accept/deny request | Request |
adapter.Request("req_id").accept() |
| Get user/group info | Api |
adapter.Api.get_user_info("123") |
| Recall message | Api |
adapter.Api.delete_message("msg_id") |
| Leave group | Api |
adapter.Api.leave_group("group_id") |
8. Adapter Implementation Checklist
Standard Actions
-
call_apican handle standard action names (or override correspondingApiDSLmethods) - Unsupported actions return
retcode=10002 - Return values follow the standard API response format
- The
datafield contains fields defined by the OB12 standard - Channel platforms must implement
get_guild_*/get_channel_*/leave_guild/leave_channel - Meta-actions (
get_status/get_version/get_supported_actions) are recommended to be implemented - File transfer uses
SendDSL.File(direct upload); file resource actions (upload_file/get_file/chunked) are not mandatory, only required if the backend hasfile_idresource capability and needs to pass through
Extended Actions
- Platform-specific extended actions use the
{prefix}.{action}naming convention - Parameters and responses for extended actions still follow the OB12 action request/response structure
9. Related Documents
- API Response Standard - Standard format for adapter API responses
- Send Method Specification - Naming and parameter conventions for methods in the Send class
- Request Action Specification - Usage of the Request DSL
- Event Conversion Standard - Event format and message segment standards