Nextsms

开发者中心

一套 API 打通国内与国际短信。多语言示例、免费沙箱与实时状态回执,让接入最快半天完成。

Open API

一套接口,短信能力全部开放

接口、控制台与监控一应俱全,按你的技术栈自由选择接入方式。

HTTP 开放接口

无需安装任何组件、不保持长连接,一个 HTTP 请求即可完成提交与结果回收。

支持单条 / 批量 / 变量 / 一对一四种提交方式;发送状态与用户上行回复可主动拉取,也可配好回调地址由平台推送;余额可实时查询。

凭据与下方接入参数完全共用(sp_id 即账号,密码即 API 密码);国内产品内容须以已报备【签名】开头。

9 个开放接口 4 种提交方式 报告 / 上行 拉取推送双模式 7 种语言代码示例

REST API

标准 HTTP 接口,一次接入同时支持国内与国际通道,返回结构与错误码统一。

状态回执与上行

发送状态与用户上行回复可拉取也可推送,回调签名校验与失败重试开箱即用,接入不依赖任何额外组件。

控制台与监控

发送记录、状态回执与用量报表实时可见,支持失败告警与子账号权限隔离。

Quickstart

几行代码,发出第一条短信

下列示例取自官方接口文档、与线上实现逐行一致,覆盖 7 种语言:凭据准备、单条发送、状态报告拉取与解析。把 sp_id 与 API 密码换成开发者页「接入参数」里的真实值即可直接运行。

<?php
$BASE    = 'https://user.arkai.site/api/v1/open'; // 开发者页文档顶部的接口基地址
$SP_ID   = '669736';    // 开发者页「SPID / system_id」
$API_PWD = 'a1b2c3d4';  // 开发者页「密码」(8 位)

// 服务端百分号编码基于 JS encodeURIComponent:! ' ( ) ~ 保留原样、* 编成 %2A、空格为 %20,
// rawurlencode 会把 ! ' ( ) 编掉,故需还原(内容里出现半角 ! 或括号时签名才不会错)
function percentEncode($s) {
    return str_replace(['%21', '%27', '%28', '%29'], ['!', "'", '(', ')'], rawurlencode((string) $s));
}

// signature 鉴权(可选):字典序拼串 → METHOD&%2F&QueryString → HmacSHA1(密钥=API 密码原文) → base64
function makeSignature($method, array $params) {
    global $API_PWD;
    unset($params['signature']);
    ksort($params, SORT_STRING);
    $pairs = [];
    foreach ($params as $k => $v) {
        $pairs[] = percentEncode($k) . '=' . percentEncode($v);
    }
    $strToSign = strtoupper($method) . '&' . percentEncode('/') . '&' . implode('&', $pairs);
    return base64_encode(hash_hmac('sha1', $strToSign, $API_PWD, true));
}

function call($path, array $params, $method = 'POST') {
    global $BASE;
    $ch = curl_init();
    if ($method === 'POST') {
        curl_setopt_array($ch, [
            CURLOPT_URL => $BASE . $path,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => http_build_query($params),
            CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded; charset=UTF-8'],
        ]);
    } else {
        curl_setopt($ch, CURLOPT_URL, $BASE . $path . '?' . http_build_query($params));
    }
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15]);
    $body = curl_exec($ch);
    if ($body === false) { $e = curl_error($ch); curl_close($ch); throw new Exception('HTTP 请求失败: ' . $e); }
    curl_close($ch);
    return json_decode($body, true);
}

// 1. 单条发送(password = API 密码的 md5,PHP md5() 本身就是 32 位小写十六进制)
$send = [
    'sp_id'    => $SP_ID,
    'password' => md5($API_PWD),
    'mobile'   => '176xxxxxxxxx',
    'content'  => '【测试签名】您的验证码是123456', // 国内产品必须带已报备签名
];
// 改用 signature 鉴权:unset($send['password']); $send['signature'] = makeSignature('POST', $send);
var_dump(call('/send-sms-single', $send));

