Skip to main content

Read a live deal in five minutes

No key, no account, no signup. Everything on this page is a real request against the running test network deal, and the responses below are what it returned.

1. List the deals

curl -s https://tranching-production.up.railway.app/api/deals
{
"deals": [
{
"id": 1,
"name": "Bavarian Sky French Auto Leases 5",
"dealContractId": "CB3S3NWG7IUKUBAWAAJPFKVMCIMTRJ73GHZX6YZASRMZPVUGYFLCATJ4",
"payingAgentContractId": "CAXBYHZVHXOP3HQCMXPPVZMDUYEO27CTQQQDMWVNMMGSRCBSJHGIARZW",
"periodDays": 3,
"phase": "AMORTIZING",
"tranches": [ "..." ]
},
{ "id": 2, "name": "CARA7 Demo Series 2", "phase": "FUNDING", "...": "..." }
]
}

phase is read live from the contract, not from the database: FUNDING, AMORTIZING, ENFORCED or MATURED.

2. Get a class and its current state

curl -s https://tranching-production.up.railway.app/api/tranches/1
{
"tranche": {
"id": 1,
"name": "Class A Notes",
"seniority": "SENIOR",
"contractId": "CBHFKNK7UK6YBVXZUWPOMY6LK44FZJSKWHPF4HJBUBV64KC455IJDROK",
"originalFace": "1000000000000",
"assetSymbol": "EURC",
"assetDecimals": 7,
"stats": {
"phase": "AMORTIZING",
"outstanding": "705477067000",
"noteFactorPct": 70.5477,
"coupon": { "allInPct": 2.809, "pricing": "EURIBOR 1M + 0.60% (floor 0%)" },
"cumulative": {
"interestPaid": "633316000",
"principalPaid": "294522933000"
},
"nextPayment": { "dueAt": "2026-08-06T19:15:33.000Z", "estimatedInterest": "165140423" }
}
}
}

Every amount is a string of base units. EURC has 7 decimals, so 705477067000 is 70,547.7067 EURC. Amounts are strings because they do not fit in a JavaScript number without losing the last digits, and the last digits are the ones that make a waterfall balance.

const toDecimal = (baseUnits: string, decimals: number): number =>
Number(BigInt(baseUnits)) / 10 ** decimals;

toDecimal('705477067000', 7); // 70547.7067

3. See who holds the notes and what they were paid

curl -s https://tranching-production.up.railway.app/notes/CBHFKNK7UK6YBVXZUWPOMY6LK44FZJSKWHPF4HJBUBV64KC455IJDROK/holders
[
{
"address": "GCV6OX6GKQOJJGD3DTF5AIENK3EKR64OPHCNCX5MGZUT2KTDD5QGFFRI",
"units": "800",
"sharePct": 80,
"interestReceived": "632916751",
"principalReceived": "274883474800"
},
{
"address": "GBXMM4TTZO3T7Y7VAZLXHZDTUEXODNU7NHA744FWFP5VBFGGCV22PGKB",
"units": "200",
"sharePct": 20,
"interestReceived": "399248",
"principalReceived": "19639458200"
}
]

The second holder bought 200 notes in the middle of a period. Look at the two numbers: they received 20% of the principal, because principal follows the holder at the end of the period, but only 0.0399 EURC of interest, because the coupon is split by the days each side actually held the notes. That is the whole day weighting rule, visible in one response.

4. Read the contract directly, without our API

Our API is a cache. The contract is the source. Anyone can query it:

stellar contract invoke \
--id CB3S3NWG7IUKUBAWAAJPFKVMCIMTRJ73GHZX6YZASRMZPVUGYFLCATJ4 \
--source-account <any-account> --network testnet --send=no \
-- get_note_factors
["705477067","10000000","10000000"]

Three classes, in seniority order. Factors are in units where 10000000 is 100%, so Class A stands at 70.5477067% and B and C are untouched.

From TypeScript, without a key:

import { rpc, TransactionBuilder, Contract, BASE_FEE, Account, Keypair, scValToNative } from '@stellar/stellar-sdk';

const server = new rpc.Server('https://soroban-testnet.stellar.org');
const tx = new TransactionBuilder(new Account(Keypair.random().publicKey(), '0'), {
fee: BASE_FEE,
networkPassphrase: 'Test SDF Network ; September 2015',
})
.addOperation(new Contract(DEAL_ID).call('get_note_factors'))
.setTimeout(30)
.build();

const simulation = await server.simulateTransaction(tx);
const factors = scValToNative(simulation.result!.retval) as bigint[];

Simulation costs nothing and needs no signature. Every get_* function on every contract can be read this way.

Next