diff --git a/docs/en/docs/api-reference/how-to-access-api.md b/docs/en/docs/api-reference/how-to-access-api.md index 07e13f20..570342fc 100644 --- a/docs/en/docs/api-reference/how-to-access-api.md +++ b/docs/en/docs/api-reference/how-to-access-api.md @@ -5,26 +5,28 @@ slug: /how-to-access-api sidebar_position: 1 --- -This section mainly introduces the basic information of Longbridge OpenAPI, including how to access the API, how to use the API, how to obtain the API interface document, etc., the content is relatively primitive. +This page is reorganized as a practical **OAuth 2.0 access flow** for new integrations. :::success Tip -It is recommended to directly use the SDK to access the API, the SDK has encapsulated the API call method, which is more convenient to use. +Prefer using SDKs for faster integration: https://open.longbridge.com/sdk ::: -## OAuth 2.0 (Current Recommendation) +## Notes + +| Precautions | Reference | +| --- | --- | +| Prefer SDKs over raw HTTP when possible | [SDK Quick Start](../docs/getting-started) | +| Enable required OpenAPI services first | [How to enable OpenAPI](../docs/#how-to-enable-openapi) | +| Understand permissions and restrictions | [Permissions and restrictions](../docs/#permissions-and-restrictions) | +| Check common error codes for troubleshooting | [Error Codes](../docs/error-codes) | -Use OAuth 2.0 for new integrations. It is simpler than the legacy `X-Api-Key` signature flow. +## OAuth 2.0 (Default) -### Quick path (recommended) +For new integrations, OAuth 2.0 is the default path. -1. Register OAuth client via `POST /oauth2/register` and obtain `client_id`. -2. Use the same `redirect_uri` in registration and authorization. -3. Open authorization URL and obtain `code`. -4. Exchange `code` for `access_token`. -5. Call APIs with `Authorization: Bearer `. -6. Refresh with `grant_type=refresh_token` when needed. +API-key signature mode can remain as a fallback for legacy compatibility, but it is not the default. ### Discovery endpoints @@ -36,7 +38,11 @@ Supported grant types (from discovery): - `authorization_code` - `refresh_token` -### 0) Register OAuth client +## OAuth 2.0 flow (step-by-step) + +### 1) Register OAuth client + +If there is no UI for client creation in your environment, register dynamically: ```bash curl -X POST https://openapi.longportapp.com/oauth2/register \ @@ -49,9 +55,9 @@ curl -X POST https://openapi.longportapp.com/oauth2/register \ }' ``` -> Registration may return only `client_id` (public client, no `client_secret`). In this case, use PKCE and omit `client_secret` in token requests. +> Registration may return only `client_id` (public client, no `client_secret`). In this case, use PKCE and do not send `client_secret` in token requests. -### 1) Build authorization URL +### 2) Build authorization URL and get `code` ```text https://openapi.longportapp.com/oauth2/authorize @@ -64,13 +70,13 @@ https://openapi.longportapp.com/oauth2/authorize &code_challenge_method=S256 ``` -After consent, callback receives: +After user consent, callback receives: ```text YOUR_REDIRECT_URI?code=AUTH_CODE&state=YOUR_RANDOM_STATE ``` -### 2) Exchange code for token +### 3) Exchange `code` for `access_token` ```bash curl -X POST https://openapi.longportapp.com/oauth2/token \ @@ -80,292 +86,51 @@ curl -X POST https://openapi.longportapp.com/oauth2/token \ -d "redirect_uri=YOUR_REDIRECT_URI" \ -d "code=AUTH_CODE" \ -d "code_verifier=YOUR_CODE_VERIFIER" -# add this only when your client has secret: +# only when your client has secret: # -d "client_secret=YOUR_CLIENT_SECRET" ``` -### 3) Call API with Bearer token +### 4) Call API with Bearer token (TSLA.US example) ```bash -curl -X GET "https://openapi.longportapp.com/v1/asset/account" \ +curl -X GET "https://openapi.longportapp.com/v1/quote/get_security_list?market=US&category=Overnight" \ -H "Authorization: Bearer ACCESS_TOKEN" ``` -### 4) Refresh token - -```bash -curl -X POST https://openapi.longportapp.com/oauth2/token \ - -H "Content-Type: application/x-www-form-urlencoded" \ - -d "grant_type=refresh_token" \ - -d "client_id=YOUR_CLIENT_ID" \ - -d "refresh_token=REFRESH_TOKEN" -# add this only when your client has secret: -# -d "client_secret=YOUR_CLIENT_SECRET" -``` - -### TypeScript / Python examples - -For production projects, use mature OAuth2 client libraries (`simple-oauth2`, `requests-oauthlib`) to handle token exchange / refresh and then call APIs with Bearer tokens. - -:::tip -The `X-Api-Key` + `X-Api-Signature` sections below are legacy compatibility references. New integrations should use OAuth 2.0. -::: - - -## Notes - -| Precautions | Reference Documents | -| ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -| It is recommended to use the SDK of the respective language, instead of calling the native interface | [SDK Quick Start Page](../docs/getting-started) | -| Read the OpenAPI introduction to enable the corresponding service | [How to enable OpenAPI](../docs/#how-to-enable-openapi) | -| Read about OpenAPI access and restrictions in OpenAPI Introduction | [OpenAPI's permissions and restrictions](../docs/#permissions-and-restrictions) | -| Common Error Codes for finding errors in interface calls | [Common Error Codes](../docs/error-codes) | - -## REST API documentation convention format - -The main format of the server REST API documentation is as follows. - -``` -Request: - Request Info - Parameters - Request Example -Response: - Response Headers - Response Example - Response Status -Response Status -``` - -### Request Info - -This section introduces the request method and path required to call the API. - -- HTTP URL: The URL of the server API. -- HTTP Method: The server API only supports HTTP protocol methods, such as GET, POST, etc. - -### Parameters - -Introduces the request headers, query parameters or request body to be passed to call the API. -:::tip - -Parameters are query parameters by default for GET API, parameters are request bodies by default for not GET API, and the request body format is JSON. - -::: - -### Request Example - -Detailed example of calling an interface using the SDK. - -### Response - -- Response Headers: Returns content header information. -- Response Example: Returns a text example of the content. -- Response Status: Interface returns a specific explanation of the `status` of the content. - -## API access process - -### 1. Enable OpenAPI service - -Refer to [Introduction to OpenAPI](../docs#how-to-enable) to enable the corresponding services. - -### 2. Get App Key and Access Token information - -Get **Access Token**, **App Key** and **App Secret** on the [Developer Website](https://open.longbridge.com/account). - -**Access Token** will expires in three months. Token can be reset in Developer Website after expiration. Also token can be refresh through invoking [Refresh Token](./refresh-token-api) API before token expired. - -### 3. Calculate signature - -:::tip - -Most of the content introduced on this page has been fully implemented in our OpenAPI SDK. If you are an SDK user, you can directly ignore the signature authentication part. - -This section is intended as a reference for non-SDK users. - -::: - -After constructing a request based on an corresponding API documentation, call the API directly through the OpenAPI SDK, which will help generate a signature, or create a signature through the following process. - -#### Add `X-Api-Key`、`X-Timestamp`、`Authorization` on headers - -Set the request parameter header information, and `X-Api-Key`, `Authorization`, `X-Timestamp` will be used in the signature function. - -```python -import time -headers = {} -headers['X-Api-Key'] = '${app_key}' -headers['Authorization'] = '${access_token}' -headers['X-Timestamp' = str(time.time()) # Unix Timestamp, eg: 1539095200.123 -headers['Content-Type'] = 'application/json; charset=utf-8', -``` - -#### Sign requests - -The example of signature function: - -```py -# signature function on python3 -def sign(method, uri, headers, params, body, secret): - ts = headers["X-Timestamp"] - access_token = headers["Authorization"] - app_key = headers["X-Api-Key"] - mtd = method.upper() - - canonical_request = mtd + "|" + uri + "|" + params + "|authorization:" + access_token + "\nx-api-key:" + app_key + "\nx-timestamp:" + ts + "\n|authorization;x-api-key;x-timestamp|" - - if body != "": - payload_hash = hashlib.sha1(body.encode("utf-8")).hexdigest() - canonical_request = canonical_request + payload_hash - - sign_str = "HMAC-SHA256|" + hashlib.sha1(canonical_request.encode("utf-8")).hexdigest() - signature = hmac.new(secret.encode('utf-8'), sign_str.encode('utf-8'), digestmod=hashlib.sha256).hexdigest() - return "HMAC-SHA256 SignedHeaders=authorization;x-api-key;x-timestamp, Signature=" + signature - -``` - -Sign the request and set the signature in the request header `X-Api-Signature`. - -```py -# request method -method = "POST" -# request path -uri = "/v1/trade/order/submit" -# request params, for example member_id=1&account_channel=2 -params = "" -# request body -body = json.dumps({ "order_id": '683615454870679552' }) -# signing requests and set signature it on the X-Api-Signature -headers['X-Api-Signature'] = sign(method, uri, headers, params, body, secret) - -``` - -### 4. Call API - -Use the HTTP client to send signed requests. - -## API Path - -All API paths start with [https://openapi.longportapp.com](https://openapi.longportapp.com). - -> TIP: You can also use https://openapi.longportapp.com - -## API Request - -The call to the server-side interface needs to be in HTTPS protocol, JSON format, and encoded in `UTF-8`. - -For a test example: - -```bash -curl -v https://openapi.longportapp.com/v1/test \ - -H "X-Api-Signature: {signature}" -H "X-Api-Key: {AppKey}" \ - -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" -``` - -The method of Get Stock Positions interface is `GET` and needs to set query parameters. The example is as follows: - -```bash -curl -v https://openapi.longportapp.com/v1/asset/stock?symbol=700.HK&symbol=BABA.US \ - -H "X-Api-Signature: {Signature}" -H "X-Api-Key: {AppKey}" \ - -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" -``` - -The method of Submit Order interface is `POST` and needs to set the request body. The example is as follows: - -```bash -curl -v -XPOST https://openapi.longportapp.com/v1/trade/order \ - -d '{ "side": "Buy", symbol": "700.HK", "order_type": "LO", "submitted_price": "50", "submitted_quantity": "200", "time_in_force": " Day", remark": "Hello from Shell"}' \ - -H "X-Api-Signature: {Signature}" -H "X-Api-Key: {AppKey}" \ - -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" - -H "Content-Type: application/json; charset=utf-8" -``` - -## API Response - -All API corresponding body structures consist of `code`, `message`, `data`. `code` is the business code, `message` is the error message, and `data` is the request result. - -:::tip -HTTP Status follows [RESTFull style](https://restfulapi.net/http-status-codes) and `code = 0` if the request succeeds, otherwise `code` will describe the specific error code. -::: - -### HTTP Status - -- 1xx: Informational – Communicates transfer protocol-level information. -- 2xx: Success – Indicates that the client's request was accepted successfully. -- 3xx: Redirection – Indicates that the client must take some additional action in order to complete their request. -- 4xx: Client Error – This category of error status codes points the finger at clients. -- 5xx: Server Error – The server takes responsibility for these error status codes. - -For example, the response body of a successful request: +Real response (excerpt, keeping `TSLA.US` row): ```json { "code": 0, - "msg": "success", + "message": "success", "data": { - // ... + "list": [ + { + "symbol": "TSLA.US", + "name_cn": "特斯拉", + "name_hk": "", + "name_en": "" + } + ] } } ``` -the response body of a failed request: +### 5) Refresh token -```json -{ - "code": 403201, - "msg": "signature invalid" -} +Use OAuth token endpoint for refresh (details in [Refresh Token](./refresh-token-api)): + +```bash +curl -X POST https://openapi.longportapp.com/oauth2/token \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "grant_type=refresh_token" \ + -d "client_id=YOUR_CLIENT_ID" \ + -d "refresh_token=REFRESH_TOKEN" +# only when your client has secret: +# -d "client_secret=YOUR_CLIENT_SECRET" ``` -## A code demo to call the API - -```py -import requests -import json -import time -import hashlib -import hmac - -# request information -# request method -method = "POST" -# request path -uri = "/v1/trade/order/submit" -# request params, for example member_id=1&account_channel=2 -params = "" -# request body -body = json.dumps({ "order_id": '683615454870679552' }) -# request headers -headers = {} -headers['X-Api-Key'] = '${app_key}' -headers['Authorization'] = '${access_token}' -headers['X-Timestamp'] = str(time.time()) # Unix TimeStamp, eg. 1539095200.123 -headers['Content-Type'] = 'application/json; charset=utf-8' - -# App Secret -app_secret = "${app_secret}" - -## signature function -def sign(method, uri, headers, params, body, secret): - ts = headers["X-Timestamp"] - access_token = headers["Authorization"] - app_key = headers["X-Api-Key"] - mtd = method.upper() - canonical_request = mtd + "|" + uri + "|" + params + "|authorization:" + access_token + "\nx-api-key:" + app_key + "\nx-timestamp:" + ts + "\n|authorization;x-api-key;x-timestamp|" - if body != "": - payload_hash = hashlib.sha1(body.encode("utf-8")).hexdigest() - canonical_request = canonical_request + payload_hash - sign_str = "HMAC-SHA256|" + hashlib.sha1(canonical_request.encode("utf-8")).hexdigest() - - signature = hmac.new(secret.encode('utf-8'), sign_str.encode('utf-8'), digestmod=hashlib.sha256).hexdigest() - return "HMAC-SHA256 SignedHeaders=authorization;x-api-key;x-timestamp, Signature=" + signature - -# set signature header -headers['X-Api-Signature'] = sign(method, uri, headers, params, body, app_secret) - -# call an API -response = requests.request(method, "https://openapi.longportapp.com" + uri + '?' + params, headers=headers, data=body) - -print(response.text) +## Relationship with legacy docs -``` +- This page: OAuth 2.0 main flow for new integrations. +- [Refresh Token](./refresh-token-api): refresh step details only, to avoid duplication. diff --git a/docs/en/docs/api-reference/refresh-token-api.md b/docs/en/docs/api-reference/refresh-token-api.md index e564d06d..d2d2eb17 100644 --- a/docs/en/docs/api-reference/refresh-token-api.md +++ b/docs/en/docs/api-reference/refresh-token-api.md @@ -5,70 +5,58 @@ slug: /refresh-token-api sidebar_position: 2 --- -# Refresh Access Token +# Refresh Token (OAuth 2.0) -For OAuth 2.0 clients, token refresh is recommended via the OAuth token endpoint with `grant_type=refresh_token`: +This page focuses only on the OAuth 2.0 **refresh token** step. -- `https://openapi.longportapp.com/oauth2/token` +- If you have not completed the full flow yet, read [How to Access API](./how-to-access-api) first. +- This page does not repeat client registration / authorization code steps. -This page documents the legacy refresh API (`/v1/token/refresh`) kept for compatibility. +## Recommended refresh method (OAuth 2.0) -Call this to get a new `access_token` before the old `access_token` expires. The old `access_token` will be invalidated after a successful call. +Use OAuth token endpoint: -> Lasted 2022-04-21 +- `POST https://openapi.longportapp.com/oauth2/token` +- or China: `POST https://openapi.longportapp.cn/oauth2/token` -## Request +### Request parameters (`application/x-www-form-urlencoded`) -| Basic Information | | -| ----------------- | ----------------- | -| HTTP URL | /v1/token/refresh | -| HTTP Method | GET | -| Permission | Not required | +| Name | Required | Description | +| --- | --- | --- | +| grant_type | Yes | Must be `refresh_token` | +| client_id | Yes | OAuth client id | +| refresh_token | Yes | Previously issued refresh token | +| client_secret | Optional | Required only for confidential clients; omit for public clients | -### Request Headers +### Refresh example -| Name | Type | Required | Description | -| ------------- | ------ | -------- | ----------- | -| Authorization | string | Yes | | - -### Request Parameters - -| Name | Type | Required | Description | Example | -| ---------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------ | ------------------------ | -| expired_at | string | Yes | Expiration timestamp, formatted according to [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) specification | 2023-04-14T12:13:57.859Z | - -## Response - -### Response Body - -| Name | Type | Description | -| ----------------- | ------ | ---------------------------------- | -| code | int | Error code, non-zero means failure | -| msg | string | Error message | -| data | object | | -| ∟token | string | new access_token | -| ∟expired_at | string | access_token expired time | -| ∟issued_at | string | issued time | -| ∟account_info | object | user info | -| ∟∟member_id | string | user id | -| ∟∟aaid | string | aaid | -| ∟∟account_channel | string | account_channel | +```bash +curl -X POST https://openapi.longportapp.com/oauth2/token \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "grant_type=refresh_token" \ + -d "client_id=YOUR_CLIENT_ID" \ + -d "refresh_token=YOUR_REFRESH_TOKEN" +# only when your client has secret: +# -d "client_secret=YOUR_CLIENT_SECRET" +``` -### Response Example +### Response example ```json { - "code": 0, - "message": "", - "data": { - "token": "xxxxxx", - "expired_at": "2022-05-14T12:13:57.859Z", - "issued_at": "2022-04-14T12:13:57.859Z", - "account_info": { - "member_id": 123, - "aaid": 13, - "account_channel": "lb" - } - } + "access_token": "...", + "refresh_token": "...", + "expires_in": 2592000, + "token_type": "Bearer" } ``` + +## How this page differs from the main flow page + +- [How to Access API](./how-to-access-api): complete onboarding flow (register, authorize, exchange token, call API, refresh). +- This page: refresh token request details only. + +## Compatibility note + +Legacy `/v1/token/refresh` remains for backward compatibility. +For new integrations, use OAuth 2.0 token endpoint as default. diff --git a/docs/zh-CN/docs/api-reference/how-to-access-api.md b/docs/zh-CN/docs/api-reference/how-to-access-api.md index 5f32b76d..55fa9424 100644 --- a/docs/zh-CN/docs/api-reference/how-to-access-api.md +++ b/docs/zh-CN/docs/api-reference/how-to-access-api.md @@ -5,26 +5,26 @@ slug: /how-to-access-api sidebar_position: 1 --- -本部分内容主要介绍 Longbridge OpenAPI 的基础信息,包括如何访问 API、如何使用 API、如何获取 API 接口文档等,内容比较原始。 +本页按 **OAuth 2.0 实际接入流程** 重新整理,用于新接入用户快速走通。 :::success 提示 -建议可以直接采用 SDK 的方式访问 API,SDK 已经封装了 API 的调用方式,使用起来更加方便。 +优先使用 SDK,接入更简单: https://open.longbridge.com/sdk ::: -## OAuth 2.0(当前推荐) +## API 须知 -新接入建议使用 OAuth 2.0。相比后面的 `X-Api-Key` 签名方式,OAuth 2.0 更简单、接入成本更低。 +| 注意事项 | 参考文档 | +| -------------------------------------------- | ------------------------------------------------- | +| 推荐使用各自语言的 SDK,而不是调用原生的接口 | [SDK 快速开始页面](../docs/getting-started) | +| 阅读 OpenAPI 介绍中开通相应服务 | [OpenAPI 如何开通](../docs/#如何开通) | +| 阅读 OpenAPI 介绍中使用权限及限制 | [OpenAPI 使用权限及限制](../docs/#使用权限及限制) | +| 了解通用错误码,便于查找调用接口出错的原因 | [通用错误码](../docs/error-codes) | -### 推荐接入路径 +## OAuth 2.0(推荐方案) -1. 通过 `POST /oauth2/register` 注册 OAuth 客户端,获取 `client_id`。 -2. 注册与授权步骤使用同一个 `redirect_uri`。 -3. 打开授权链接,拿到 `code`。 -4. 用 `code` 换取 `access_token`。 -5. 用 `Authorization: Bearer ` 调用 API。 -6. 通过 `grant_type=refresh_token` 刷新 token。 +新接入默认使用 OAuth 2.0。API Key 签名方式作为备选兼容方案可保留(例如在 SDK/历史实现中),但不作为默认接入方式。 ### Discovery 地址 @@ -36,7 +36,11 @@ https://open.longbridge.com/sdk - `authorization_code` - `refresh_token` -### 0)注册 OAuth 客户端 +## OAuth 2.0 接入流程(一步一步) + +### 1)注册 OAuth 客户端 + +如果没有可视化后台入口,可通过接口动态注册: ```bash curl -X POST https://openapi.longportapp.com/oauth2/register \ @@ -49,9 +53,9 @@ curl -X POST https://openapi.longportapp.com/oauth2/register \ }' ``` -> 注册返回可能仅有 `client_id`(public client,不含 `client_secret`)。这种情况请使用 PKCE,并在 token 请求中不传 `client_secret`。 +> 注册返回可能仅包含 `client_id`(public client,不返回 `client_secret`)。这种情况下请使用 PKCE,并在 token 请求里不传 `client_secret`。 -### 1)构造授权链接 +### 2)构造授权链接并获取 code ```text https://openapi.longportapp.com/oauth2/authorize @@ -64,13 +68,13 @@ https://openapi.longportapp.com/oauth2/authorize &code_challenge_method=S256 ``` -授权完成后回调: +用户授权后,回调地址会收到: ```text YOUR_REDIRECT_URI?code=AUTH_CODE&state=YOUR_RANDOM_STATE ``` -### 2)用 code 换 token +### 3)用 code 换 access_token ```bash curl -X POST https://openapi.longportapp.com/oauth2/token \ @@ -80,290 +84,51 @@ curl -X POST https://openapi.longportapp.com/oauth2/token \ -d "redirect_uri=YOUR_REDIRECT_URI" \ -d "code=AUTH_CODE" \ -d "code_verifier=YOUR_CODE_VERIFIER" -# 仅当你的客户端有 secret 时再加: +# 仅当客户端有 secret 时再加: # -d "client_secret=YOUR_CLIENT_SECRET" ``` -### 3)用 Bearer token 调 API +### 4)用 Bearer token 调 API(TSLA.US 实例) ```bash -curl -X GET "https://openapi.longportapp.com/v1/asset/account" \ +curl -X GET "https://openapi.longportapp.com/v1/quote/get_security_list?market=US&category=Overnight" \ -H "Authorization: Bearer ACCESS_TOKEN" ``` -### 4)刷新 token - -```bash -curl -X POST https://openapi.longportapp.com/oauth2/token \ - -H "Content-Type: application/x-www-form-urlencoded" \ - -d "grant_type=refresh_token" \ - -d "client_id=YOUR_CLIENT_ID" \ - -d "refresh_token=REFRESH_TOKEN" -# 仅当你的客户端有 secret 时再加: -# -d "client_secret=YOUR_CLIENT_SECRET" -``` - -### TypeScript / Python 示例 - -生产项目建议使用成熟 OAuth2 客户端库(`simple-oauth2`、`requests-oauthlib`)处理换 token / 刷新,再用 Bearer token 调用 API。 - -:::tip -后文 `X-Api-Key` + `X-Api-Signature` 是历史兼容说明。新接入请优先使用 OAuth 2.0。 -::: - - -## API 须知 - -| 注意事项 | 参考文档 | -| -------------------------------------------- | ------------------------------------------------- | -| 推荐使用各自语言的 SDK,而不是调用原生的接口 | [SDK 快速开始页面](../docs/getting-started) | -| 阅读 OpenAPI 介绍中开通相应服务 | [OpenAPI 如何开通](../docs/#如何开通) | -| 阅读 OpenAPI 介绍中使用权限及限制 | [OpenAPI 使用权限及限制](../docs/#使用权限及限制) | -| 了解通用错误码,便于查找调用接口出错的原因 | [通用错误码](../docs/error-codes) | - -## REST API 文档约定格式 - -服务端 REST API 文档格式主要如下: - -``` -Request: - Request Info - Parameters - Request Example -Response: - Response Headers - Response Example - Response Status -``` - -### Request Info - -介绍调用 API 所需要的请求方式、路径。 - -- HTTP URL:服务端 API 的 URL。 -- HTTP Method:服务端 API 仅支持 HTTP 协议的方法,如 GET、POST 等。 - -### Parameters - -介绍调用 API 所需传递的请求头部,查询参数或者请求体。 -:::tip - -GET 请求时默认所有参数为查询参数,非 GET 请求时默认所有参数都是请求体,请求体格式为 JSON。 - -::: - -### Request Example - -使用 SDK 调用接口的详细例子。 - -### Response - -- Response Headers: 返回内容头部信息。 -- Response Example: 返回内容的文本示例。 -- Response Status: 接口返回内容中的 `status` 的具体解释。 - -## API 调用流程 - -### 1. 开通服务 - -参考 [OpenAPI 介绍](../docs/#如何开通) 开通相应服务。 - -### 2. 获取 App Key 信息及 Access Token - -在 [开发者后台](https://open.longbridge.com/account) 中获取 **Access Token**, **App Key** 以及 **App Secret**。 - -**Access Token** 的有效期是三个月,失效后可以在开发者后台重置。在失效之前,可以通过调用 [刷新 Access Token](./refresh-token-api) API 进行刷新。 - -### 3. 生成签名 - -:::tip - -本页介绍的内容大部分,我们的 [OpenAPI SDK](/sdk) 已经完整实现了,你如果是 [SDK](/sdk) 用户,可以直接忽略签名认证部分。 - -此部分内容是为了给非 SDK 用户提供参考。 - -::: - -先根据相应的 API 文档构造请求后,通过 OpenAPI SDK 直接调用 API,SDK 会帮助生成签名,或者通过以下流程创建签名。 - -#### 添加 `X-Api-Key`、`X-Timestamp`、`Authorization` - -设置请求参数头部信息, `X-Api-Key`、 `Authorization`、`X-Timestamp` 将在签名函数中被使用。 - -```python -import time -headers = {} -headers['X-Api-Key'] = '${app_key}' -headers['Authorization'] = '${access_token}' -headers['X-Timestamp' = str(time.time()) # Unix Timestamp, eg: 1539095200.123 -headers['Content-Type'] = 'application/json; charset=utf-8', -``` - -#### 使用签名函数对请求签名 - -签名函数如下: - -```py -# python3 签名函数 -def sign(method, uri, headers, params, body, secret): - ts = headers["X-Timestamp"] - access_token = headers["Authorization"] - app_key = headers["X-Api-Key"] - mtd = method.upper() - - canonical_request = mtd + "|" + uri + "|" + params + "|authorization:" + access_token + "\nx-api-key:" + app_key + "\nx-timestamp:" + ts + "\n|authorization;x-api-key;x-timestamp|" - - if body != "": - payload_hash = hashlib.sha1(body.encode("utf-8")).hexdigest() - canonical_request = canonical_request + payload_hash - - sign_str = "HMAC-SHA256|" + hashlib.sha1(canonical_request.encode("utf-8")).hexdigest() - signature = hmac.new(secret.encode('utf-8'), sign_str.encode('utf-8'), digestmod=hashlib.sha256).hexdigest() - return "HMAC-SHA256 SignedHeaders=authorization;x-api-key;x-timestamp, Signature=" + signature - -``` - -使用签名函数进行签名,并设置签名到请求头部 `X-Api-Signature` 中: - -```py -# 请求方法 -method = "POST" -# 请求路径 -uri = "/v1/trade/order/submit" -# 请求参数 如 member_id=1&account_channel=2 -params = "" -# 请求 body 如 -body = json.dumps({ "order_id": '683615454870679552' }) -# 签名并设置 -headers['X-Api-Signature'] = sign(method, uri, headers, params, body, secret) - -``` - -### 4. 调用 API - -使用 HTTP 客户端发送签名过后的请求。 - -## 基本路径 - -- HTTP API - `https://openapi.longportapp.com` -- WebSocket - `wss://openapi-quote.longportapp.com` - -## API Request - -调用服务端接口需要是用 HTTPS 协议,JSON 格式,并是用 `UTF-8` 编码。 - -测试接口示例如下: - -```bash -curl -v https://openapi.longportapp.com/v1/test \ - -H "X-Api-Signature: {签名}" -H "X-Api-Key: {Appkey}" \ - -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" -``` - -获取股票持仓接口是`GET`请求并需要传递参数,示例如下: - -```bash -curl -v https://openapi.longportapp.com/v1/asset/stock?symbol=700.HK&symbol=BABA.US \ - -H "X-Api-Signature: {签名}" -H "X-Api-Key: {AppKey}" \ - -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" -``` - -委托下单接口是`POST`请求并需要传递`Body`参数,示例如下: - -```bash -curl -v -XPOST https://openapi.longportapp.com/v1/trade/order \ - -d '{ "side": "Buy", symbol": "700.HK", "order_type": "LO", "submitted_price": "50", "submitted_quantity": "200", "time_in_force": "Day", remark": "Hello from Shell"}' \ - -H "X-Api-Signature: {签名}" -H "X-Api-Key: {AppKey}" \ - -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" - -H "Content-Type: application/json; charset=utf-8" -``` - -## API Response - -所有 API 相应体结构都包括 `code`, `message`, `data` 三个部分。`code` 是业务码,`message` 是 message,`data` 是请求结果。 - -:::tip -HTTP Status 遵循 [RESTFull 风格](https://restfulapi.net/http-status-codes),请求成功时 `code = 0`, 否则 `code` 会描述具体的错误码。 -::: - -### HTTP Status - -- 1xx: Informational – Communicates transfer protocol-level information. -- 2xx: Success – Indicates that the client's request was accepted successfully. -- 3xx: Redirection – Indicates that the client must take some additional action in order to complete their request. -- 4xx: Client Error – This category of error status codes points the finger at clients. -- 5xx: Server Error – The server takes responsibility for these error status codes. - -例如,请求成功,Response Body +实际返回(节选,保留 `TSLA.US` 项): ```json { "code": 0, - "msg": "success", + "message": "success", "data": { - // ... + "list": [ + { + "symbol": "TSLA.US", + "name_cn": "特斯拉", + "name_hk": "", + "name_en": "" + } + ] } } ``` -例如,失败的 Response Body - -```json -{ - "code": 403201, - "msg": "signature invalid" -} -``` - -## 完整的调用 API 例子 - -```py -import requests -import json -import time -import hashlib -import hmac - -# request 请求信息 -# 请求方法 -method = "POST" -# 请求路径 -uri = "/v1/trade/order/submit" -# 请求参数 如 member_id=1&account_channel=2 -params = "" -# 请求 body -body = json.dumps({ "order_id": '683615454870679552' }) -# 请求头部信息 -headers = {} -headers['X-Api-Key'] = '${app_key}' -headers['Authorization'] = '${access_token}' -headers['X-Timestamp'] = str(time.time()) # Unix TimeStamp, eg. 1539095200.123 -headers['Content-Type'] = 'application/json; charset=utf-8' - -# App Secret -app_secret = "${app_secret}" +### 5)刷新 token -## 签名方法 -def sign(method, uri, headers, params, body, secret): - ts = headers["X-Timestamp"] - access_token = headers["Authorization"] - app_key = headers["X-Api-Key"] - mtd = method.upper() - canonical_request = mtd + "|" + uri + "|" + params + "|authorization:" + access_token + "\nx-api-key:" + app_key + "\nx-timestamp:" + ts + "\n|authorization;x-api-key;x-timestamp|" - if body != "": - payload_hash = hashlib.sha1(body.encode("utf-8")).hexdigest() - canonical_request = canonical_request + payload_hash - sign_str = "HMAC-SHA256|" + hashlib.sha1(canonical_request.encode("utf-8")).hexdigest() +通过 OAuth token endpoint 刷新(详见 [刷新 Token](./refresh-token-api)): - signature = hmac.new(secret.encode('utf-8'), sign_str.encode('utf-8'), digestmod=hashlib.sha256).hexdigest() - return "HMAC-SHA256 SignedHeaders=authorization;x-api-key;x-timestamp, Signature=" + signature - -# 设置签名 -headers['X-Api-Signature'] = sign(method, uri, headers, params, body, app_secret) - -# 请求接口 -response = requests.request(method, "https://openapi.longportapp.com" + uri + '?' + params, headers=headers, data=body) +```bash +curl -X POST https://openapi.longportapp.com/oauth2/token \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "grant_type=refresh_token" \ + -d "client_id=YOUR_CLIENT_ID" \ + -d "refresh_token=REFRESH_TOKEN" +# 仅当客户端有 secret 时再加: +# -d "client_secret=YOUR_CLIENT_SECRET" +``` -print(response.text) +## 与旧文档的关系 -``` +- 本页:只讲 **OAuth 2.0 主流程**(新接入默认看这里)。 +- [刷新 Token](./refresh-token-api):只讲刷新步骤细节与常见问题,避免重复。 diff --git a/docs/zh-CN/docs/api-reference/refresh-token-api.md b/docs/zh-CN/docs/api-reference/refresh-token-api.md index 7a5a5e7d..867ee868 100644 --- a/docs/zh-CN/docs/api-reference/refresh-token-api.md +++ b/docs/zh-CN/docs/api-reference/refresh-token-api.md @@ -5,69 +5,57 @@ slug: /refresh-token-api sidebar_position: 2 --- -# 刷新 Access Token +# 刷新 Token(OAuth 2.0) -对于 OAuth 2.0 客户端,推荐通过 OAuth token endpoint 使用 `grant_type=refresh_token` 刷新: +本页仅说明 OAuth 2.0 的 **refresh token** 刷新步骤。 -- `https://openapi.longportapp.com/oauth2/token` +- 如果你还没走完完整授权流程,请先看:[如何访问 API](./how-to-access-api) +- 本页不重复注册 client / 获取 code 的流程,只关注“刷新”这一步 -本文档记录的是兼容保留的旧刷新接口(`/v1/token/refresh`)。 +## 推荐刷新方式(OAuth 2.0) -在老的 `access_token` 过期之前,通过调用此接口获取新的 `access_token`。调用成功后老的 `access_token` 就会作废。 +使用 OAuth token endpoint: -> 最后更新于 2022-04-21 +- `POST https://openapi.longportapp.com/oauth2/token` +- 或中国内地:`POST https://openapi.longportapp.cn/oauth2/token` -## 请求 +### 请求参数(`application/x-www-form-urlencoded`) -| 基本信息 | | -| ----------- | ----------------- | -| HTTP URL | /v1/token/refresh | -| HTTP Method | GET | +| 名称 | 必须 | 说明 | +| ------------- | ---- | ---- | +| grant_type | 是 | 固定为 `refresh_token` | +| client_id | 是 | OAuth client id | +| refresh_token | 是 | 上一次签发的 refresh token | +| client_secret | 否 | 仅机密客户端需要;public client 不传 | -### 请求头 +### 刷新示例 -| 名称 | 类型 | 必须 | 描述 | -| ------------- | ------ | ---- | ---- | -| Authorization | string | 是 | | - -### 请求参数 - -| 名称 | 类型 | 必须 | 描述 | 默认值 | 示例 | -| ---------- | ------ | ---- | ---- | --------------------------------------------------------------------------- | ------------------------ | -| expired_at | string | 是 | 格式 | 过期时间戳,格式遵循 [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) 规范 | 2023-04-14T12:13:57.859Z | - -## 响应 - -### 响应体 - -| 名称 | 类型 | 描述 | -| ----------------- | ------ | --------------------- | -| code | int | 错误码,非 0 表示失败 | -| msg | string | 错误描述 | -| data | object | | -| ∟token | string | 新的 access_token | -| ∟expired_at | string | 过期的时间戳 | -| ∟issued_at | string | 颁发时间 | -| ∟account_info | object | 用户信息 | -| ∟∟member_id | string | 用户 id | -| ∟∟aaid | string | aaid | -| ∟∟account_channel | string | account_channel | +```bash +curl -X POST https://openapi.longportapp.com/oauth2/token \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "grant_type=refresh_token" \ + -d "client_id=YOUR_CLIENT_ID" \ + -d "refresh_token=YOUR_REFRESH_TOKEN" +# 仅当你的客户端有 secret 时再加: +# -d "client_secret=YOUR_CLIENT_SECRET" +``` -### 响应体示例 +### 响应示例 ```json { - "code": 0, - "message": "", - "data": { - "token": "xxxxxx", - "expired_at": "2022-05-14T12:13:57.859Z", - "issued_at": "2022-04-14T12:13:57.859Z", - "account_info": { - "member_id": 123, - "aaid": 13, - "account_channel": "lb" - } - } + "access_token": "...", + "refresh_token": "...", + "expires_in": 2592000, + "token_type": "Bearer" } ``` + +## 如何消除和主流程文档的重复 + +- [如何访问 API](./how-to-access-api):负责完整接入流程(注册、授权、换 token、调用 API、刷新) +- 本页:只保留 refresh token 的参数与示例,作为“步骤 5”的深入说明 + +## 兼容说明 + +历史接口 `/v1/token/refresh` 属于旧方案兼容路径,不建议新接入继续采用。新接入请统一使用 OAuth 2.0 token endpoint。 diff --git a/docs/zh-HK/docs/api-reference/how-to-access-api.md b/docs/zh-HK/docs/api-reference/how-to-access-api.md index 3fac43ed..b82c030c 100644 --- a/docs/zh-HK/docs/api-reference/how-to-access-api.md +++ b/docs/zh-HK/docs/api-reference/how-to-access-api.md @@ -5,38 +5,44 @@ slug: /how-to-access-api sidebar_position: 1 --- -本部分內容主要介紹 Longbridge OpenAPI 的基礎訊息,包括如何存取 API、如何使用 API、如何取得 API 介面文件等,內容較為原始。 +本頁按 **OAuth 2.0 實際接入流程** 重新整理,供新接入者快速走通。 :::success 提示 -建議可以直接採用 SDK 的方式存取 API,SDK 已經封裝了 API 的呼叫方式,使用起來更方便。 +建議優先使用 SDK,接入更簡單: https://open.longbridge.com/sdk ::: -## OAuth 2.0(目前推薦) +## API 須知 + +| 注意事項 | 參考文件 | +| --- | --- | +| 建議使用各語言 SDK,而非直接呼叫原生介面 | [SDK 快速開始](../docs/getting-started) | +| 先開通對應 OpenAPI 服務 | [OpenAPI 如何開通](../docs/#如何開通) | +| 先了解權限與限制 | [OpenAPI 使用權限及限制](../docs/#使用權限及限制) | +| 出錯時先查通用錯誤碼 | [通用錯誤碼](../docs/error-codes) | -新接入建議使用 OAuth 2.0。相比後文 `X-Api-Key` 簽名方式,OAuth 2.0 更簡單。 +## OAuth 2.0(預設方案) -### 推薦接入路徑 +新接入預設使用 OAuth 2.0。 -1. 透過 `POST /oauth2/register` 註冊 OAuth client,取得 `client_id`。 -2. 註冊與授權步驟使用同一個 `redirect_uri`。 -3. 打開授權連結取得 `code`。 -4. 以 `code` 換取 `access_token`。 -5. 使用 `Authorization: Bearer ` 呼叫 API。 -6. 透過 `grant_type=refresh_token` 刷新 token。 +API-key 簽名方式可作為舊系統相容備選,但不作為預設接入方式。 ### Discovery 位址 - 生產環境:`https://openapi.longportapp.com/.well-known/oauth-authorization-server` - 中國內地:`https://openapi.longportapp.cn/.well-known/oauth-authorization-server` -支援授權類型(以 Discovery 為準): +支援授權類型(以 Discovery 回傳為準): - `authorization_code` - `refresh_token` -### 0)註冊 OAuth client +## OAuth 2.0 接入流程(逐步) + +### 1)註冊 OAuth client + +若目前環境沒有可視化建立頁面,可透過接口動態註冊: ```bash curl -X POST https://openapi.longportapp.com/oauth2/register \ @@ -49,9 +55,9 @@ curl -X POST https://openapi.longportapp.com/oauth2/register \ }' ``` -> 註冊回傳可能僅有 `client_id`(public client,不含 `client_secret`)。此情況請使用 PKCE,並在 token 請求中不傳 `client_secret`。 +> 註冊回傳可能只有 `client_id`(public client,不含 `client_secret`)。此情況請使用 PKCE,且 token 請求中不要傳 `client_secret`。 -### 1)組裝授權連結 +### 2)組裝授權連結並取得 code ```text https://openapi.longportapp.com/oauth2/authorize @@ -64,13 +70,13 @@ https://openapi.longportapp.com/oauth2/authorize &code_challenge_method=S256 ``` -授權完成後回調: +使用者授權後,回調會帶回: ```text YOUR_REDIRECT_URI?code=AUTH_CODE&state=YOUR_RANDOM_STATE ``` -### 2)用 code 換 token +### 3)用 code 換 access_token ```bash curl -X POST https://openapi.longportapp.com/oauth2/token \ @@ -80,291 +86,51 @@ curl -X POST https://openapi.longportapp.com/oauth2/token \ -d "redirect_uri=YOUR_REDIRECT_URI" \ -d "code=AUTH_CODE" \ -d "code_verifier=YOUR_CODE_VERIFIER" -# 僅當你的 client 有 secret 時再加: +# 只有 client 有 secret 時才加: # -d "client_secret=YOUR_CLIENT_SECRET" ``` -### 3)用 Bearer token 呼叫 API +### 4)用 Bearer token 呼叫 API(TSLA.US 示例) ```bash -curl -X GET "https://openapi.longportapp.com/v1/asset/account" \ +curl -X GET "https://openapi.longportapp.com/v1/quote/get_security_list?market=US&category=Overnight" \ -H "Authorization: Bearer ACCESS_TOKEN" ``` -### 4)刷新 token - -```bash -curl -X POST https://openapi.longportapp.com/oauth2/token \ - -H "Content-Type: application/x-www-form-urlencoded" \ - -d "grant_type=refresh_token" \ - -d "client_id=YOUR_CLIENT_ID" \ - -d "refresh_token=REFRESH_TOKEN" -# 僅當你的 client 有 secret 時再加: -# -d "client_secret=YOUR_CLIENT_SECRET" -``` - -### TypeScript / Python 範例 - -實務建議使用成熟 OAuth2 客戶端庫(`simple-oauth2`、`requests-oauthlib`)處理換 token / 刷新,再以 Bearer token 呼叫 API。 - -:::tip -後文 `X-Api-Key` + `X-Api-Signature` 為舊式相容說明。新接入請優先使用 OAuth 2.0。 -::: - - -## API 須知 - -| 注意事項 | 參考文檔 | -| -------------------------------------------- | ------------------------------------------------- | -| 推薦使用各自語言的 SDK,而不是調用原生的接口 | [SDK 快速開始頁面](../docs/getting-started) | -| 閱讀 OpenAPI 介紹中開通相應服務 | [OpenAPI 如何開通](../docs/#如何開通) | -| 閱讀 OpenAPI 介紹中使用權限及限制 | [OpenAPI 使用權限及限制](../docs/#使用權限及限制) | -| 了解通用錯誤碼,便於查找調用接口出錯的原因 | [通用錯誤碼](../docs/error-codes) | - -## REST API 文檔約定格式 - -服務端 REST API 文檔格式主要如下: - -``` -Request: - Request Info - Parameters - Request Example -Response: - Response Headers - Response Example - Response Status -``` - -### Request Info - -介紹調用 API 所需要的請求方式、路徑。 - -- HTTP URL:服務端 API 的 URL。 -- HTTP Method:服務端 API 僅支持 HTTP 協議的方法,如 GET、POST 等。 - -### Parameters - -介紹調用 API 所需傳遞的請求頭部,查詢參數或者請求體。 -:::tip - -GET 請求時默認所有參數為查詢參數,非 GET 請求時默認所有參數都是請求體,請求體格式為 JSON。 - -::: - -### Request Example - -使用 SDK 調用接口的詳細例子。 - -### Response - -- Response Headers: 返回內容頭部信息。 -- Response Example: 返回內容的文本示例。 -- Response Status: 接口返回內容中的 `status` 的具體解釋。 - -## API 調用流程 - -### 1. 開通服務 - -參考 [OpenAPI 介紹](../docs/#如何開通) 開通相應服務。 - -### 2. 獲取 App Key 信息及 Access Token - -在 [開發者後台](https://open.longbridge.com/account) 中獲取 **Access Token**, **App Key** 以及 **App Secret**。 - -**Access Token** 的有效期是三個月,失效後可以在開發者後臺重置。在失效之前,可以通過調用 [刷新 Access Token](./refresh-token-api) API 進行刷新。 - -### 3. 生成簽名 - -:::tip - -本頁介紹的內容大部分,我們的 [OpenAPI SDK](/sdk) 已經完整實現了,你如果是 SDK 用戶,可以直接忽略簽名認證部分。 - -此部分內容是為了給非 SDK 用戶提供參考。 - -::: - -先根據相應的 API 文檔構造請求後,通過 OpenAPI SDK 直接調用 API,SDK 會幫助生成簽名,或者通過以下流程創建簽名。 - -#### 添加 `X-Api-Key`、`X-Timestamp`、`Authorization` - -設置請求參數頭部信息, `X-Api-Key`、 `Authorization`、`X-Timestamp` 將在簽名函數中被使用。 - -```python -import time -headers = {} -headers['X-Api-Key'] = '${app_key}' -headers['Authorization'] = '${access_token}' -headers['X-Timestamp' = str(time.time()) # Unix Timestamp, eg: 1539095200.123 -headers['Content-Type'] = 'application/json; charset=utf-8', -``` - -#### 使用簽名函數對請求籤名 - -簽名函數如下: - -```py -# python3 簽名函數 -def sign(method, uri, headers, params, body, secret): - ts = headers["X-Timestamp"] - access_token = headers["Authorization"] - app_key = headers["X-Api-Key"] - mtd = method.upper() - - canonical_request = mtd + "|" + uri + "|" + params + "|authorization:" + access_token + "\nx-api-key:" + app_key + "\nx-timestamp:" + ts + "\n|authorization;x-api-key;x-timestamp|" - - if body != "": - payload_hash = hashlib.sha1(body.encode("utf-8")).hexdigest() - canonical_request = canonical_request + payload_hash - - sign_str = "HMAC-SHA256|" + hashlib.sha1(canonical_request.encode("utf-8")).hexdigest() - signature = hmac.new(secret.encode('utf-8'), sign_str.encode('utf-8'), digestmod=hashlib.sha256).hexdigest() - return "HMAC-SHA256 SignedHeaders=authorization;x-api-key;x-timestamp, Signature=" + signature - -``` - -使用簽名函數進行簽名,並設置簽名到請求頭部 `X-Api-Signature` 中: - -```py -# 請求方法 -method = "POST" -# 請求路徑 -uri = "/v1/trade/order/submit" -# 請求參數 如 member_id=1&account_channel=2 -params = "" -# 請求 body 如 -body = json.dumps({ "order_id": '683615454870679552' }) -# 簽名並設置 -headers['X-Api-Signature'] = sign(method, uri, headers, params, body, secret) - -``` - -### 4. 調用 API - -使用 HTTP 客戶端發送簽名過後的請求。 - -## 基本路徑 - -所有 API 的路徑都以 [https://openapi.longportapp.com](https://openapi.longportapp.com) 開頭。 - -> TIP: 也可以用 https://openapi.longportapp.com - -## API Request - -調用服務端接口需要是用 HTTPS 協議,JSON 格式,並是用 `UTF-8` 編碼。 - -測試接口示例如下: - -```bash -curl -v https://openapi.longportapp.com/v1/test \ - -H "X-Api-Signature: {簽名}" -H "X-Api-Key: {Appkey}" \ - -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" -``` - -獲取股票持倉接口是`GET`請求並需要傳遞參數,示例如下: - -```bash -curl -v https://openapi.longportapp.com/v1/asset/stock?symbol=700.HK&symbol=BABA.US \ - -H "X-Api-Signature: {簽名}" -H "X-Api-Key: {AppKey}" \ - -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" -``` - -委託下單接口是`POST`請求並需要傳遞`Body`參數,示例如下: - -```bash -curl -v -XPOST https://openapi.longportapp.com/v1/trade/order \ - -d '{ "side": "Buy", symbol": "700.HK", "order_type": "LO", "submitted_price": "50", "submitted_quantity": "200", "time_in_force": "Day", remark": "Hello from Shell"}' \ - -H "X-Api-Signature: {簽名}" -H "X-Api-Key: {AppKey}" \ - -H "Authorization: {AccessToken}" -H "X-Timestamp: 1539095200.123" - -H "Content-Type: application/json; charset=utf-8" -``` - -## API Response - -所有 API 相應體結構都包括 `code`, `message`, `data` 三個部分。 `code` 是業務碼,`message` 是 message,`data` 是請求結果。 - -:::tip -HTTP Status 遵循 [RESTFull 風格](https://restfulapi.net/http-status-codes),請求成功時 `code = 0`, 否則 `code` 會描述具體的錯誤碼。 -::: - -### HTTP Status - -- 1xx: Informational – Communicates transfer protocol-level information. -- 2xx: Success – Indicates that the client's request was accepted successfully. -- 3xx: Redirection – Indicates that the client must take some additional action in order to complete their request. -- 4xx: Client Error – This category of error status codes points the finger at clients. -- 5xx: Server Error – The server takes responsibility for these error status codes. - -例如,請求成功,Response Body +實際回應(節選,保留 `TSLA.US`): ```json { "code": 0, - "msg": "success", + "message": "success", "data": { - // ... + "list": [ + { + "symbol": "TSLA.US", + "name_cn": "特斯拉", + "name_hk": "", + "name_en": "" + } + ] } } ``` -例如,失敗的 Response Body +### 5)刷新 token -```json -{ - "code": 403201, - "msg": "signature invalid" -} +使用 OAuth token endpoint 刷新(詳見 [刷新 Token](./refresh-token-api)): + +```bash +curl -X POST https://openapi.longportapp.com/oauth2/token \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "grant_type=refresh_token" \ + -d "client_id=YOUR_CLIENT_ID" \ + -d "refresh_token=REFRESH_TOKEN" +# 只有 client 有 secret 時才加: +# -d "client_secret=YOUR_CLIENT_SECRET" ``` -## 完整的調用 API 例子 - -```py -import requests -import json -import time -import hashlib -import hmac - -# request 請求信息 -# 請求方法 -method = "POST" -# 請求路徑 -uri = "/v1/trade/order/submit" -# 請求參數 如 member_id=1&account_channel=2 -params = "" -# 請求 body -body = json.dumps({ "order_id": '683615454870679552' }) -# 請求頭部信息 -headers = {} -headers['X-Api-Key'] = '${app_key}' -headers['Authorization'] = '${access_token}' -headers['X-Timestamp'] = str(time.time()) # Unix TimeStamp, eg. 1539095200.123 -headers['Content-Type'] = 'application/json; charset=utf-8' - -# App Secret -app_secret = "${app_secret}" - -## 簽名方法 -def sign(method, uri, headers, params, body, secret): - ts = headers["X-Timestamp"] - access_token = headers["Authorization"] - app_key = headers["X-Api-Key"] - mtd = method.upper() - canonical_request = mtd + "|" + uri + "|" + params + "|authorization:" + access_token + "\nx-api-key:" + app_key + "\nx-timestamp:" + ts + "\n|authorization;x-api-key;x-timestamp|" - if body != "": - payload_hash = hashlib.sha1(body.encode("utf-8")).hexdigest() - canonical_request = canonical_request + payload_hash - sign_str = "HMAC-SHA256|" + hashlib.sha1(canonical_request.encode("utf-8")).hexdigest() - - signature = hmac.new(secret.encode('utf-8'), sign_str.encode('utf-8'), digestmod=hashlib.sha256).hexdigest() - return "HMAC-SHA256 SignedHeaders=authorization;x-api-key;x-timestamp, Signature=" + signature - -# 設置簽名 -headers['X-Api-Signature'] = sign(method, uri, headers, params, body, app_secret) - -# 請求接口 -response = requests.request(method, "https://openapi.longportapp.com" + uri + '?' + params, headers=headers, data=body) - -print(response.text) +## 與舊文檔的分工 -``` +- 本頁:只講 OAuth 2.0 主流程(新接入預設看這裡)。 +- [刷新 Token](./refresh-token-api):只講刷新步驟細節,避免重複。 diff --git a/docs/zh-HK/docs/api-reference/refresh-token-api.md b/docs/zh-HK/docs/api-reference/refresh-token-api.md index 12f2fa97..6f25bdb0 100644 --- a/docs/zh-HK/docs/api-reference/refresh-token-api.md +++ b/docs/zh-HK/docs/api-reference/refresh-token-api.md @@ -5,69 +5,57 @@ slug: /refresh-token-api sidebar_position: 2 --- -# 刷新 Access Token +# 刷新 Token(OAuth 2.0) -對於 OAuth 2.0 客戶端,建議透過 OAuth token endpoint 使用 `grant_type=refresh_token` 進行刷新: +本頁僅說明 OAuth 2.0 的 **refresh token** 刷新步驟。 -- `https://openapi.longportapp.com/oauth2/token` +- 若尚未完成完整流程,請先看:[如何訪問 API](./how-to-access-api) +- 本頁不重複註冊 client / 取得 code,只聚焦刷新步驟 -本文檔記錄的是兼容保留的舊刷新接口(`/v1/token/refresh`)。 +## 推薦刷新方式(OAuth 2.0) -在老的 `access_token` 過期之前,通過調用此接口獲取新的 `access_token`。調用成功後老的 `access_token` 就會作廢。 +使用 OAuth token endpoint: -> 最後更新於 2022-04-21 +- `POST https://openapi.longportapp.com/oauth2/token` +- 或中國內地:`POST https://openapi.longportapp.cn/oauth2/token` -## 請求 +### 請求參數(`application/x-www-form-urlencoded`) -| 基本信息 | | -| ----------- | ----------------- | -| HTTP URL | /v1/token/refresh | -| HTTP Method | GET | +| 名稱 | 必須 | 說明 | +| --- | --- | --- | +| grant_type | 是 | 固定為 `refresh_token` | +| client_id | 是 | OAuth client id | +| refresh_token | 是 | 上次簽發的 refresh token | +| client_secret | 否 | 僅機密型 client 需要;public client 不傳 | -### 請求頭 +### 刷新示例 -| 名稱 | 類型 | 必須 | 描述 | -| ------------- | ------ | ---- | ---- | -| Authorization | string | 是 | | - -### 請求參數 - -| 名稱 | 類型 | 必須 | 描述 | 默認值 | 示例 | -| ---------- | ------ | ---- | ---- | --------------------------------------------------------------------------- | ------------------------ | -| expired_at | string | 是 | 格式 | 過期時間戳,格式遵循 [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) 規範 | 2023-04-14T12:13:57.859Z | - -## 響應 - -### 響應體 - -| 名稱 | 類型 | 描述 | -| ----------------- | ------ | --------------------- | -| code | int | 錯誤碼,非 0 表示失敗 | -| msg | string | 錯誤描述 | -| data | object | | -| ∟token | string | 新的 access_token | -| ∟expired_at | string | 過期的時間戳 | -| ∟issued_at | string | 頒發時間 | -| ∟account_info | object | 用戶信息 | -| ∟∟member_id | string | 用戶 id | -| ∟∟aaid | string | aaid | -| ∟∟account_channel | string | account_channel | +```bash +curl -X POST https://openapi.longportapp.com/oauth2/token \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "grant_type=refresh_token" \ + -d "client_id=YOUR_CLIENT_ID" \ + -d "refresh_token=YOUR_REFRESH_TOKEN" +# 僅當你的 client 有 secret 時再加: +# -d "client_secret=YOUR_CLIENT_SECRET" +``` -### 響應體示例 +### 回應示例 ```json { - "code": 0, - "message": "", - "data": { - "token": "xxxxxx", - "expired_at": "2022-05-14T12:13:57.859Z", - "issued_at": "2022-04-14T12:13:57.859Z", - "account_info": { - "member_id": 123, - "aaid": 13, - "account_channel": "lb" - } - } + "access_token": "...", + "refresh_token": "...", + "expires_in": 2592000, + "token_type": "Bearer" } ``` + +## 如何與主流程文檔消歧 + +- [如何訪問 API](./how-to-access-api):完整接入流程(註冊、授權、換 token、呼叫 API、刷新) +- 本頁:僅保留 refresh token 的參數與示例(對應主流程第 5 步) + +## 相容說明 + +舊接口 `/v1/token/refresh` 僅作歷史相容保留;新接入請統一使用 OAuth 2.0 token endpoint。