// 2. 批量发送(一次最多一万条)
var_dump(call('/send-sms-batch', [
    'sp_id'    => $SP_ID,
    'password' => md5($API_PWD),
    'mobiles'  => '176xxxxxxxxx,171xxxxxxxxx',
    'content'  => '【测试签名】您的验证码是123456',
]));

// 3. 拉取状态报告:data 为 "扩展号,msg_id,手机号,状态,时间,售价",多条以 | 分隔
//    每条只能拉取一次,务必先落库再处理
$auth = ['sp_id' => $SP_ID, 'password' => md5($API_PWD)];
$report = call('/report', $auth, 'GET');
if (($report['code'] ?? -1) === 0 && !empty($report['data'])) {
    foreach (explode('|', $report['data']) as $line) {
        list($ext, $msgId, $phone, $status, $sentAt, $price) = explode(',', $line);
        echo $phone . ' ' . $status . ' ' . $sentAt . PHP_EOL;
    }
}

var_dump(call('/get-reply', $auth, 'GET')); // 4. 上行回复
var_dump(call('/balance', $auth, 'GET'));   // 5. 余额
# ===== 0. 准备(基地址与凭据都来自用户端「开发者」页)=====
BASE="https://user.arkai.site/api/v1/open"
SP_ID="669736"           # 开发者页「SPID / system_id」
API_PWD="a1b2c3d4"       # 开发者页「密码」(8 位,CMPP/SMPP 与 HTTP 共用)
# 鉴权用 password:API 密码做 md5(32 位小写十六进制)
PWD=$(printf '%s' "$API_PWD" | md5sum | cut -d' ' -f1)     # macOS: PWD=$(md5 -qs "$API_PWD")

# ===== 1. 单条短信发送 =====
curl -s -X POST "$BASE/send-sms-single" \
  --data-urlencode "sp_id=$SP_ID" \
  --data-urlencode "password=$PWD" \
  --data-urlencode "mobile=176xxxxxxxxx" \
  --data-urlencode "content=【测试签名】您的验证码是123456"
# => {"code":0,"msg":"success","msg_id":"100000017"}

# ===== 2. 批量发送(一次最多一万条,号码用英文逗号分隔)=====
curl -s -X POST "$BASE/send-sms-batch" \
  --data-urlencode "sp_id=$SP_ID" \
  --data-urlencode "password=$PWD" \
  --data-urlencode "mobiles=176xxxxxxxxx,171xxxxxxxxx" \
  --data-urlencode "content=【测试签名】您的验证码是123456"

# ===== 3. 拉取状态报告(GET,每条只能拉一次,拿到立刻入库)=====
curl -s -G "$BASE/report" \
  --data-urlencode "sp_id=$SP_ID" \
  --data-urlencode "password=$PWD"
# => {"code":0,"msg":"success","data":"扩展号,msg_id,手机号,状态,时间,售价|..."}

# ===== 4. 拉取上行回复 / 查询余额 =====
curl -s -G "$BASE/get-reply" --data-urlencode "sp_id=$SP_ID" --data-urlencode "password=$PWD"
curl -s -G "$BASE/balance"   --data-urlencode "sp_id=$SP_ID" --data-urlencode "password=$PWD"
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

public class SmsDemo {
    static final String BASE = "https://user.arkai.site/api/v1/open";   // 开发者页文档顶部的接口基地址
    static final String SP_ID = "669736";      // 开发者页「SPID / system_id」
    static final String API_PWD = "a1b2c3d4";  // 开发者页「密码」(8 位,CMPP/SMPP 与 HTTP 共用)

