The fee-abstraction service lets developers pay Stellar transaction fees using app tokens rather than holding XLM. The backend wraps the developer's inner transaction in a Stellar fee-bump transaction signed by the platform fee account.
- Developer builds and signs an inner Stellar transaction.
- Developer calls
POST /api/billing/fee-abstraction/quoteto get the XLM fee and its app-token equivalent. - Developer submits an app-token payment for that amount (off-chain).
- Developer calls
POST /api/billing/fee-abstractionwith the inner XDR and the payment reference. - The backend creates and signs a fee-bump transaction; the caller receives the signed XDR for submission to Horizon.
Returns an estimated fee for wrapping the supplied inner transaction.
Authentication: Bearer token required.
Request body:
{
"innerXdr": "<base64-encoded Stellar transaction XDR>"
}Response 200:
{
"baseFeeStroops": 100,
"feeBumpFeeStroops": 600,
"feeBumpFeeXlm": "0.0000600",
"appTokenAmount": "0.0000060",
"network": "testnet"
}| Field | Description |
|---|---|
baseFeeStroops |
Per-operation base fee in stroops |
feeBumpFeeStroops |
Total outer fee for the fee-bump envelope |
feeBumpFeeXlm |
feeBumpFeeStroops expressed in XLM |
appTokenAmount |
Equivalent app-token amount to charge (based on current XLM/token rate) |
network |
Active Stellar network (testnet or mainnet) |
Errors:
| Status | Code | When |
|---|---|---|
400 |
VALIDATION_ERROR |
innerXdr missing, empty, or not a valid Stellar transaction XDR |
401 |
UNAUTHORIZED |
Missing or invalid Bearer token |
Creates and signs a fee-bump transaction wrapping the supplied inner transaction.
Authentication: Bearer token required.
Request body:
{
"innerXdr": "<base64-encoded Stellar transaction XDR>",
"appTokenPaymentTxId": "<payment reference confirming app-token deduction>"
}Response 200:
{
"feeBumpXdr": "<signed fee-bump transaction XDR>",
"feeAccountPublicKey": "G...",
"feeStroops": 600
}| Field | Description |
|---|---|
feeBumpXdr |
Signed fee-bump transaction XDR; submit directly to Horizon |
feeAccountPublicKey |
Public key of the platform fee account |
feeStroops |
Total fee charged by the fee-bump envelope |
Errors:
| Status | Code | When |
|---|---|---|
400 |
VALIDATION_ERROR |
Missing/empty fields or invalid innerXdr |
401 |
UNAUTHORIZED |
Missing or invalid Bearer token |
500 |
INTERNAL_SERVER_ERROR |
Fee-bumper not configured or signing failed |
The outer fee-bump fee is calculated as:
feeBumpFeeStroops = BASE_FEE × FEE_BUMP_MULTIPLIER × (inner_op_count + 1)
BASE_FEEdefaults to100stroops (override viaSTELLAR_BASE_FEE).FEE_BUMP_MULTIPLIERis3(hardcoded to ensure the fee-bump envelope is competitive).- The app-token equivalent uses an approximate XLM → app-token exchange rate of
0.10 USDC/XLM(for indicative quoting only).
- Signing key: The fee account's Stellar secret key is read from
FEE_BUMPER_SECRET_KEYat runtime. Store this as a secrets-manager or environment secret—never commit it to source control. - Authentication: Both endpoints require a valid developer Bearer token. Unauthenticated requests are rejected with
401. - No double-spend protection: The
appTokenPaymentTxIdfield is recorded in thefee_abstraction.executedevent for audit purposes but is not validated against an on-chain payment in this initial version. Callers must ensure the payment has been deducted before invoking the execution endpoint. - Network isolation: The backend only builds transactions for the configured
STELLAR_NETWORK. Cross-network mixing is rejected.
The fee-abstraction endpoints are mounted under /api/billing and inherit the same REST rate limit applied to all billing routes:
- Window:
REST_RATE_LIMIT_WINDOW_MS(default60000ms) - Max requests:
REST_RATE_LIMIT_MAX_REQUESTS(default100) - Key:
user:<userId>for authenticated requests,ip:<ip>fallback
When the limit is exceeded, a 429 Too Many Requests response is returned with a Retry-After header.
After a successful execution, the fee_abstraction.executed event is emitted:
{
userId: string; // authenticated developer ID
appTokenPaymentTxId: string; // payment reference from the request
feeAccountPublicKey: string; // public key of the fee account
feeStroops: number; // total fee paid in stroops
feeBumpXdr: string; // signed fee-bump XDR
}This event can trigger downstream webhook deliveries if the developer has subscribed to fee_abstraction.executed events.
| Variable | Required | Description |
|---|---|---|
FEE_BUMPER_SECRET_KEY |
Yes | Stellar secret key (S...) for the platform fee account |
STELLAR_BASE_FEE |
No (default 100) |
Base fee per operation in stroops |
STELLAR_NETWORK |
No (default testnet) |
Active network: testnet or mainnet |