Skip to main content

FTF Lifecycle

A subscription is the request to invest in an FTF. A holding is the live investment record created once an accepted subscription has been processed.

After calling /subscribe, use /subscription to track the returned subscription.uid until holdingUid is available. Once holdingUid exists, use /holding/{entity_code}/{holdingUid} or /holding and treat the holding as the source of truth.

The diagrams below show the typical lifecycle for Fixed and Extendable holdings. Boxes represent object statuses, and arrows represent lifecycle processes that move a holding from one status to another. Where a lifecycle process emits a public /event, the event type is shown in green on the arrow. Dashed connectors provide context, such as a rolled holding continuing through the same lifecycle, and do not represent public events.

How to read the statuses​

Pending means the holding has been created from an accepted subscription, but has not yet been issued. Cash has not yet moved at this point — the wire from the entity arrives during the issuance step, not at subscription.

Issued means the holding is live. While a holding is issued, its economics or structure may still change through lifecycle processes such as adjustment or split.

CutOff means the holding has reached its cut-off point. The maturity action is locked and can no longer be changed through the API. From this point, TreasurySpring processing determines the next lifecycle step, such as redemption, roll, extension, or finalization depending on the product type and maturity action. CutOff is a holding status, not currently a public event.

PendingWithdrawal means a redemption has been requested but the cash payout to the entity's bank account has not yet been confirmed.

Redeemed means the holding has completed its lifecycle and has been redeemed.

Cancelled means a previously-issued holding was unwound before its natural maturity — for example because funding never arrived, or operational reversal. Emits a CANCELLED event.

Maturity actions​

A holding's maturity action is the instruction for what happens to its value when it matures. Every holding exposes its current action(s) as maturityActions (see the Holding model); a holding may have more than one when its value is split across actions. The maturity action is what determines which lifecycle process runs at cut-off:

  • HOLD — mature to cash, held within the cell.
  • REDEEM — mature and withdraw the proceeds to the entity's bank account.
  • ROLL — reinvest into a new holding of the same FTF.
  • SWITCH — reinvest into a different FTF.

While a holding is Issued, the action can be changed via PUT/holding/{entity_code}/{holding_uid}/maturity-action. Once the holding reaches CutOff the action is locked and TreasurySpring processing applies it. After maturity, maturityActions continues to reflect the action(s) that were applied.

Portal labels and API enum values​

The TreasurySpring portal labels these four actions in plain language, and the label it shows depends on the product type. There are still only four values — the portal never offers a fifth action that the API is missing. If you are reconciling a screen against the API, this is the mapping:

API valuePortal label — FixedPortal label — Extendable (before the final period)Portal label — Extendable (final period)
ROLLAuto-rollAuto-extendAuto-roll
SWITCHSwitchnot offeredSwitch
HOLDHoldDo not extend (Hold)Hold
REDEEMWithdrawDo not extend (Withdraw)Withdraw

The one to know is ROLL: on an extendable holding before its final period the portal calls it Auto-extend, because it continues the same holding with a new maturity date rather than creating a new one. See Extendable holding lifecycle below.

Splitting a holding's value across actions​

A holding's value does not have to go one way at maturity. Send actions instead of action on PUT/holding/{entity_code}/{holding_uid}/maturity-action to split maturityValue across several actions, each with its own amount in the holding's currency:

{
"reason": "Need proceeds",
"actions": [
{ "action": "ROLL", "amount": 6000000.00 },
{ "action": "REDEEM", "amount": 4341950.04 }
]
}

Notes on the split form:

  • action and actions are mutually exclusive — send exactly one of them. action remains valid and applies the action to the whole of maturityValue.
  • Either form replaces every maturity action currently set on the holding, so send the complete instruction each time. A single-action request against a holding that is currently split will collapse it back to one action.
  • Amounts must not exceed maturityValue. Anything you leave unallocated becomes a HOLD action.
  • A SWITCH leg carries its own indicationUid; the top-level indicationUid is only for the single-action form.
  • Read the current split back from maturityActions on GET/holding/{entity_code}/{holding_uid} or GET/holding/{entity_code}/{holding_uid}/maturity-action.

