API REFERENCE

SACTL Gateway API

本页所有 endpoint 都是真实在 gateway-sidecar 里注册并通过 10/10 smoke-test 验证的。curl 示例把 YOUR_VK 替换为你拿到的 sk-xa-* 即可直连。

Base URL https://api.sactl.ai

Authentication

所有受保护 endpoint 都需要 Authorization: Bearer sk-xa-{env}-{base62}。key 由后台生成或 Telegram 客服直接发,数据库里存的是 HMAC 摘要(不是明文)。每个 key 带四个属性:允许的模型列表、IP 白名单、月预算上限、归属租户 — 调用前会逐项检查,不符合直接拒。

Common request headers

字段类型说明
Authorization string 必填 Bearer sk-xa-{env}-{base62}。env 取值 dev/stg/prod
Content-Type string 必填 POST 必须 application/json,/v1/files 上传为 multipart/form-data
X-Request-Id string 客户端自带的 trace id。未提供时 SACTL 会生成 UUIDv7 并回填到响应头。
anthropic-beta string 仅对 /v1/messages / Files / Batches 起作用,原样透传给 Anthropic。
anthropic-version string SACTL 在出站请求处统一锁定 2023-06-01(客户端传值会被覆盖),保持与 Anthropic SDK / Claude Code 默认值一致。

Response headers

所有 2xx 响应都会携带 SACTL 计量 header。前端可以直接读 X-SACTL-Usage-Cost-USD 做前端账本,不需要再调用 /v1/usage。

Header类型何时说明
X-SACTL-Usage-Prompt-Tokens int 2xx 本次 prompt tokens 数(按 upstream 报告回来的值计)。
X-SACTL-Usage-Completion-Tokens int 2xx 本次 completion tokens 数。
X-SACTL-Usage-Cost-USD decimal 2xx 本次消耗美元,按 SACTL 折扣表(Claude 全系 3 折;GPT 低至官方 1/30 已支持;Gemini 即将支持)结算,保留 6 位小数。
X-SACTL-Budget-Remaining-USD decimal 有 cap VK 配置了月度 cap 时出现,表示当月剩余额度。
Retry-After int 429 GCRA 限流命中时返回,单位秒,按 bucket 恢复速率计算。

Error envelope

所有 4xx/5xx 统一为下面的信封结构。不透传上游原文 error body —— 上游凭证、内部 URL、trace 细节绝不泄露给客户端。trace_id 可用于工单回溯。

{
  "error": {
    "code": "key_invalid",
    "message": "virtual key is invalid or revoked",
    "trace_id": "01JX7W3Z5A8M9E2Q1P4K6R8TVB"
  }
}

Registered error codes

HTTPcode触发条件
401key_invalidVK 缺失、错误、或已 revoke。
403model_forbidden请求的 model 不在 VK 的 allowed_models 白名单中。
403ip_forbidden请求 IP 不在 VK 的 IP 白名单中。
403signature_invalidVK HMAC 校验失败(例如 pepper 不对齐)。
402budget_exhaustedDoW 预扣判定此调用会让 VK 超过月度美元 cap。
402context_too_longprompt tokens 超过 pricing registry 登记的该模型 context window。
429rate_limitedGCRA 限流命中(tenant / vk / vk×model / vk×ip 四维任意一维)。
400ssrf_forbidden多模态 image_url 指向内网/私有地址,被 SSRF 过滤器拦截。
400model_unknown模型 ID 在 pricing registry 查不到。
400bad_requestJSON 格式错误、必填字段缺失。
413payload_too_large请求体超过 SIDECAR_MAX_BODY_MB(默认 10MB,可调 1..100)。
415unsupported_mediamultipart 上传 mime 不在白名单。
502upstream_errorAnthropic 或 OpenAI 返回 5xx。(Gemini 上游即将支持。)
504upstream_timeout上游请求超时。
500internal_error网关内部异常。
503service_unavailable多 key 池全部在冷却期(熔断器)。preview