    static String md5(String s) throws Exception {
        StringBuilder sb = new StringBuilder();
        for (byte b : MessageDigest.getInstance("MD5").digest(s.getBytes(StandardCharsets.UTF_8))) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    // 百分号编码需与服务端(JS encodeURIComponent) 完全一致:空格 %20、* 编成 %2A、~ 保留,
    // 而 ! ' ( ) 必须保持原样(URLEncoder 默认会把它们编掉,故要还原回来)
    static String pe(String s) throws Exception {
        return URLEncoder.encode(s, "UTF-8")
                .replace("+", "%20").replace("*", "%2A").replace("%7E", "~")
                .replace("%21", "!").replace("%27", "'").replace("%28", "(").replace("%29", ")");
    }

    // signature 鉴权(可选):除 signature 外的全部参数按 key 字典序拼 QueryString,
    // 待签名串 = METHOD&%2F&QueryString,HmacSHA1 密钥为 API 密码原文,结果 base64
    static String signature(String method, Map<String, String> params) throws Exception {
        StringBuilder qs = new StringBuilder();
        for (String k : new TreeMap<>(params).keySet()) {
            if ("signature".equals(k)) continue;
            if (qs.length() > 0) qs.append('&');
            qs.append(pe(k)).append('=').append(pe(params.get(k)));
        }
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(new SecretKeySpec(API_PWD.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
        String strToSign = method.toUpperCase() + "&" + pe("/") + "&" + qs;
        return Base64.getEncoder().encodeToString(mac.doFinal(strToSign.getBytes(StandardCharsets.UTF_8)));
    }

    static String form(Map<String, String> p) throws Exception {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> e : p.entrySet()) {
            if (sb.length() > 0) sb.append('&');
            sb.append(URLEncoder.encode(e.getKey(), "UTF-8")).append('=').append(URLEncoder.encode(e.getValue(), "UTF-8"));
        }
        return sb.toString();
    }

    static String call(String path, Map<String, String> p, boolean isPost) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest req = isPost
                ? HttpRequest.newBuilder(URI.create(BASE + path))
                    .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                    .POST(HttpRequest.BodyPublishers.ofString(form(p), StandardCharsets.UTF_8)).build()
                : HttpRequest.newBuilder(URI.create(BASE + path + "?" + form(p))).GET().build();
        return client.send(req, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)).body();
    }

    public static void main(String[] args) throws Exception {
        Map<String, String> send = new LinkedHashMap<>();
        send.put("sp_id", SP_ID);
        send.put("password", md5(API_PWD));                 // 鉴权方式一:password = API 密码的 md5(最简)
        send.put("mobile", "176xxxxxxxxx");
        send.put("content", "【测试签名】您的验证码是123456"); // 国内产品必须带已报备签名
        // 鉴权方式二(签名):去掉 password,改为 send.put("signature", signature("POST", send));
        System.out.println("单条发送 -> " + call("/send-sms-single", send, true));

        Map<String, String> batch = new LinkedHashMap<>();
        batch.put("sp_id", SP_ID);
        batch.put("password", md5(API_PWD));
        batch.put("mobiles", "176xxxxxxxxx,171xxxxxxxxx");
        batch.put("content", "【测试签名】您的验证码是123456");
        System.out.println("批量发送 -> " + call("/send-sms-batch", batch, true));

        Map<String, String> auth = new LinkedHashMap<>();
        auth.put("sp_id", SP_ID);
        auth.put("password", md5(API_PWD));
        System.out.println("状态报告 -> " + call("/report", auth, false));    // data: 扩展号,msg_id,手机号,状态,时间,售价|...
        System.out.println("上行回复 -> " + call("/get-reply", auth, false));
        System.out.println("账户余额 -> " + call("/balance", auth, false));
    }
}
# -*- coding: utf-8 -*-
import base64
import hashlib
import hmac
import urllib.parse

import requests

BASE = "https://user.arkai.site/api/v1/open"   # 开发者页文档顶部的接口基地址
SP_ID = "669736"      # 开发者页「SPID / system_id」
API_PWD = "a1b2c3d4"  # 开发者页「密码」(8 位,CMPP/SMPP 与 HTTP 共用)

# 鉴权方式一:password = API 密码的 md5(hexdigest 已是 32 位小写十六进制)
PASSWORD = hashlib.md5(API_PWD.encode("utf-8")).hexdigest()