When the actions on a holding are not all compatible with each other, TreasurySpring splits the holding at cut-off so each part can follow its own path — that produces a SPLIT event and a second holding uid.

Default maturity action is ROLL

If a subscription request omits maturityAction, the holding defaults to ROLL rather than REDEEM. A holding left untouched at cut-off will be reinvested in the next FTF of the same product instead of being paid out to the entity's bank account.

This is an important detail worth setting explicitly. If your workflow expects cash on maturity, please send maturityAction: "Redeem" at subscribe time, or update it via the maturity-action endpoint while the holding is Issued.

Dates and times​

The API uses three distinct representations for temporal values. Knowing which is which avoids off-by-an-hour bugs around daylight saving.

KindExampleNotes
Date"2024-01-01"A calendar date with no time and no timezone. Fields such as issueDate, maturityDate, subscriptionDate(s), and valueDate.
Datetime"2024-01-01T12:15:00+00:00"An instant in ISO 8601, always timezone-aware (carries a UTC offset). Fields such as Subscription.cutoffDatetime, Holding.cutoffDatetime, Indication.created, Indication.expiry, and Task.expiry. Parse these directly.
Time"12:15:00"A naive time-of-day in London local time (Europe/London), with no date and therefore no UTC offset. The only field of this kind is Indication.cutoffTime (see Cut-off timing).

Every datetime the API returns is timezone-aware, so you can compare and convert it without extra context. The single exception is Indication.cutoffTime, covered below.

Cut-off timing​

For a vast majority of products, daily cut-off is 12:15 London time. Some products operate on their own schedule — UK T-bills, for example, have a different cut-off — so when scheduling work against the deadline, please read the authoritative value from the object you're working with rather than hardcoding a time:

ObjectFieldTypeWhat it gives you
IndicationcutoffTimetime (naive)Wall-clock time-of-day in London local time (Europe/London), the same for every subscriptionDate. Combine it with the subscriptionDate you intend to use to compute the cut-off datetime.
SubscriptioncutoffDatetimedatetime (timezone-aware)Cut-off datetime for the chosen subscriptionDate, already calendar-adjusted. Available as soon as the subscription is created.
HoldingcutoffDatetimedatetime (timezone-aware)Cut-off datetime for the current period of the holding, calendar-adjusted. The authoritative value for any scheduling against the live position.

Indication.cutoffTime is the lightest-weight handle — useful before any subscription exists, e.g. to warn a user that they're about to submit a subscription close to cut-off. Once a subscription is placed, Subscription.cutoffDatetime is the precise value. Once a holding is issued, Holding.cutoffDatetime is the source of truth for the live position.

cutoffTime carries no UTC offset

cutoffTime is a naive time-of-day: it has no date and therefore no UTC offset. Because London observes daylight saving, the same 12:15 wall-clock time is 12:15Z under GMT (winter) but 11:15Z under BST (summer). Do not treat cutoffTime as UTC or as your own local time. To get an unambiguous instant, localise combine(subscriptionDate, cutoffTime) in the Europe/London zone — or simply read Subscription.cutoffDatetime / Holding.cutoffDatetime, which are already timezone-aware.

Cut-off schedules may evolve

Cut-off times can change over time. Reading the field from the object directly insulates your integration from those changes.

Subscription, funding, and late wires​

Cash moves into the TreasurySpring cell at issuance, not at subscription. Submitting /subscribe creates a subscription record (and, after acceptance, a Pending holding) but does not reduce the entity's cash on hold in TreasurySpring.

If cash arrives before the cut-off of the requested subscription date, the holding issues on that date and the ISSUED event fires. If cash arrives after that cut-off, the holding does not error: TreasurySpring automatically re-targets it to the next available subscription date for the same FTF. The visible effect is that subscriptionDate, issueDate, and maturityDate shift forward by a day (or to the next business day for that product).