Inference

核心推理 endpoint —— Anthropic Messages 原生协议 + OpenAI 兼容路径(OpenAI SDK 零客户端改动直连 Claude 或 GPT)。Claude + GPT 上游已接通;Gemini 即将支持。

POST /v1/messages stable

Create message (Anthropic native)

Anthropic 原生 Messages endpoint。请求体和响应体兼容官方 Anthropic Messages API(Claude Code 用的就是这个端点)。我们只在前面加了认证、用量限制、限流、计费日志几层,不改请求体语义。

Headers

字段类型说明
Authorizationstring必填Bearer sk-xa-...
Content-Typestring必填application/json
anthropic-betastring多个 beta 用逗号分隔。透传给 Anthropic。
X-Request-Idstring客户端 trace id。

Request body

字段类型说明
modelstring必填模型 ID,必须在 VK 的 allowed_models 内,见 GET /v1/models
max_tokensint必填上限由 pricing registry 查该模型的 token window。
messagesarray必填Anthropic 消息数组,role 为 user / assistant,content 可为字符串或 block 数组(含 text / image / tool_use / tool_result)。
systemstring | arraysystem prompt。数组形式可带 cache_control
temperaturenumber0.0 - 1.0。
top_pnumber核采样。
top_kinttop-k 采样。
stop_sequencesstring[]自定义停止词。
toolsarrayAnthropic 原生 tools 格式。
tool_choiceobject{type: "auto"|"any"|"tool", name?: "..."}
streambool默认 false。true 返回 SSE(text/event-stream),事件名为 Anthropic 原生(message_start / content_block_delta / ...)。
thinkingobject{type: "enabled", budget_tokens: 32000} extended thinking。若未显式设置 anthropic-beta,SACTL 自动注入。
cache_controlobject嵌在 content block / tools / system 内,{type: "ephemeral"}。SACTL 原样透传给 Anthropic,命中按 cache write/read 单价计费。
metadataobject{user_id: "..."} 原样透传,落审计。

Request example

{
  "model": "claude-sonnet-4-6",
  "max_tokens": 1024,
  "messages": [
    { "role": "user", "content": "Hello, Claude." }
  ]
}

Response

HTTP/1.1 200 OK
X-SACTL-Usage-Prompt-Tokens: 12
X-SACTL-Usage-Completion-Tokens: 28
X-SACTL-Usage-Cost-USD: 0.000336
X-SACTL-Budget-Remaining-USD: 49.832104

{
  "id": "msg_01AbCdEfGhIjKlMnOpQrStUv",
  "type": "message",
  "role": "assistant",
  "model": "claude-sonnet-4-6",
  "content": [
    { "type": "text", "text": "Hello! How can I help you today?" }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 12,
    "output_tokens": 28
  }
}

curl

curl https://api.sactl.ai/v1/messages \
  -H "Authorization: Bearer YOUR_VK" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 1024,
    "messages": [
      { "role": "user", "content": "Hello, Claude." }
    ]
  }'

Errors

HTTPcode场景
401key_invalidVK 缺失或已 revoke。
403model_forbiddenmodel 不在 allowlist。
402budget_exhaustedDoW 预扣超限。
402context_too_longprompt 超 token window。
429rate_limitedGCRA 命中,带 Retry-After
502upstream_errorAnthropic 返回 5xx。
504upstream_timeout上游超时。
POST /v1/embeddings stable

创建 embeddings

Embeddings(OpenAI 兼容 schema)。Anthropic 不提供 embeddings,此 endpoint 路由到 GPT(text-embedding-3-small / text-embedding-3-large)上游。Gemini(text-embedding-004)即将支持。按 token 实扣,跟推理 endpoint 共用 budget / rate-limit 体系。

请求体

字段类型说明
modelstring必填Embedding 模型 ID。
inputstring | array必填单个字符串或字符串数组。
encoding_formatstring"float"(默认)/ "base64"
dimensionsinttext-embedding-3-* 系列有效,截断 embedding 维度。

