Sign inGet Started

通过 API 注册 SMS 发送方

有些国家只投递来自已为该国注册的发送方的 SMS。通过 API,你可以认领发送方,为目标国家创建其注册,并提交该注册要求的材料,步骤与控制台相同。注册一经创建就可能收取开通费,因此请先检查价格和钱包余额。

开始之前

  • 一个 API 密钥,需具备写入级别的 sms_management 以创建发送方和注册,以及写入级别的 compliance 以提交其材料。
  • 如需先检查价格和钱包余额,需要一个委托用户 OAuth 令牌,详见检查注册价格和钱包余额。API 密钥无法读取组织账单信息。

示例从 BIRD_API_KEY 读取你的密钥,从 BIRD_API_URL 读取其区域主机,从 COUNTRY_CODE 读取目标国家,并在获得注册的 scr_ 标识符后从 REGISTRATION_ID 读取它。

检查注册价格和钱包余额

要显示与控制台相同的价格和钱包信息,请使用 GET /v1/organization/billing/prices/resolve 和 GET /v1/organization/billing/wallets。这些读取操作需要具备 org:billing:read 的委托用户 OAuth 令牌。工作区 API 密钥、组织主密钥和服务账号令牌都无法授予这一组织账单权限。

使用 OAuth 受保护资源发现和授权服务器元数据获取 issuer、registration_endpoint、authorization_endpoint 和 token_endpoint,详见 OAuth 发现。在发现的 registration_endpoint 注册你自己的公共 OAuth 客户端,提供 client_name、redirect_uris 和 token_endpoint_auth_method: "none"。将用户引导至发现的 authorization_endpoint,并附带该 client_id、response_type=code、你注册的 redirect_uri、新生成的 state、scope=org:billing:read、由你的验证器派生的 code_challenge 以及 code_challenge_method=S256。在授权同意页面上,用户选择目标组织中的一个工作区,并在其角色允许时授予 org:billing:read。将 state 与你发送的值进行校验,将 iss 与发现得到的签发方进行校验,然后在发现的 token_endpoint 用 grant_type=authorization_code、返回的 code、client_id、相同的 redirect_uri 和原始的 code_verifier 换取令牌。将得到的访问令牌用作 BIRD_OAUTH_TOKEN。遵守其 expires_in;安全存储刷新令牌,并在每次刷新成功后替换它。每个刷新令牌只能使用一次,因此请串行执行刷新尝试。刷新授权过期或被撤销时,请重新授权。

该令牌绑定到所选工作区及其所属组织;账单读取操作作用于该组织。X-Organization-Id 无法将其切换到其他组织;如需其他组织,请为该组织重新授权。使用此令牌配置 SDK 时,请显式设置区域主机。

对于字母数字 SMS 发送方,使用目标国家/地区查询其注册设置价格:

代码示例
curl --get "$BIRD_API_URL/v1/organization/billing/prices/resolve" \
  --header "Authorization: Bearer $BIRD_OAUTH_TOKEN" \
  --data-urlencode 'product_slug=sms_sender_registration' \
  --data-urlencode "dimensions[country_code]=$COUNTRY_CODE" \
  --data-urlencode 'dimensions[sender_type]=alphanumeric'

curl "$BIRD_API_URL/v1/organization/billing/wallets" \
  --header "Authorization: Bearer $BIRD_OAUTH_TOKEN"

使用相同的维度查询 product_slug=sms_sender,获取周期性价格。要执行与控制台相同的余额检查,请将设置价格响应中的 gross_price.amount 与首次周期性费用相加,首次周期性费用为周期性价格响应中的 gross_price.amount 乘以其 intervals_per_charge。将该总额与 data 中某个钱包的 balance 进行比较,该钱包的 currency_code 须与两个价格的 gross_price.currency_code 一致。请使用十进制运算,不要对返回的金额进行舍入。如果总额超过余额,差额即为资金缺口;请在创建注册之前充值,或确认您组织的信用安排。服务器在最终的支付能力检查中还会考虑信用额度。这些读取操作显示的是当前价格和资金,不会预留资金,也不会批准注册。

获取要提交材料的注册

  1. 使用 GET /v1/sms/senders 或 GET /v1/sms/senders/{sender_id} 查找发送方。如有需要,使用 POST /v1/sms/senders 创建发送方。
  2. 读取目标国家/地区的 GET /v1/sms/senders/{sender_id}/requirements,并按照其中的 next 步骤操作。如果要求您创建注册,请先按照检查注册价格和钱包资金中的说明检查价格,然后使用 country_code 调用 POST /v1/sms/senders/{sender_id}/registrations。
  3. 再次读取发送方要求,将该行的 registration_id(scr_)保存为 REGISTRATION_ID,并将其 program 保存为 PROGRAM。仅当该行的 has_compliance_requirements 为 true 时才提交材料;当其为 false 时,表示该注册无需提交,或由专门的计划负责,此时请改为按照该行的 next 操作。免费电话号码验证和 10DLC 等专门计划有各自的步骤。

读取发送方需要 sms_management:read;创建发送方和注册需要 sms_management:write。为其提交材料还需要 compliance:write。

提交注册材料

本节适用于 has_compliance_requirements 为 true 的注册。

使用 GET /v1/compliance/requirements 读取该注册所要求的内容,其中 subject_kind 设为 sms_sender,subject_id 设为该注册:

代码示例
curl "$BIRD_API_URL/v1/compliance/requirements?subject_kind=sms_sender&subject_id=$REGISTRATION_ID&country_code=$COUNTRY_CODE&program=$PROGRAM" \
  --header "Authorization: Bearer $BIRD_API_KEY"

这些字段的含义与号码注册时相同;读取国家/地区的要求对每个字段都有说明,上传每份文件介绍了 document 字段所要求的文件。使用 POST /v1/compliance/submissions 提交所有答案,并将该注册指定为提交对象:

代码示例
curl --request POST "$BIRD_API_URL/v1/compliance/submissions" \
  --header "Authorization: Bearer $BIRD_API_KEY" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: sender-$REGISTRATION_ID" \
  --data '{
    "subject_kind": "sms_sender",
    "subject_id": "'"$REGISTRATION_ID"'",
    "program": "'"$PROGRAM"'",
    "country_code": "'"$COUNTRY_CODE"'",
    "answers": [{ "key": "legal_entity_name", "value": "Goldcrest Communications Inc" }]
  }'

示例仅展示了一个答案;请为每个 required 为 true 的字段发送一个条目,对于有实际答案的可选字段也同样发送,详见提交所有答案。201 响应会返回该提交;请保存其 csb_ id。发送方没有 ownership 字段,因此要跟踪审核进度,请使用 GET /v1/compliance/submissions/{submission_id} 读取该提交,其中的答案带有 state,被拒绝时还带有 reason;或者再次读取发送方要求,查看注册状态。使用 POST /v1/compliance/submissions/{submission_id}/resupply 替换被拒绝的答案,具体参见更正被拒绝的答案。

后续步骤