Sep31Service
SEP-31 Cross-Border Payments service client.
Provides the Sending Anchor side of SEP-31 by talking to a Receiving Anchor's DIRECT_PAYMENT_SERVER. Wraps the five HTTP endpoints defined by SEP-0031:
GET /info— discover supported assets, limits, and KYC requirements.POST /transactions— initiate a cross-border payment and receive on-chain instructions.GET /transactions/:id— fetch the current state of a transaction.PUT /transactions/:id/callback— register a callback URL for status notifications.PATCH /transactions/:id— update legacy per-transaction fields (deprecated; use SEP-12 instead).
Security posture
HTTPS enforcement. The constructor rejects non-HTTPS serviceUrl values, the companion Companion.fromDomain re-validates the resolved
DIRECT_PAYMENT_SERVER, and putTransactionCallback re-validates the supplied callback URL before any network call.http://is allowed only for the three loopback authorities (localhost,127.0.0.1,[::1], each optionally with a port) so callers can integrate against a local Anchor Platform without standing up a TLS proxy; every other host must use HTTPS. Validation errors do not echo the offending input to avoid log-injection.Path-segment validation. Every transaction id interpolated into a URL is percent-decoded once and matched against the RFC 3986
pcharallow-list (A-Z,a-z,0-9,-,.,_,~,!,$,&,',(,),*,+,,,;,=,:,@). The substring..is additionally rejected to prevent path-traversal attempts, which is stricter than what RFC 3986 alone requires.Redirect handling. The default HTTP client used by this service sets
followRedirects = false. The anchor URL is authoritative; a redirect indicates misconfiguration or an attack. A caller-supplied httpClient is used as-is — the caller is responsible for redirect policy on the client they pass in.Response body caps. Bodies are size-capped before decoding (2 MB for
/info, 256 KB for transaction responses). If the response advertises aContent-Lengthlarger than the cap, or streams more bytes than the cap, Sep31InvalidResponseException is raised before any body content is materialized.Content-Type allow-list. Responses must declare
application/jsonorapplication/problem+json(RFC 7807). Other types raise Sep31InvalidResponseException before body read; this defends against anchors returning HTML error pages that would otherwise reach the error-message extractor.No logging plugin by default. This service does not install Ktor's
Loggingplugin. If a caller supplies a logging-enabled httpClient, the caller is responsible for redaction. JWT bearer tokens, PII (KYC fields, customer ids, refund memos, names), and full request bodies must be filtered upstream.TLS baseline. TLS minimum version and certificate pinning follow the platform Ktor client defaults. Production deployments that require pinning or a higher TLS floor should construct an
HttpClientwith their engine's pinning policy and pass it via the httpClient constructor parameter.
Typical workflow
// 1. Initialize from the receiving anchor's domain.
val sep31 = Sep31Service.fromDomain("anchor.example.org")
// 2. Discover available assets.
val info = sep31.info(jwt = jwtToken)
val usdc = info.receiveAssets["USDC"] ?: error("USDC not supported")
// 3. Initiate a transaction.
val request = Sep31PostTransactionsRequest(
amount = 100.0,
assetCode = "USDC",
fundingMethod = "SWIFT",
senderId = "11111111-1111-1111-1111-111111111111",
receiverId = "22222222-2222-2222-2222-222222222222"
)
val post = sep31.postTransactions(request, jwtToken)
// 4. Poll for status.
val transaction = sep31.getTransaction(post.id, jwtToken)
println("Status: ${transaction.status}")See also:
Companion.fromDomain for automatic configuration via stellar.toml
Sep31PostTransactionsRequest for request construction
Sep31TransactionResponse for transaction state
Parameters
Optional caller-supplied HTTP client. When null, the service constructs a Ktor client with followRedirects = false, content negotiation, and a 30 s request timeout. A caller-supplied client is used verbatim and never closed by this service.
Optional headers attached to every outbound request in addition to Authorization and Content-Type.
Throws
if serviceUrl is neither HTTPS nor HTTP targeting a loopback authority.
Properties
Functions
Fetches the current state of a previously-initiated transaction.
Fetches the Receiving Anchor's supported assets, limits, and KYC requirements.
Updates legacy per-transaction fields on a pending transaction.
Initiates a SEP-31 cross-border payment.
Registers a callback URL the Receiving Anchor will invoke when the transaction status changes.