响应

{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "index": 0,
      "embedding": [0.0023, -0.0091, 0.0412, /* ... 1536 floats */]
    }
  ],
  "model": "text-embedding-3-small",
  "usage": {
    "prompt_tokens": 7,
    "total_tokens": 7
  }
}

curl

curl https://api.sactl.ai/v1/embeddings \
  -H "Authorization: Bearer YOUR_VK" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "text-embedding-3-small",
    "input": "The quick brown fox jumps over the lazy dog."
  }'

错误

HTTPcode场景
401key_invalidVK 无效。
400model_unknown模型 ID 未注册。
413payload_too_largeinput 数组过大。
429rate_limited命中限流。
GET /v1/models stable

List models

列出你的 VK 有权限调用的所有模型。返回 Anthropic 原生 shape {data: [{id, type, ...}]}。这个列表由 VK 的 allowed_models 数组交集 pricing registry 动态生成 —— 即使 pricing registry 登记了某个模型,如果 VK 没开通该模型,它不会出现。

Response

{
  "data": [
    { "type": "model", "id": "claude-opus-4-7",     "display_name": "Claude Opus 4.7",   "created_at": "2025-09-29T00:00:00Z" },
    { "type": "model", "id": "claude-opus-4-6",     "display_name": "Claude Opus 4.6",   "created_at": "2025-08-05T00:00:00Z" },
    { "type": "model", "id": "claude-sonnet-4-6",   "display_name": "Claude Sonnet 4.6", "created_at": "2025-07-10T00:00:00Z" },
    { "type": "model", "id": "claude-haiku-4-5",    "display_name": "Claude Haiku 4.5",  "created_at": "2025-05-03T00:00:00Z" }
  ],
  "has_more": false,
  "first_id": "claude-opus-4-7",
  "last_id": "claude-haiku-4-5"
}
# GPT 模型(gpt-4o / gpt-4o-mini / text-embedding-3-* 等)已加入此列表(与 VK allowed_models 取交集)。Gemini 上游接入后自动出现。

curl

curl https://api.sactl.ai/v1/models \
  -H "Authorization: Bearer YOUR_VK"

Files API

Anthropic Files API 透传。用于上传文档 / 图片供后续 /v1/messages 引用。最大文件大小由 SIDECAR_FILES_MAX_MB(默认 100MB)控制,MIME 白名单可配。所有 Files 操作会写一条计费日志(file.uploaded / file.deleted),便于对账。

POST /v1/files stable

Upload file

上传文件。multipart/form-data。文件 id 随后可在 /v1/messages 的 content block 里通过 {type: "document", source: {type: "file", file_id: "..."}} 引用。

Form fields

字段类型说明
filefile必填文件二进制。MIME 白名单:application/pdf, image/png, image/jpeg, image/gif, image/webp, text/plain, text/csv, text/markdown
purposestring可选标签,落审计。

Response

{
  "id": "file_01AbCdEfGhIjKlMnOpQrStUv",
  "type": "file",
  "filename": "contract.pdf",
  "mime_type": "application/pdf",
  "size_bytes": 183204,
  "created_at": "2026-04-20T08:12:31.441Z",
  "downloadable": false
}

curl

curl https://api.sactl.ai/v1/files \
  -H "Authorization: Bearer YOUR_VK" \
  -F "[email protected];type=application/pdf" \
  -F "purpose=context"

Errors

HTTPcode场景
401key_invalidVK 无效。
413payload_too_large文件超过 SIDECAR_FILES_MAX_MB(默认 100MB)。
415unsupported_mediaMIME 不在白名单。
GET /v1/files stable

List files

列出当前 VK 上传过的文件(其它 VK 的文件不可见)。分页基于 cursor。

Query params

字段类型说明
limitint1 - 1000,默认 20。
before_idstringcursor,返回此 id 之前的文件。
after_idstringcursor,返回此 id 之后的文件。

Response