# 百分号编码需与 JS encodeURIComponent 一致:额外保留 - _ . ! ~ * ' ( ),再把 * 编成 %2A
def percent_encode(value):
    return urllib.parse.quote(str(value), safe="-_.!~*'()").replace("*", "%2A")

# signature 鉴权方式二:除 signature 外的参数按 key 字典序拼 QueryString,
# 待签名串 = METHOD&%2F&QueryString,HmacSHA1 密钥为 API 密码**原文**,结果 base64
def make_signature(method, params):
    qs = "&".join(
        percent_encode(k) + "=" + percent_encode(params[k])
        for k in sorted(params) if k != "signature"
    )
    str_to_sign = method.upper() + "&" + percent_encode("/") + "&" + qs
    digest = hmac.new(API_PWD.encode("utf-8"), str_to_sign.encode("utf-8"), hashlib.sha1).digest()
    return base64.b64encode(digest).decode("utf-8")

def post(path, params):
    # 表单按 UTF-8 提交即可;服务端解析出原文后重算签名,表单编码方式不必与签名串相同
    return requests.post(BASE + path, data=params, timeout=15).json()

def get(path, params):
    return requests.get(BASE + path, params=params, timeout=15).json()

# 1. 单条短信发送
send = {
    "sp_id": SP_ID,
    "password": PASSWORD,
    "mobile": "176xxxxxxxxx",
    "content": "【测试签名】您的验证码是123456",  # 国内产品必须带已报备签名
}
# 改用 signature:send.pop("password"); send["signature"] = make_signature("POST", send)
print("单条发送 ->", post("/send-sms-single", send))

# 2. 批量发送(一次最多一万条)
print("批量发送 ->", post("/send-sms-batch", {
    "sp_id": SP_ID, "password": PASSWORD,
    "mobiles": "176xxxxxxxxx,171xxxxxxxxx",
    "content": "【测试签名】您的验证码是123456",
}))

# 3. 拉取状态报告:data = "扩展号,msg_id,手机号,状态,时间,售价",多条以 | 分隔
#    每条只能拉取一次,务必先落库再按 手机号+msg_id 匹配
auth = {"sp_id": SP_ID, "password": PASSWORD}
rep = get("/report", auth)
if rep.get("code") == 0 and rep.get("data"):
    for line in rep["data"].split("|"):
        ext, msg_id, phone, status, sent_at, price = line.split(",")
        print("状态报告 ->", phone, status, sent_at)

print("上行回复 ->", get("/get-reply", auth))  # 4. 上行回复
print("账户余额 ->", get("/balance", auth))    # 5. 余额
const crypto = require('crypto');

const BASE = process.env.SMS_BASE || 'https://user.arkai.site/api/v1/open'; // 开发者页文档顶部的接口基地址
const SP_ID = process.env.SMS_SPID || '669736';   // 开发者页「SPID / system_id」
const API_PWD = process.env.SMS_PWD || 'a1b2c3d4';// 开发者页「密码」(8 位)

// 鉴权方式一:password = API 密码的 md5(32 位小写十六进制)
const md5 = (s) => crypto.createHash('md5').update(s, 'utf8').digest('hex');

// 百分号编码与服务端同源:encodeURIComponent 后按文档做三处替换
const percentEncode = (v) => encodeURIComponent(String(v))
  .split('+').join('%20').split('*').join('%2A').split('%7E').join('~');

// signature 鉴权方式二:除 signature 外的参数按 key 字典序拼 QueryString,
// 待签名串 = METHOD&%2F&QueryString,HmacSHA1 密钥为 API 密码原文,结果 base64
function makeSignature(method, params) {
  const qs = Object.keys(params)
    .filter((k) => k !== 'signature' && params[k] !== undefined && params[k] !== null)
    .sort()
    .map((k) => percentEncode(k) + '=' + percentEncode(params[k]))
    .join('&');
  const strToSign = method.toUpperCase() + '&' + percentEncode('/') + '&' + qs;
  return crypto.createHmac('sha1', API_PWD).update(strToSign, 'utf8').digest('base64');
}