For reconciliation, treat the subscriptionDate on the holding as the source of truth once issuance happens — the subscription you originally submitted may show an earlier date.

Rolls produce two non-overlapping holdings​

A ROLL action at cut-off creates a new holding rather than extending the existing one. The two holdings are non-overlapping in time:

  • The original holding's maturityDate becomes the new holding's issueDate (or the next available subscription date).
  • Both records remain queryable — the old holding moves to Redeemed, the new one starts at Pending then Issued.

When aggregating positions for reporting, use issue/maturity dates as the period boundaries to avoid double-counting. The SUBSCRIBED event for the successor holding fires immediately after the predecessor's redemption process completes.

Partial and early redemption (maturity value adjustment)​

If part of a holding's value is redeemed before maturity, TreasurySpring uses a maturity value adjustment (MVA) rather than a separate fee charge. The process is:

  1. The original holding is Split into two — the portion staying invested keeps its terms; the portion being withdrawn is segregated.
  2. The withdrawing portion is Adjusted — its maturityValue is reduced to reflect early-exit pricing.
  3. The adjusted portion is then Redeemed to the entity's bank account.

This produces three events for one logical "partial redemption": SPLIT, ADJUSTED, then REDEEMED. There is no separate fee field — the MVA is folded into the holding's maturityValue.

Fixed holding lifecycle​

Fixed holdings have a simpler lifecycle: they are created, issued, reach cut-off, and are then either redeemed or rolled into a new holding.

Fixed holding lifecycle

Extendable holding lifecycle​

Extendable holdings follow the same initial lifecycle, but may move from cut-off back to issued when extended. This can happen multiple times before the holding enters its final period and is eventually redeemed or rolled. The final-period boxes represent the same holding after Finalize; a new holding is only created when a holding is rolled.

Extendable holding lifecycle

Each extension of an extendable holding is recorded with its own yield, price per share, and new maturity date. To retrieve that history (most recent first), call GET/holding/{entity_code}/{holding_uid}/extension. Fixed holdings have no extensions.

Choosing whether an extendable extends​

There is no separate "auto-extend" action. On an extendable holding that is not yet in its final period, ROLL is auto-extend — the portal labels it that way for exactly this reason. It continues the same holding, moving its maturity out to extendedMaturityDate, rather than creating a new holding the way ROLL does on a fixed holding.

To stop an extendable extending and send it into its final period, set HOLD or REDEEM — the two "do not extend" instructions:

actionAt the next option-date cut-offAt the final maturity date
ROLLHolding extends — same uid, new maturityDate. Emits EXTENDED.— (repeats until you say otherwise)
HOLDHolding enters its final period. Emits FINALIZED.Matures to cash, held within the cell.
REDEEMHolding enters its final period. Emits FINALIZED.Proceeds withdrawn to the entity's bank account.

Two things to watch:

  • The deadline is the option-date cut-off, not the maturity date. Set the action while the holding is Issued and before cutoffDatetime; after that it is locked.
  • SWITCH is not available on an extendable before its final period. Switch into a different FTF once the holding is in its final period (finalized: true), or withdraw and subscribe separately.

Extendable holdings expose type: "Extendable", finalized, extensionOptionDate and extendedMaturityDate on GET/holding, so you can tell from the API alone whether ROLL currently means extend or roll. finalized: true means the holding is in its final period, and extensionOptionDate / extendedMaturityDate are then null.

You can also split the decision — extend part of the holding and withdraw the rest — by sending actions with an amount per leg. See Splitting a holding's value across actions. TreasurySpring splits the holding at cut-off so the extending part carries on and the rest goes to its final period, which emits a SPLIT event.

Reading an extendable's terms​

GET/holding returns the full extension term structure alongside the yields. All of these are null on a fixed holding.