{
  "data": [
    { "id": "file_01AbCd...", "filename": "contract.pdf", "size_bytes": 183204, "mime_type": "application/pdf", "created_at": "2026-04-20T08:12:31.441Z" }
  ],
  "has_more": false,
  "first_id": "file_01AbCd...",
  "last_id": "file_01AbCd..."
}

curl

curl "https://api.sactl.ai/v1/files?limit=20" \
  -H "Authorization: Bearer YOUR_VK"
GET /v1/files/{id} stable

Get file metadata

读取单个文件的元数据。SACTL 不落文件二进制本身,本 endpoint 返回的是 Anthropic 上游的 metadata 透传。

curl

curl https://api.sactl.ai/v1/files/file_01AbCdEfGhIjKlMnOpQrStUv \
  -H "Authorization: Bearer YOUR_VK"

Errors

HTTPcode场景
401key_invalidVK 无效。
404bad_requestfile id 不存在或不属于本 VK。
DELETE /v1/files/{id} stable

Delete file

删除文件。删除成功后 /v1/messages 引用该 file_id 的请求会得到 bad_request。审计会 emit file.deleted

Response

{
  "id": "file_01AbCdEfGhIjKlMnOpQrStUv",
  "type": "file_deleted"
}

curl

curl -X DELETE https://api.sactl.ai/v1/files/file_01AbCdEfGhIjKlMnOpQrStUv \
  -H "Authorization: Bearer YOUR_VK"

MCP Servers API

每个 VK 可以挂载若干 MCP server(filesystem / fetch / 自定义 tool 链)。SACTL 把 server 配置存在 admin-api 的 mcp_servers 表,Anthropic Messages 调用前 sidecar 拼到 mcp_servers 字段透传给上游。OAuth-token 类 server 需先调 /auth-url 拿到授权链接由用户完成绑定。

POST /v1/mcp_servers stable

Create MCP server

注册一个新的 MCP server 配置。typeurl(直连 SSE)、stdio(本地命令)或 oauth(需先走 /auth-url 拿 token)。

curl

curl -X POST https://api.sactl.ai/v1/mcp_servers \
  -H "Authorization: Bearer YOUR_VK" \
  -H "Content-Type: application/json" \
  -d '{"name":"fs","type":"url","url":"https://mcp.example.com/sse"}'
GET /v1/mcp_servers stable

List MCP servers

列出当前 VK 配置的所有 MCP server。limit 默认 1000(与 Anthropic 上游一致)。

curl

curl "https://api.sactl.ai/v1/mcp_servers?limit=1000" \
  -H "Authorization: Bearer YOUR_VK"
GET /v1/mcp_servers/{id} stable

Retrieve MCP server

读取单个 MCP server 配置。

curl

curl https://api.sactl.ai/v1/mcp_servers/mcp_01AbCd... \
  -H "Authorization: Bearer YOUR_VK"
GET /v1/mcp_servers/{id}/auth-url stable

Generate OAuth auth URL

type=oauth 的 MCP server,返回授权链接,用户走完之后回调写回 token。

curl

curl https://api.sactl.ai/v1/mcp_servers/mcp_01AbCd.../auth-url \
  -H "Authorization: Bearer YOUR_VK"
PATCH /v1/mcp_servers/{id} stable

Update MCP server

局部更新 server 配置。仅支持改 name / url / headers;type 不可变。

curl

curl -X PATCH https://api.sactl.ai/v1/mcp_servers/mcp_01AbCd... \
  -H "Authorization: Bearer YOUR_VK" \
  -H "Content-Type: application/json" \
  -d '{"name":"fs-prod"}'
DELETE /v1/mcp_servers/{id} stable

Delete MCP server

删除 server 配置。已 in-flight 的会话不受影响。

curl

curl -X DELETE https://api.sactl.ai/v1/mcp_servers/mcp_01AbCd... \
  -H "Authorization: Bearer YOUR_VK"

Batch API

大量 Messages 请求打包提交,状态机:validating → in_progress → ended | canceled | failed。结果以 JSONL 返回,只在 ended 状态可下载。

计费:批量调用按官方 50% 折扣再叠加 SACTL 3 折,Claude 批量价 = 官方 × 0.15(见 定价页)。计费结算由后台 poller 在 batch 进入 ended 状态时触发(默认 5 分钟扫一轮),canceled / failed 的 request 不计费。

POST /v1/messages/batches stable

Create message batch

提交一批 Messages 请求。每条 request 与单次 /v1/messages 的 body 等价,外层加 custom_id 用于对账。

Request body

字段类型说明
requestsarray必填1 - 10,000 个 {custom_id, params} 条目。
requests[].custom_idstring必填批内唯一,用于把结果对回业务 id。
requests[].paramsobject必填/v1/messages 请求体同构(model / max_tokens / messages / ...)。

Request example

{
  "requests": [
    {
      "custom_id": "job-001",
      "params": {
        "model": "claude-haiku-4-5",
        "max_tokens": 256,
        "messages": [ { "role": "user", "content": "Summarize Go channels." } ]
      }
    },
    {
      "custom_id": "job-002",
      "params": {
        "model": "claude-haiku-4-5",
        "max_tokens": 256,
        "messages": [ { "role": "user", "content": "What is GCRA?" } ]
      }
    }
  ]
}

Response

{
  "id": "msgbatch_01Wx9...",
  "type": "message_batch",
  "processing_status": "in_progress",
  "request_counts": { "processing": 2, "succeeded": 0, "errored": 0, "canceled": 0, "expired": 0 },
  "ended_at": null,
  "created_at": "2026-04-20T08:12:31.441Z",
  "expires_at": "2026-04-21T08:12:31.441Z",
  "cancel_initiated_at": null,
  "results_url": null
}

curl

curl https://api.sactl.ai/v1/messages/batches \
  -H "Authorization: Bearer YOUR_VK" \
  -H "Content-Type: application/json" \
  -d @batch.json
GET /v1/messages/batches stable

List message batches

列出当前 VK 的所有 batch。支持 limit / before_id / after_id cursor 分页。

curl

curl "https://api.sactl.ai/v1/messages/batches?limit=20" \
  -H "Authorization: Bearer YOUR_VK"
GET /v1/messages/batches/{id} stable

Retrieve message batch

读取单个 batch 的状态。processing_statusvalidatingin_progressended / canceled / failed 之间流转。

Response

{
  "id": "msgbatch_01Wx9...",
  "processing_status": "ended",
  "request_counts": { "processing": 0, "succeeded": 2, "errored": 0, "canceled": 0, "expired": 0 },
  "ended_at": "2026-04-20T08:14:02.112Z",
  "results_url": "https://api.sactl.ai/v1/messages/batches/msgbatch_01Wx9.../results"
}

curl

curl https://api.sactl.ai/v1/messages/batches/msgbatch_01Wx9... \
  -H "Authorization: Bearer YOUR_VK"
GET /v1/messages/batches/{id}/results stable

Retrieve message batch results

以 JSONL (application/x-ndjson) 返回每条 request 的结果。仅在 processing_status=ended 时可用,其它状态返回 bad_request

Response (one line per request)

{"custom_id":"job-001","result":{"type":"succeeded","message":{"id":"msg_...","content":[...],"usage":{...}}}}
{"custom_id":"job-002","result":{"type":"succeeded","message":{"id":"msg_...","content":[...],"usage":{...}}}}

curl

curl https://api.sactl.ai/v1/messages/batches/msgbatch_01Wx9.../results \
  -H "Authorization: Bearer YOUR_VK"
POST /v1/messages/batches/{id}/cancel stable

Cancel message batch

把一个 in_progress / validating 的 batch 迁移到 canceling。已 in-flight 的 request 仍可能完成,完成的计费正常,取消的 request 不计费。

curl