async function call(path, params, method = 'POST') {
  const body = new URLSearchParams(params).toString();
  const res = await fetch(method === 'POST' ? BASE + path : BASE + path + '?' + body, {
    method,
    ...(method === 'POST'
      ? { headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' }, body }
      : {}),
  });
  return res.json();
}

(async () => {
  const auth = { sp_id: SP_ID, password: md5(API_PWD) };

  // 1. 单条发送(国内产品内容必须以已报备【签名】开头)
  const send = { ...auth, mobile: '176xxxxxxxxx', content: '【测试签名】您的验证码是123456' };
  // 改用 signature:去掉 password 后 send.signature = makeSignature('POST', send)
  console.log('单条发送 ->', await call('/send-sms-single', send));

  // 2. 批量发送(一次最多一万条)
  console.log('批量发送 ->', await call('/send-sms-batch', {
    ...auth, mobiles: '176xxxxxxxxx,171xxxxxxxxx', content: '【测试签名】您的验证码是123456',
  }));

  // 3. 拉取状态报告:data = "扩展号,msg_id,手机号,状态,时间,售价",多条以 | 分隔
  const rep = await call('/report', auth, 'GET');
  if (rep.code === 0 && rep.data) {
    rep.data.split('|').forEach((line) => {
      const [ext, msgId, phone, status, sentAt, price] = line.split(',');
      console.log('状态报告 ->', phone, status, sentAt); // 每条只能拉一次,务必先落库
    });
  }

  console.log('上行回复 ->', await call('/get-reply', auth, 'GET')); // 4. 上行回复
  console.log('账户余额 ->', await call('/balance', auth, 'GET'));   // 5. 余额
})();
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

class SmsDemo
{
    const string Base = "https://user.arkai.site/api/v1/open";  // 开发者页文档顶部的接口基地址
    const string SpId = "669736";     // 开发者页「SPID / system_id」
    const string ApiPwd = "a1b2c3d4"; // 开发者页「密码」(8 位)
    static readonly HttpClient Http = new HttpClient { Timeout = TimeSpan.FromSeconds(15) };

    // 鉴权方式一:password = API 密码的 md5(32 位小写十六进制)
    static string Md5(string s) =>
        Convert.ToHexString(MD5.HashData(Encoding.UTF8.GetBytes(s))).ToLowerInvariant();

    // 百分号编码需与服务端(JS encodeURIComponent) 对齐:! ' ( ) ~ 保留原样,* 编成 %2A,空格 %20
    static string PercentEncode(string s) => Uri.EscapeDataString(s)
        .Replace("%21", "!").Replace("%27", "'").Replace("%28", "(").Replace("%29", ")");

    // signature 鉴权方式二:字典序拼 QueryString → METHOD&%2F&QS → HmacSHA1(密钥=API 密码原文) → base64
    static string MakeSignature(string method, Dictionary<string, string> p)
    {
        var qs = string.Join("&", p.Where(kv => kv.Key != "signature")
            .OrderBy(kv => kv.Key, StringComparer.Ordinal)
            .Select(kv => PercentEncode(kv.Key) + "=" + PercentEncode(kv.Value)));
        using var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(ApiPwd));
        var strToSign = method.ToUpperInvariant() + "&" + PercentEncode("/") + "&" + qs;
        return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(strToSign)));
    }

    static async Task<string> Call(string path, Dictionary<string, string> p, string method = "POST")
    {
        HttpResponseMessage resp;
        if (method == "POST")
            resp = await Http.PostAsync(Base + path, new FormUrlEncodedContent(p));
        else
            resp = await Http.GetAsync(Base + path + "?" + await new FormUrlEncodedContent(p).ReadAsStringAsync());
        return await resp.Content.ReadAsStringAsync();
    }

    static async Task Main()
    {
        var auth = new Dictionary<string, string> { ["sp_id"] = SpId, ["password"] = Md5(ApiPwd) };

        // 1. 单条发送(国内产品内容必须以已报备【签名】开头)
        var send = new Dictionary<string, string>(auth)
        { ["mobile"] = "176xxxxxxxxx", ["content"] = "【测试签名】您的验证码是123456" };
        // 改用 signature:去掉 password 后 send["signature"] = MakeSignature("POST", send);
        Console.WriteLine("单条发送 -> " + await Call("/send-sms-single", send));

        // 2. 批量发送(一次最多一万条)
        var batch = new Dictionary<string, string>(auth)
        { ["mobiles"] = "176xxxxxxxxx,171xxxxxxxxx", ["content"] = "【测试签名】您的验证码是123456" };
        Console.WriteLine("批量发送 -> " + await Call("/send-sms-batch", batch));

        // 3. 状态报告:data = "扩展号,msg_id,手机号,状态,时间,售价",多条以 | 分隔,每条只能拉一次
        Console.WriteLine("状态报告 -> " + await Call("/report", new Dictionary<string, string>(auth), "GET"));
        Console.WriteLine("上行回复 -> " + await Call("/get-reply", new Dictionary<string, string>(auth), "GET"));
        Console.WriteLine("账户余额 -> " + await Call("/balance", new Dictionary<string, string>(auth), "GET"));
    }
}
package main

