Payment streams are non-custodial. The backend never stores user private keys.
- User deploys / interacts with the
StreamPaymentSoroban contract (stellar-contract/src/stream_payment.rs). - User deposits an allowance into contract escrow via
create_stream(requires sender auth on-chain only). - Backend stores only
escrowContractId+contractStreamId— neversenderSecret. - The streaming worker calls permissionless
tick_stream(stream_id)to release one interval payment. Compromise of the backend cannot drain the user's primary account — only the remaining escrowed allowance is at risk, and only via the contract's rate/interval rules.
senderSecretcolumn is alwaysNULL. Existing encrypted secrets are purged by migration20261015160000_delegated_stream_escrow.- API rejects any request that still sends
senderSecret(CUSTODIAL_SECRET_REJECTED).
const stream = await createStream({
senderPublicKey: 'G...',
recipientPublicKey: 'G...',
escrowContractId: 'C...', // StreamPayment contract
contractStreamId: '42', // on-chain stream id
rateAmount: 10,
intervalSeconds: 60,
allowance: 1000,
});Optional platform invoker for RPC submits (cannot spend user primary balances):
STREAM_CONTRACT_ID=C...
# SOROBAN_RPC_URL=...