curl -X POST https://api.sactl.ai/v1/messages/batches/msgbatch_01Wx9.../cancel \
  -H "Authorization: Bearer YOUR_VK"

System

健康检查和 metrics。不需要 VK,但生产部署应在 ingress 层限制只对运维网段开放。

GET /health stable

Health check

健康检查。返回 200 + JSON,字段展示各依赖的连通性。Kubernetes liveness / readiness 可直接用此端点。无需 auth。

Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "status": "ok",
  "deps": {
    "redis": "ok",
    "vault": "ok"
  }
}

任一依赖不可达时,status 退化为 degraded,HTTP 状态码升至 503,Kubernetes liveness 直接据此剔除 pod。

curl

curl https://api.sactl.ai/health
GET /metrics stable

Prometheus metrics

Prometheus metrics endpoint。返回 text/plain 格式的所有业务 metric。所有 series 以 sactl_gateway_* 为前缀(熔断状态用 sactl_breaker_*)。挂在 Prometheus scrape config 里即可。

生产建议:此 endpoint 在生产环境里应限制只有运维网段 / Prometheus scraper 可访问(靠上游 ingress / nginx 做 CIDR 白名单)。metric 本身不含凭证,但会暴露流量画像。

Response (节选)

# HELP sactl_gateway_ratelimit_rejected_total Requests rejected by GCRA rate limiter
# TYPE sactl_gateway_ratelimit_rejected_total counter
sactl_gateway_ratelimit_rejected_total{dimension="tenant"} 12
sactl_gateway_ratelimit_rejected_total{dimension="vk"} 3
sactl_gateway_ratelimit_rejected_total{dimension="vk_model"} 1
sactl_gateway_ratelimit_rejected_total{dimension="vk_ip"} 0

# HELP sactl_gateway_request_duration_seconds Request duration histogram
# TYPE sactl_gateway_request_duration_seconds histogram
sactl_gateway_request_duration_seconds_bucket{route="/v1/messages",le="0.5"} 4821
sactl_gateway_request_duration_seconds_bucket{route="/v1/messages",le="1"} 5910
sactl_gateway_request_duration_seconds_bucket{route="/v1/messages",le="+Inf"} 6024

# HELP sactl_gateway_upstream_errors_total Upstream 5xx / timeout / parse errors
# TYPE sactl_gateway_upstream_errors_total counter
sactl_gateway_upstream_errors_total{provider="anthropic",kind="5xx"} 2

# HELP sactl_breaker_open Per-provider breaker open=1 closed=0
# TYPE sactl_breaker_open gauge
sactl_breaker_open{provider="anthropic"} 0

# HELP sactl_gateway_ssrf_blocked_total Multimodal URL blocked by SSRF filter
# TYPE sactl_gateway_ssrf_blocked_total counter
sactl_gateway_ssrf_blocked_total 0

curl

curl https://api.sactl.ai/metrics

Preview / Coming soon

以下能力代码就绪但未挂热路径,或仍在灰度。生产客户请不要依赖它们的行为。

Multi-key pool PickMiddleware preview

单个 upstream provider 下挂多把 API key,按 health / cost / usage 选择调用对象,某把 key 被上游 429 / 401 时进入冷却窗口,所有 key 冷却时整个 provider 熔断并返回 503 service_unavailable

  • 当前状态:中间件代码已实现,未默认挂在 forward 路径上。
  • 预期 GA:2026 Q2。挂入后不会改变 API 契约,只会把 503 service_unavailable 从 "理论可能" 变成真实观察到。

Markup multiplier settle preview

对多层转售场景,支持给 VK 配置 markup_multiplier(例如 1.20 = 加 20% 渠道差价),结算时自动把差价归入渠道账户。

  • 当前状态:schema 字段已落库,结算阶段尚未应用乘子,实际计费等于原价。
  • 预期 GA:与 Multi-key pool 同批次 2026 Q2。
  • 注意:这不会向客户端暴露新 endpoint,只会改变 X-SACTL-Usage-Cost-USD header 的金额含义。