import (
    "crypto/hmac"
    "crypto/md5"
    "crypto/sha1"
    "encoding/base64"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "sort"
    "strings"
)

const (
    base    = "https://user.arkai.site/api/v1/open" // 开发者页文档顶部的接口基地址
    spID    = "669736"    // 开发者页「SPID / system_id」
    apiPwd  = "a1b2c3d4"  // 开发者页「密码」(8 位)
)

// 鉴权方式一:password = API 密码的 md5(32 位小写十六进制)
func md5Hex(s string) string { return fmt.Sprintf("%x", md5.Sum([]byte(s))) }

// 百分号编码需与服务端(JS encodeURIComponent) 同规则:保留字母数字与 - _ . ! ~ ' ( ),
// 其余按 UTF-8 逐字节 %XX(* 不在保留集合内,天然编成 %2A,空格编成 %20)
func percentEncode(s string) string {
    const keep = "-_.!~'()"
    var b strings.Builder
    for i := 0; i < len(s); i++ {
        c := s[i]
        if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || strings.IndexByte(keep, c) >= 0 {
            b.WriteByte(c)
            continue
        }
        fmt.Fprintf(&b, "%%%02X", c)
    }
    return b.String()
}

// signature 鉴权方式二:字典序拼 QueryString → METHOD&%2F&QS → HmacSHA1(密钥=API 密码原文) → base64
func makeSignature(method string, params map[string]string) string {
    keys := make([]string, 0, len(params))
    for k := range params {
        if k != "signature" {
            keys = append(keys, k)
        }
    }
    sort.Strings(keys)
    pairs := make([]string, 0, len(keys))
    for _, k := range keys {
        pairs = append(pairs, percentEncode(k)+"="+percentEncode(params[k]))
    }
    strToSign := strings.ToUpper(method) + "&" + percentEncode("/") + "&" + strings.Join(pairs, "&")
    mac := hmac.New(sha1.New, []byte(apiPwd))
    mac.Write([]byte(strToSign))
    return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

func call(path string, params map[string]string, method string) string {
    form := url.Values{}
    for k, v := range params {
        form.Set(k, v)
    }
    encoded := form.Encode()
    var (
        resp *http.Response
        err  error
    )
    if method == "POST" {
        resp, err = http.Post(base+path, "application/x-www-form-urlencoded; charset=utf-8", strings.NewReader(encoded))
    } else {
        resp, err = http.Get(base + path + "?" + encoded)
    }
    if err != nil {
        return "请求失败: " + err.Error()
    }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    return string(body)
}

func main() {
    auth := map[string]string{"sp_id": spID, "password": md5Hex(apiPwd)}

    // 1. 单条发送(国内产品内容必须以已报备【签名】开头)
    send := map[string]string{"mobile": "176xxxxxxxxx", "content": "【测试签名】您的验证码是123456"}
    for k, v := range auth {
        send[k] = v
    }
    // 改用 signature:delete(send, "password"); send["signature"] = makeSignature("POST", send)
    fmt.Println("单条发送 ->", call("/send-sms-single", send, "POST"))

    // 2. 批量发送(一次最多一万条)
    batch := map[string]string{"mobiles": "176xxxxxxxxx,171xxxxxxxxx", "content": "【测试签名】您的验证码是123456"}
    for k, v := range auth {
        batch[k] = v
    }
    fmt.Println("批量发送 ->", call("/send-sms-batch", batch, "POST"))

    // 3. 状态报告:data = "扩展号,msg_id,手机号,状态,时间,售价",多条以 | 分隔,每条只能拉一次
    fmt.Println("状态报告 ->", call("/report", auth, "GET"))
    fmt.Println("上行回复 ->", call("/get-reply", auth, "GET"))
    fmt.Println("账户余额 ->", call("/balance", auth, "GET"))
}

接口基地址 https://user.arkai.site/api/v1/open,代码注释沿用官方文档原文;状态报告与上行回复每条只能取到一次,请先落库再走业务处理。

Onboarding

四步接入,当天跑通第一条短信

从注册到上线全流程线上自助完成,沙箱环境免费调试,正式通道按量计费。

01

注册与实名

提交企业资料,线上完成实名认证与短信签名报备,无需线下邮寄材料。

02

创建应用与模板

在控制台创建应用并提交短信模板,最快 2 小时审核通过,支持多模板批量管理。

03

对接 API

直接调用 HTTP API,提供 7 种语言示例,沙箱环境先跑通再切正式通道。

04

上线与监控

配置发送频率与失败告警,实时查看发送、送达与失败明细,问题分钟级定位。

Endpoints

9 个开放接口,覆盖提交到回收全链路

所有接口以 sp_id 标识产品,POST 表单编码提交,返回结构统一为 code / msg / data;发送类接口的拦截错误实时返回。

接口请求说明
单条发送POST /send-sms-single单个号码提交,拦截类错误实时返回;返回的 msg_id 用于匹配状态报告。
批量发送POST /send-sms-batch号码用英文逗号分隔,一次最多 10 万个;单包上限 1 万,超出由平台自动拆包,对外仍是同一个 msg_id。
变量发送POST /send-variable内容用 {变量名} 占位(支持中文),每个号码的变量值按顺序跟在手机号后,多组以分号分隔。
一对一发送POST /send-biuniqueparams 传 JSON:key 为手机号、value 为内容;一次最多 500 条,同一批的签名必须一致。
获取状态报告GET /report每条状态仅可取到一次,拉到请立刻落库;单次最多返回 1000 条,未拉完继续轮询。
推送状态报告PUSH PUSH 回调推送到开发者页配置的接收地址,POST 原始字节流;报文与 GET /report 的 data 完全同构,切换模式无需改解析代码。
获取上行回复GET /get-reply用户回复(如退订 TD)每条仅可取到一次;报文本身不带 msg_id,平台按最近一次提交反查回填。
推送上行回复PUSH PUSH 回调同样以 POST 推送,内容为 urlencode 后的回复文本;你的接口返回 2xx 即视为接收成功。
获取余额GET /balance返回账户可用余额,用于发送前的额度自检与告警。

状态报告只返回最终态:DELIVRD 送达、UNDELIV 未送达、REJECTD 平台拒绝、DELETED 已删除;处理中的短信不会提前返回,请继续轮询。

文档中心

完整的接口说明、错误码与最佳实践,支持在线调试与一键复制示例。

打开文档中心

服务状态

实时查看国内与国际通道可用性、平均延迟与历史故障记录。

查看服务状态
开始使用

下一代 AI 短信,保障你的每一条短信准时送达

留下联系方式,解决方案专家会在 1 个工作日内与你联系,为你定制通道方案与接入支持。

无需信用卡 · 5 分钟完成接入 · 提供免费试用额度