Blockabc
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    1
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # CCPay 商户接口文档-2.2 [English Version](https://hackmd.io/BsXiQAnRQLanw8tMj-EYxg?view) [中文版本](./) version 2.1 > 2.0 更新多一种支付回调,原 payto 接口的名称修改 payback,老版本的依然兼容 > 2.1 修改原来的 appKey 和 appSecret 名称为 businessKey 与 businessSecret > 2.2 增加一些校验说明以及增加 recordId 检测接口 [TOC] ### 接口域名 测试环境: https://paytest-api.cctip.io/ 正式环境: https://pay-api.cctip.io/ ### 公共的参数请求组成 请求体: * header,属于接口的`公共部分`: * reqId,每次请求的唯一 id,字母与数字的组合,不能含非法字符,字符数限制最多32个; * platform,机器人平台,比如: `telegram`; * businessKey,商户的唯一凭证; * signature,签名信息,生成方式见下面的`签名方式`小节。 * body: * 携带对应接口所要求的 json 参数 body 的例子: ```json { "user_bot_id": "", "coin": { "chain_id": 0, "contract": "" }, "origin_amount": "", "backup": "" } ``` ### 公共的返回结构 数据返回结构都是 Json,字段组成如下: * errno `整形`,是错误码,0 的时候,代表成功请求 * errmsg `字符串`,错误信息 * data 具体的数据,根据不同的接口而具体定义 ### 现支持的接入应用与平台类型 商家机器人: * 电报,platform 取值为: `telegram` CCTip·APP: * 电报,platform 取值为: `telegram` * 推特,platform 取值为: `twitter` * discord,platform 取值为: `discord` * reddit,platform 取值为: `reddit` * 苹果,platform 取值为: `apple` ### 签名方式 businessKey 和 businessSecret 将由 `CCPay` 提供给商户: * businessKey 唯一标识商户; * businessSecret 密钥 参数的签名步骤: 1. body 内 json 转 string 得 A,如果没有 body,那么不需要拼接它。这里还要注意一点,json 的参数顺序以具体接口中给出的为准,如果顺序改变了会导致验证签名失败; 2. `务必使用` "_" 按照格式下面例子格式进行拼接: `businessKey + _ + platform + _ + reqId + _ + A` ,拼接后得 Str; 3. 用 businessSecret 对 Str 进行生成签名 `signature`,这个`不要转大小写`,需要原样保存: ```golang signature = base64_encode(hash_hmac('sha1', Str, businessSecret)); ``` > 注:PHP 语言的开发者,hash_hmac 函数的第四个参数,raw_output 请设置为 true 线上签名调试工具网址:https://1024tools.com/hmac 下面是个例子 / Demo: ```txt 原文:74yfkb7q8rwfss6r1oo8u74s8t_{"attach":{"action":"income","amount":"1","chat_id":894669391,"message_id":"1627080","timestamp":1591670552,"token_name":"DOGE","user_id":"894669391","username":"qweazxcdddd"},"coin":{"chain_id":7,"contract":"D00000003"},"record_id":"b4a3a0d7a405174ebb290717907f2b829992ac9af9da43b3fbc0d579594a9f9f","tx_hash":"","type":3} ``` ```key 私钥:zhr9uexm6mnrxu1eukypgght64RSWFKPDTR8C1H1ZINMW5WAB8KO ``` ```result 结果:jf/sXfQccE0wDxE0hWCF88vtETE= ``` ### 接口列表 #### 1. 获取代币信息 > 该接口内所返回的 Token 信息,是当前 CCPay 所支持的,没在返回列表中的,证明不被支持,其它相关接口中的 `chain_id` 与 `contract` 的取值,请以该接口的为准。包含用户充值代币的合法性,也要以这里的为准,防止重复 Symbol 的代币充值攻击。 路由 | 方式 | 是否鉴权 | 是否限频 | 是否需要 header 参数 -|-|- | - |- /v1/ccpay/token/list | GET | 是 | 5s/次 | 是 | 参数: * body 无 返回 失败: ```json { "data": null, "errmsg": "param invalid", "errno": 100 } ``` 成功: ```json { "data": [{ "chain_id": 2, "name": "Bitcoin", "symbol": "BTC", "contract": "100000001", "decimals": 8, "platform": "twitter,wechat,telegram", "logo": "https://assets.coingecko.com/coins/images/1/large/bitcoin.png?1547033579", "max": "0", "min": "1", "fee": "10000", "confirmed": 2, "web_site": "" }, { "chain_id": 4, "name": "Bitcoin Cash", "symbol": "BCH", "contract": "100000002", "decimals": 8, "platform": "twitter,wechat,telegram", "logo": "https://assets.coingecko.com/coins/images/780/large/bitcoin_cash.png?1547034541", "max": "0", "min": "1", "fee": "10000", "confirmed": 2, "web_site": "" }], "errmsg": "", "errno": 0 } ``` #### 2. 创建充值订单 -- `已废弃` 该接口,允许商户帮用户生成要进行`链上充值`的相关信息。 路由 | 方式 | 是否鉴权 | 是否限频 | 是否需要 header 参数 -|-|- | - | - /v1/ccpay/order/deposit/submit | POST | 是 | 20ms/次 | 是 | 参数: 除 `backup` 外,都是必填; * user_bot_id 字符串,订单中,充值用户的基于机器人平台的 id * `chain_id` 整形,Token 所在链的id * `contract` 字符串,Token 的合约值 * `origin_amount` 字符串,订单中要充值的数值,`非精度放大值` ```json { "user_bot_id": "", "coin": { "chain_id": 0, "contract": "" }, "origin_amount": "2.3", "backup": "" } ``` 返回: 失败: ```json { "data": null, "errmsg": "param invalid", "errno": 100 } ``` 成功: * address 字符串,用户要充值 Token 到的地址; * fixed_amount_normal 字符串,要充值的数值,非精度放大值; * fixed_amount_big_val 字符串,要充值的数值,精度放大值; * confirmation 整形,该 Token 的充值后,在 CCTip 系统中所认定的区块确认数,达到该区块确认数,充值才会真实生效; * expire_at 字符串,订单的过期时间,单位毫秒,代表这个时间点后将过期; * record_id 字符串,订单的流水id,总是64位字符,每个被成功接收的订单,流水id 唯一; * memo 字符串,备注信息 ```json { "data": { "address": "0xA2d7Ef1C65d679c2D6770A4a356ad9A32d753396", "coin": { "amount": { "fixed_amount_normal": "2.7421", "fixed_amount_big_val": "2742100000000000000" }, "confirmation": 12, "chain_id": 1, "contract": "0x0000000000000000000000000000000000000000", "decimal": 18 }, "expire_at": "1586925482324", "record_id": "2eed99a4ed077ec4f0f3d93a8f8b95c05f962e90fff557dc7e692b2a1be3d686", "memo": "" }, "errmsg": "", "errno": 0 } ``` #### 3. 申请提现 --- 链上 --- `已废弃` 该接口允许商户将自己 CCTip 系统的 Token 资产从链上提现到用户指定的`链地址`。 路由 | 方式 | 是否鉴权 | 是否限频 | 是否需要 header 参数 -|-|- | - | - /v1/ccpay/withdraw | POST | 是 | 20ms/次 | 是 | 参数: 所有参数,都是必填 * to_bot_id 字符串,商户要将对应的 Token 提现到的用户,用户基于机器人平台的 id * `chain_id` 整形,要提现的 Token 所在链的id * `contract` 字符串,要提现的 Token 的合约值 * `amount` 字符串,提现的数值,`非精度放大值` * `address` 用户指定的提现地址 ```json { "coin": { "chain_id": 0, "contract": "" }, "to_bot_id": "", "amount": "2.43232" } ``` 返回: 失败: ```json { "data": null, "errmsg": "param invalid", "errno": 100 } ``` 成功: * record_id 提现的流水 id ```json { "data": { "record_id": "A2d7Ef1C65d679c2D6770A4a356ad9A32d753396" }, "errmsg": "", "errno": 0 } ``` #### 4. 申请转账 --- 非链上 该接口允许商户将自己的 Token 资产转账给指定的用户。请注意,这里的 payback 接口和用户在 `cctip_bot` 机器人私聊界面使用 `payto` 命令充值不是同一个。 路由 | 方式 | 是否鉴权 | 是否限频 | 是否需要 header 参数 -|-|- | - | - /v1/ccpay/payback | POST | 是 | 20ms/次 | 是 | 参数: 所有参数,除特殊说明,都是必填 > 下面的 `to_bot_id` 和 `to_sys_id` 填其一即可,如果都填了,以 to_sys_id 为主。 * to_bot_id 字符串,商户要将对应的 Token 提现到的用户,用户基于机器人平台的 id * to_sys_id 字符串,商户要将对应的 Token 提现到的用户,用户基于 cctip 系统的id * `chain_id` 整形,要提现的 Token 所在链的id * `contract` 字符串,要提现的 Token 的合约值 * `amount` 字符串,提现的数值,`非精度放大值` * `order_id` 可选参数,如果携带了,ccpay 会记录,当该接口处理请求成功了,那么本次的 order_id 不再可用。会返回重放错误。 ```json { "coin": { "chain_id": 0, "contract": "" }, "to_bot_id": "", "amount": "2.43232", "order_id": "xxxxxx" // 可选 } ``` 或 ```json { "coin": { "chain_id": 0, "contract": "" }, "to_sys_id": "", "amount": "2.43232", "order_id": "xxxxxx" // 可选 } ``` 返回: 失败: ```json { "data": null, "errmsg": "param invalid", "errno": 100 } ``` 成功: * record_id 提现的流水 id ```json { "data": { "record_id": "A2d7Ef1C65d679c2D6770A4a356ad9A32d753396" }, "errmsg": "", "errno": 0 } ``` #### 5. 查询商户余额 该接⼝允许商户查询⾃⼰的`商家账号`在 CCTip 系统中的 Token 余额。 > `注`:如果商户自己有链上提现系统,当用户在走自己的链上提现时,请务必使用该进行一次余额检查。 路由 | 方式 | 是否鉴权 | 是否限频 | 是否需要 header 参数 -|-|- | - | - /v1/ccpay/business/balance | POST | 是 | 20ms/次 | 是 | 参数: 所有参数,都是必填 * chain_id 整型,要查询的 Token 所在链的id * 如果 chain_id 为 0,那么会返回所有币种的余额 * contract 字符串,要查询的 Token 的合约值 ```json { "chain_id": 0, "contract": "" } ``` 失败: ```json { "data": null, "errmsg": "param invalid", "errno": 100 } ``` 成功: * confirmed 代表的是已 确认的 余额; * balance 是精度放⼤值 * price 是当前代币的市场价格,单位 `枚/美⾦` * unconfirmed 是待确认的 * locks 是被锁定的 ```json { "data": { "confirmed": [ { "balance": "279006620705932878", "chain_id": 1, "contract": "0x0000000000000000000000000000000000000000", "decimals": 18, "logo": "https://raw.githubusercontent.com/BlockABC/eth-tokens/master/tokens/0x000000000000000000 0000000000000000000000/token.png", "name": "Ethereum", "price": "187.57", "symbol": "ETH" }], "unconfirmed": [ { "balance": "9006620705932878", "chain_id": 1, "contract": "0x0000000000000000000000000000000000000000", "decimals": 18, "logo": "https://raw.githubusercontent.com/BlockABC/eth-tokens/master/tokens/0x000000000000000000 0000000000000000000000/token.png", "name": "Ethereum", "price": "187.57", "symbol": "ETH" }], "locks": [ { "balance": "69006620705932878", "chain_id": 1, "contract": "0x0000000000000000000000000000000000000000", "decimals": 18, "logo": "https://raw.githubusercontent.com/BlockABC/eth-tokens/master/tokens/0x000000000000000000 0000000000000000000000/token.png", "name": "Ethereum", "price": "187.57", "symbol": "ETH" }] }, "errmsg": "", "errno": 0 } ``` #### 6. 商户查询自己账户的链上充值地址 该接⼝允许商户查询⾃⼰的`商家账号`在 CCTip 系统中的所有支持链的钱包地址。 路由 | 方式 | 是否鉴权 | 是否限频 | 是否需要 header 参数 -|-|- | - | - /v1/ccpay/business/address | POST | 是 | 20ms/次 | 是 | 参数: * 无参数 失败: ```json { "data": null, "errmsg": "param invalid", "errno": 100 } ``` 成功: * address 就是地址 * chain_id 对应 token/list 接口中返回的链 id,标示了该地址是什么链的 > 注意:波场链的地址,暂时不能直接充值 ```json { "errno": 0, "errmsg": "", "data": [ { "address": "0x1234...", "chain_id": 1 }, { "address": "0x1234...", "chain_id": 1 } ] } ``` #### 7. 校验由 CCTip·APP 下发的 AccessToken 该接口允许商户在后台服务发送请求校验由 `CCTip·APP` 下发的 `AccessToken` 是否有效。 路由 | 方式 | 是否鉴权 | 是否限频 | 是否需要 header 参数 -|-|- | - | - /v1/ccpay/accesstoken/check | POST | 是 | 10ms/次 | 是 | 参数: 所有参数,除特殊说明,都是必填 * access_token ```json { "access_token": "xxxx" } ``` 返回: 失败: ```json { "data": null, "errmsg": "param invalid", "errno": 100 } ``` 成功: ```json { "data": { "sys_id": "xx", // 当前用户在 cctip 系统中的用户id "nickname": "", // 昵称 "avatar": "", // 头像 "sns_platform":"", // 社交平台 "sns_id":"" // 社交平台账户ID }, "errmsg": "", "errno": 0 } ``` #### 8. 检测充值订单是否已经到账 ---- 重要 该接口允许商户在后台服务发送请求检查 `RecordId` 对应的充值订单是否已经入账了。自2020-10-8下午开始,虽然说 `充/提回调` 通知处已经能保证充值是必然到账了才会回调,但是还是建议商户在收到回调或其它需要的时机,使用该接口对 RecordId 进行校验! > 注:调用该接口的时机最好是在接收到回调后几分钟内进行调用,如果时间过久才调用,可能会得到订单过期的结果。 路由 | 方式 | 是否鉴权 | 是否限频 | 是否需要 header 参数 -|-|- | - | - /v1/ccpay/record/check | POST | 是 | 20ms/次 | 是 | 参数: 所有参数,除特殊说明,都是必填 * record_id ```json { "record_id": "由回调返回的订单 record_id 参数" } ``` 返回: 失败: ```json { "data": null, "errmsg": "param invalid", "errno": 100 // 相关的其它错误码,见错误码表的 145 和 146 } ``` 成功: ```json { "data": { "record_id": "xx" // 原样返回 }, "errmsg": "", "errno": 0 } ``` #### 9. 根据用户的CCPay系统id获取用户信息 该接口允许商户在后台服务发送请求,根据CCPay的sys_id 来获取一些用户信息。 路由 | 方式 | 是否鉴权 | 是否限频 | 是否需要 header 参数 -|-|- | - | - /v1/ccpay/userinfo | POST | 是 | 20ms/次 | 是 | 参数: 所有参数,除特殊说明,都是必填 * sys_id ```json { "sys_id": "用户基于CCPay系统的id" } ``` 返回: 失败: ```json { "data": null, "errmsg": "param invalid", "errno": 100 } ``` 成功: ```json { "data": { "sys_id": "xx", // 原样返回 "nickname": "", // 昵称 "avatar": "", // 头像 "sns_platform":"", // 社交平台 "sns_id":"" // 社交平台账户ID }, "errmsg": "", "errno": 0 } ``` #### 10. 充 / 提回调 充 / 提回调,包含下面四种场景: 1. 当用户通过订单信息,在链上充值 Token 给商家成功了,CCPay 通知给商家; 2. 当商家给用户进行`链上提现`,到账的时候; 3. 平台用户在 CCTip 的 `telegram 机器人` 里使用 payto 命令给商家的 telegram 机器人充值时; 4. 用户在 `CCTip APP` 里面打开了商家的应用,进行了充值 Token 给商家; 5. 商户在 CCTip 中的某币种授信额度不足的时候,CCTip 通知商家。 --- 为了接收 CCPay 系统的回调,商户要提供一个满足下面要求的接口。 1. 链接:`https://example.com/some/path/ccpay/notify`,**注意以 /ccpay/notify 结尾**: 1. 合法例子:`https://ccpay.cctip.io/v1/ccpay/notify` 2. 非法例子:`http://47.23.44.252:81/ccpay/notify` 2. 方式:`POST` 3. 请求的参数: 1. header: 1. reqId,解析见`公共的参数请求组成` 小节的描述; 2. signature,签名信息,生成方式见第4点。 2. body 的 json: 1. type 回调类型: 1. 值为 1,对应上文的场景 1; 2. 值为 2,对应上文的场景 2; 3. 值为 3,对应上文的场景 3; 4. 值为 4,对应上文的场景 4; 5. 值为 5,对应上文的场景 5。 2. record_id 对应的操作流水id,用于对账; 3. tx_hash 对应充值交易的链上 hash 值,非链上操作的时候,它就会是空字符串; 4. attach 的数据体: * 类型 `3` 和 `4` 的时候,其内部的数据就是见下⾯解析: * action 动作,⽬前都是 income 字符串 * amount 数值,精度放小值 * app_id 当 type = 4 的时候,这个是商家应用对应的应用id * backup ,目前只有在 type = 4 的时候,才可能有值,对应商家在接入 `CCTip·APP` 接口时候的 nonce 字段值,它是透传的。 * chat_id 聊天的id,由第三⽅平台产⽣,可能为空 * platform 用户所处的第三方平台,仅仅当 type = 4 才会出现该字段,注意是出现,不是空字符串 * message_id 消息id,由第三⽅平台产⽣,,可能为空 * sys_id 触发相关操作的用户基于 CCTip 平台的用户id * timestamp 对应操作发⽣的时间戳,秒级别 * token_name 代币名称 * user_id ,触发相关操作的⽤户基于第三⽅平台的⽤户id,如果是 `CCTip APP` 的用户,则它对应 `CCTip APP` 提供的 `sns_id` * username ⽤户基于第三⽅平台的⽤户名 * 类型为 `5` 的时候,其内部的数据见下解析: * left_value 剩下的授信额度; * debt_value 负债的授信额度; * timestamp 授信提示的时间戳,单位秒。 5. 提示,如果要根据 `user_id` 来唯一确定一个用户,最好结合 `platfrom` 参数。 ```json { "attach": { "action": "income", "amount": "1", "app_id": "xxxx", "backup": "yyyy", "chat_id": -12334, "message_id": "2324", "platform": "telegram", // 只有当 type = 4 时才有该字段 "sys_id": "xxxx", "timestamp": 123242343, "token_name": "ETH", "user_id": "14214", "username": "lin_m" }, "coin": { "chain_id": 1, "contract": "0x000..." }, "record_id": "abc234...", "tx_hash": "0x123456...", "type": 3, } ``` ```json { "attach": { "debt_value": "0.02", "left_value": "0.005", "timestamp": 123242343 }, "coin": { "chain_id": 1, "contract": "0x000..." }, "record_id": "", "tx_hash": "", "type": 5, } ``` 4. 签名方式: 1. body 内 json 序列化为 bytes; 2. bytes 转 string 得 A,A 里面所对应的 json object 的顺序请按照上面例子进行解析,比如 attach 才到 coin,而不能是 coin 才到 attach; 3. 使用 "_" 拼接:`reqId + _ + A` 得 Str; 4. 用商户的 businessSecret 对 Str 进行生成签名 `signature` : 5. 商户要做的: 1. 对 reqId 的唯一性检测,避免被`重放攻击`; 2. 验证签名,在接收到请求参数后,对参数按照步骤4 使用自己的 businessSecret 进行生成签名 `signature_2`,然后比较 signature == signature_2,一致,那么证明请求信息没被篡改。 6. 签名代码例子: ```golang signature = base64_encode(hash_hmac('sha1', Str, businessSecret)); ``` 7. 收到回调请求后,CCPay 不关心商户的处理结果,无论处理成功还是失败,务必返回 `httpCode` 为 `200` 的响应给 CCPay ### 订单回调重试机制 CCPay 在回调商户的 `notify` 接口的时候,如果返回的响应,其 httpCode 不是 200,那么CCPay 将会认为该次请求不可达,它会将该次的请求信息存储,然后进行`策略性`的下次进行调用,所有的请求信息将会一样,包含 reqId 。在特定的重试次数后,同一回调依然失败,那么 CCPay 将`会记录`并`丢弃`该回调。 ### 错误码列表 数值 | 解析 -|-|- 20 | CCTip·APP 下发的 AccessToken 过期 或 非法 数值 | 解析 -|-|- 100 | 参数错误 101 | CCPay 内部服务错误 102 | 验证签名失败 103 | 接口访问次数限制 104 | 请求重放 105 | 不支持的平台 106 | 参数错误 110 | 转账余额不足 112 | 商户链下提现给用户,orderId 重放 120 | 充值订单不存在 数值 | 解析 -|-|- 145 | recordId 对应的订单,已经过期 146 | recordId 对应的订单,不存在 数值 | 解析 -|-|- 157 | 提现参数错误 158 | 提现系统内部错误 159 | 提现余额不足 160 | 提现的币种不支持 161 | 提现手续费不足 162 | TRON 链,提现地址不能是一个还没被创建过的地址 163 | TRON 链,提现地址不能是自己 164 | 申请提现记录不存在 165 | 链上提现功能维护 数值 | 解析 -|-|- 200X | 数据库操作错误

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully