sent-integration-starter

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Sent Integration Starter

Sent集成入门指南

Bring up a Sent integration in four stages: authenticate, send idempotently, receive verified events, then harden. Do not conflate them — most broken integrations pass stage one and skip stage three.
通过四个阶段搭建Sent集成:认证、幂等发送、接收已验证事件、然后强化集成。请勿混淆这些阶段——大多数集成失败都是因为通过了第一阶段却跳过了第三阶段。

Stage 1: client and credentials

阶段1:客户端与凭证

Direct Sent v3 REST requests authenticate with the
x-api-key
header. An application proxy may accept
Authorization: Bearer
from its own callers, and the Sent MCP server uses client-managed OAuth, but neither changes the REST header sent to
api.sent.dm
. Organization keys may add
x-profile-id
to act for a child profile; a profile-scoped key that sends that header receives
403
.
LanguagePackageClient
TypeScript
@sentdm/sentdm
new SentDm()
Python
sentdm
(imports
sent_dm
)
Sent()
or
AsyncSent()
Go
github.com/sentdm/sent-dm-go
sentdm.NewClient()
Java
dm.sent:sent-java
SentOkHttpClient.fromEnv()
C#
Sentdm
new SentClient()
PHP
sentdm/sent-dm-php
new SentDm\Client($apiKey)
Ruby
sentdm
Sentdm::Client.new
Every SDK except PHP reads
SENT_DM_API_KEY
automatically. Single-endpoint receiver samples read
SENT_DM_WEBHOOK_SECRET
; multi-tenant production receivers need a secret registry keyed by webhook id instead of one process-wide secret. Older documentation uses
SENT_API_KEY
and
SENT_WEBHOOK_SECRET
— treat those as aliases and standardize on the
SENT_DM_
names.
Choose the client lifecycle from the credential model. A single-account service with one server-managed key should reuse a long-lived client and its connection pool. A multi-tenant proxy that resolves a caller or profile credential per request should construct the client for that request and discard it, so tenant credentials cannot leak through shared state. Framework-specific wiring, the Ruby
messages.send_
naming quirk, and per-ecosystem background-work choices are in references/sdk-and-frameworks.md.
Validate configuration at boot and fail fast when the key is missing, rather than surfacing an auth error on the first customer send.
直接调用Sent v3 REST接口需通过
x-api-key
头进行认证。应用代理可能会从自身调用者处接收
Authorization: Bearer
凭证,Sent MCP服务器使用客户端管理的OAuth,但这两者都不会改变发送至
api.sent.dm
的REST请求头。组织级密钥可添加
x-profile-id
以代表子配置文件操作;若使用配置文件范围的密钥发送该头,会收到
403
错误。
语言客户端
TypeScript
@sentdm/sentdm
new SentDm()
Python
sentdm
(导入
sent_dm
Sent()
AsyncSent()
Go
github.com/sentdm/sent-dm-go
sentdm.NewClient()
Java
dm.sent:sent-java
SentOkHttpClient.fromEnv()
C#
Sentdm
new SentClient()
PHP
sentdm/sent-dm-php
new SentDm\Client($apiKey)
Ruby
sentdm
Sentdm::Client.new
除PHP外,所有SDK都会自动读取
SENT_DM_API_KEY
。单端点接收器示例会读取
SENT_DM_WEBHOOK_SECRET
;多租户生产级接收器需要一个按Webhook ID索引的密钥注册表,而非全局单一密钥。旧版文档使用
SENT_API_KEY
SENT_WEBHOOK_SECRET
——可将其视为别名,并统一使用
SENT_DM_
前缀的命名。
根据凭证模型选择客户端生命周期。使用单个服务器管理密钥的单账户服务应复用长期存在的客户端及其连接池。每个请求解析调用者或配置文件凭证的多租户代理应针对该请求构建客户端并在使用后丢弃,避免租户凭证通过共享状态泄露。框架特定配置、Ruby的
messages.send_
命名特性以及各生态系统的后台任务选择可查看references/sdk-and-frameworks.md
在启动时验证配置,当密钥缺失时快速失败,而非在首次客户发送时才暴露认证错误。

Stage 2: idempotent sends

阶段2:幂等发送

json
{
  "to": ["+14155551234"],
  "template": {
    "name": "order_confirmation",
    "parameters": { "order_id": "12345" }
  },
  "sandbox": true
}
to
is the only required field. Supply
template
or
text
, and omit
channel
to let automatic routing choose. Never write a
channel
array with several values expecting fallback — that broadcasts and multiplies charges. Channel decisions belong to
sent-routing-strategist
.
Send
Idempotency-Key
on every POST, PUT, and PATCH, derived deterministically from your own domain object (for example the order id plus the notification type) so a retry after a timeout cannot double-send. Keys are 1–255 characters of
[A-Za-z0-9_-]
, cached 24 hours per key per customer. A replay returns the cached body with
Idempotent-Replayed: true
and
X-Original-Request-Id
. A duplicate arriving while the original is still in flight waits up to five seconds and then fails
409 CONFLICT_001
; a
503 SERVICE_001
means the idempotency store was unavailable and the request was deliberately not executed.
202
means accepted, not delivered. Persist the returned
message_id
values immediately with your own tenant, profile, and logical send identifiers. Webhook events carry the Sent message id and account data, but never your application's tenant identifier.
json
{
  "to": ["+14155551234"],
  "template": {
    "name": "order_confirmation",
    "parameters": { "order_id": "12345" }
  },
  "sandbox": true
}
to
是唯一必填字段。提供
template
text
,省略
channel
可让自动路由选择渠道。切勿编写包含多个值的
channel
数组以期望降级——这会广播消息并增加费用。渠道决策应由
sent-routing-strategist
负责。
在每个POST、PUT和PATCH请求中发送
Idempotency-Key
,该密钥应从您自己的领域对象(例如订单ID加通知类型)确定性生成,这样超时后的重试不会导致重复发送。密钥长度为1-255字符,允许的字符为
[A-Za-z0-9_-]
,每个客户的密钥会被缓存24小时。重放请求会返回缓存的响应体,并带有
Idempotent-Replayed: true
X-Original-Request-Id
头。当原始请求仍在处理时收到重复请求,会等待最多5秒,然后返回
409 CONFLICT_001
错误;
503 SERVICE_001
表示幂等存储不可用,请求未被执行。
202
表示请求已接受,而非已送达。请立即将返回的
message_id
值与您自己的租户、配置文件和逻辑发送标识符一起持久化。Webhook事件会携带Sent的消息ID和账户数据,但绝不会包含您应用的租户标识符。

Stage 3: verified webhook receiver

阶段3:已验证的Webhook接收器

An integration without a receiver has no delivery truth. Register an endpoint, then verify every delivery: HMAC-SHA256 over
{x-webhook-id}.{x-webhook-timestamp}.{raw_body}
, keyed on the base64-decoded secret after stripping
whsec_
, compared in constant time, rejecting timestamps outside 300 seconds. No SDK ships a verifier in any language.
Acknowledge with
200
before doing work, and deduplicate on
{message_id}:{message_status}
for outbound events and
message_id
for inbound. Ten consecutive failed deliveries disable the endpoint. Full mechanics belong to
sent-webhook-engineer
; treat a verified, fast-acknowledging, deduplicating receiver as a launch requirement here.
没有接收器的集成无法获取真实的送达状态。注册一个端点,然后验证每一次送达:使用去除
whsec_
前缀后经base64解码的密钥,对
{x-webhook-id}.{x-webhook-timestamp}.{raw_body}
进行HMAC-SHA256签名,以恒定时间进行比较,拒绝超出300秒的时间戳。目前没有任何语言的SDK提供验证器。
先返回
200
确认,再处理任务;针对出站事件按
{message_id}:{message_status}
去重,针对入站事件按
message_id
去重。连续十次送达失败会禁用该端点。完整机制可查看
sent-webhook-engineer
;在此处,需将已验证、快速确认、可去重的接收器视为发布必备条件。

Stage 4: harden

阶段4:强化集成

Retry policy by response class

按响应类别制定重试策略

ResponseRetryHow
2xx
NoSuccess
400
,
422
VALIDATION_*
NoFix the request
401
,
403
AUTH_*
NoStop immediately; ten consecutive auth failures lock the credential with escalating lockouts
404
RESOURCE_*
NoThe referenced object does not exist
409 CONFLICT_001
Yes, once, after a pauseA concurrent duplicate is in flight
429
YesHonor
Retry-After
; jittered backoff
5xx
,
503 SERVICE_001
YesExponential backoff with jitter and a ceiling
Timeout with no responseRetry safely only with evidenceReuse the same
Idempotency-Key
; without one, there is no reliable API lookup by key or recipient, so do not automate a resend
The standard limit is 200 requests per minute on a sliding window.
POST /v3/webhooks/{id}/rotate-secret
and
POST /v3/webhooks/{id}/test
are limited to 10 per minute. Rate-limit headers appear only on
429
responses, so pacing must be designed rather than measured — batch up to 1,000 recipients per request and pace at roughly one request per second for bulk work.
响应是否重试方式
2xx
成功
400
422
VALIDATION_*
修改请求
401
403
AUTH_*
立即停止;连续十次认证失败会锁定凭证并逐步延长锁定时间
404
RESOURCE_*
引用的对象不存在
409 CONFLICT_001
是,暂停后重试一次存在并发的重复请求
429
遵循
Retry-After
头;添加抖动的退避策略
5xx
503 SERVICE_001
带抖动的指数退避策略,并设置上限
无响应超时仅在有依据时安全重试复用相同的
Idempotency-Key
;若无该密钥,无法通过密钥或收件人进行可靠的API查询,因此请勿自动重发
标准限制为滑动窗口内每分钟200次请求。
POST /v3/webhooks/{id}/rotate-secret
POST /v3/webhooks/{id}/test
的限制为每分钟10次。限流头仅出现在
429
响应中,因此必须主动设计请求节奏而非被动测量——批量请求最多包含1000个收件人,批量处理时大致保持每秒一次请求的节奏。

Error handling

错误处理

Errors arrive as
{success, data, error: {code, message, details, doc_url}, meta: {request_id, timestamp, version}}
. Branch on the
error.code
prefix family (
AUTH_
,
VALIDATION_
,
RESOURCE_
,
BUSINESS_
,
CONFLICT_
,
SERVICE_
,
INTERNAL_
) rather than on message text or on individual codes. The full 46-code catalog with retry classification is in references/errors-and-limits.md.
Two codes are counterintuitive:
BUSINESS_003
and
BUSINESS_004
are documented as request-level errors, but on
POST /v3/messages
the request is accepted with
202
and the affected messages finalize as
BLOCKED
and
FILTERED
. Insufficient balance therefore does not fail the send call.
错误响应格式为
{success, data, error: {code, message, details, doc_url}, meta: {request_id, timestamp, version}}
。应根据
error.code
的前缀类别(
AUTH_
VALIDATION_
RESOURCE_
BUSINESS_
CONFLICT_
SERVICE_
INTERNAL_
)进行分支处理,而非根据消息文本或单个错误码。包含重试分类的完整46项错误码目录可查看references/errors-and-limits.md
有两个错误码较为特殊:
BUSINESS_003
BUSINESS_004
被记录为请求级错误,但在调用
POST /v3/messages
时,请求会被
202
接受,受影响的消息最终会变为
BLOCKED
FILTERED
状态。因此余额不足不会导致发送调用失败。

Observability

可观测性

Log
meta.request_id
on every response, success or failure — it is the correlation handle for support. Record the mapping from your logical send to the returned
message_id
values, and keep an append-only event history so a reroute's sequence remains auditable. Never log the API key, the webhook signing secret,
payment_details
, or raw recipient message content beyond your retention policy.
无论响应成功或失败,都要记录
meta.request_id
——这是支持团队的关联标识。记录您的逻辑发送与返回的
message_id
值之间的映射,并保留追加式事件历史,以便重新路由的序列可被审计。切勿记录API密钥、Webhook签名密钥、
payment_details
或超出您保留策略的原始收件人消息内容。

Launch checklist

发布检查清单

  • Credentials load from the environment; nothing is committed, and separate keys exist per environment.
  • Client lifecycle matches credential scope: shared for one server-managed key, per request for tenant-supplied credentials.
  • Idempotency-Key
    on every mutating call, derived deterministically.
  • Retry policy distinguishes retryable from terminal by error family.
  • Bulk paths pace against 200 requests per minute and batch to at most 1,000 recipients.
  • Webhook receiver verifies signature and timestamp, returns
    200
    fast, and dedupes.
  • Receiver returns non-2xx on genuine failure so Sent retries.
  • message_id
    to tenant mapping is persisted before sending.
  • request_id
    is logged; secrets and card data are not.
  • Sandbox smoke test passes, then a real send reaches
    DELIVERED
    .
  • Alerting covers webhook
    consecutive_failures
    ,
    429
    volume, and filtered or blocked rates.
  • 凭证从环境变量加载;无硬编码凭证,每个环境使用独立密钥。
  • 客户端生命周期与凭证范围匹配:单服务器管理密钥使用共享客户端,租户提供的凭证则按请求创建客户端。
  • 每个变更请求都携带
    Idempotency-Key
    ,且该密钥由确定性方式生成。
  • 重试策略根据错误类别区分可重试与终端错误。
  • 批量请求按每分钟200次的限制控制节奏,每次批量最多包含1000个收件人。
  • Webhook接收器验证签名和时间戳,快速返回
    200
    ,并进行去重。
  • 接收器在真正失败时返回非2xx状态码,以便Sent进行重试。
  • 在发送前持久化
    message_id
    与租户的映射关系。
  • 记录
    request_id
    ;不记录密钥和卡片数据。
  • 沙箱冒烟测试通过,且至少有一次真实发送通过接收器确认已
    DELIVERED
  • 告警覆盖Webhook
    consecutive_failures
    429
    请求量以及过滤或拦截率。

Verification

验证

Run the local preflight, which needs no credentials and no network:
bash
python3 scripts/preflight.py --self-test
Then verify a real path with
"sandbox": true
, which authenticates and validates without executing, and finally with one live send confirmed to
DELIVERED
through the receiver.
运行本地预检,无需凭证和网络:
bash
python3 scripts/preflight.py --self-test
然后使用
"sandbox": true
验证真实路径,该模式会进行认证和验证但不会执行实际发送,最后通过接收器确认至少一次真实发送已
DELIVERED

Boundaries

边界说明

Use
sent-webhook-engineer
for receiver depth,
sent-routing-strategist
for channel choice,
sent-messaging
for a confirmed one-off send,
sent-two-way-messaging
for inbound and consent,
sent-profile-provisioning
for multi-tenant provisioning, and
migrate-to-sent
when replacing another CPaaS provider.
如需深入了解接收器,请使用
sent-webhook-engineer
;渠道选择请使用
sent-routing-strategist
;确认一次性发送请使用
sent-messaging
;入站消息与同意管理请使用
sent-two-way-messaging
;多租户配置请使用
sent-profile-provisioning
;替换其他CPaaS提供商请使用
migrate-to-sent