FieldMeaning
nextYieldyield the holding would earn if it extends
nextFinalYieldyield it would earn in the final period reached from the next extension
finalYieldyield of the final period reached from the current one
extensionDayslength of the current extension period, in calendar days
finalDayslength of the final period, in calendar days
extensionOptionDatenext option date — null once finalized is true
extendedMaturityDatematurity the holding would move to if it extends
extensionStartDate / extensionStartValuewhen the current extension began, and its value then

extensionDays and finalDays are day counts, not counts of extensions — a holding with extensionDays: 30 and finalDays: 98 extends a month at a time and runs 98 days once finalized. They are the same two values the indication model calls extensionDays and finalDays.

Calendar days, business-day dates

extensionDays and finalDays are calendar days. They describe an unadjusted schedule: TreasurySpring advances the schedule by that many calendar days and then rolls the resulting date onto a business day in the holding's calendars. So the realised gap between two consecutive option dates is usually, but not always, extensionDays.

Treat them as the product's period length, not as arithmetic you can apply to a date. To know when the next decision actually falls, read extensionOptionDate and extendedMaturityDate — those are the adjusted dates. An option date can also be skipped entirely for a given product, which rolls that period into the next one.

The two timing fields below go the other way: noticeDate and selectableNextDatetime are derived by counting business days back from cut-off and maturity respectively.

nextYield is null until the next period is priced

nextYield and nextFinalYield are null on the large majority of live extendable holdings. A continuation yield is locked only once TreasurySpring has priced the next period for a holding that is actually going to extend — a holding set to hold or withdraw at maturity never gets one. null means not yet priced, not not available.

Before that, call GET/holding/{entity_code}/{holding_uid}/indication — the indications available against the holding carry indicativeYield and indicativeFinalYield for the terms it could continue into.

Both are also null once finalized is true, because there is no next period.

Two timing fields help you act before the window shuts: noticeDate is the last business day before cut-off, and selectableNextDatetime is the point from which a SWITCH becomes selectable on the holding.

The table below summarises the lifecycle processes shown in the diagrams. These process names are descriptive labels used in this guide; they may not exactly match internal TreasurySpring task names. Some transitions are initiated by API activity, while others are TreasurySpring scheduled or operational processes based on the current holding state and selected maturity action. The public event column shows the /event type emitted when that process produces an event. If no event is listed for a status change, query /holding to observe the latest state.

Lifecycle processApplies toMain effectWhat drives itPublic event
SubscribeFixed, ExtendableCreates a holding from an accepted subscriptionClient request followed by accepted subscription processingSUBSCRIBED
IssueFixed, ExtendableMoves holding Pending to Issued; cash moves into the cell at this pointTreasurySpring issue processingISSUED
AdjustFixed, ExtendableUpdates holding economics or key dates (including MVA for early/partial redemption)TreasurySpring operational change while the holding is issuedADJUSTED
SplitFixed, ExtendableSplits one holding into separate holdingsTreasurySpring operational change while the holding is issuedSPLIT
Cut offFixed, ExtendableMoves holding Issued to CutOffScheduled TreasurySpring process once the holding reaches cutoffDatetime
RedeemFixed, ExtendableMoves holding CutOff to RedeemedTreasurySpring maturity processing based on the selected maturity actionREDEEMED
RollFixed; Extendable final period onlyCreates the next (non-overlapping) holding from a cut-off holdingTreasurySpring maturity processing based on the selected maturity actionSUBSCRIBED, then ISSUED
ExtendExtendable onlyContinues the holding with a new maturity dateTreasurySpring extendable maturity processing before the final periodEXTENDED
FinalizeExtendable onlyMoves the same holding from CutOff to Issued in its final periodTreasurySpring extendable maturity processing into the final periodFINALIZED
CancelFixed, ExtendableUnwinds a previously-issued holding (e.g. funding never arrived)TreasurySpring operational processCANCELLED

For reconciliation, use public events to detect lifecycle changes and use /holding/{entity_code}/{holdingUid} to retrieve the current authoritative holding state.