Resource lifecycles

Every long-lived resource in the v2 API exposes a status field whose value is one of an explicit, enumerated set of lifecycle states. State changes — and only state changes — fire webhook events. This page is the source of truth for both.

State machine is the explicit enumeration of every state a resource can be in plus the allowed transitions between them. Knowing the full set up-front lets you (a) wire deterministic UI, (b) reconcile against your own ledger, and (c) subscribe to exactly the events you care about.

Pool

pending ──init confirmed──▶ live ──reserve >= threshold──▶ migration_triggered ──DAMM v2 active──▶ migrated
   │                          │                                                        │
   └─────────────────────── failed ◀──────────────────────────────────────────────────┘
StateMeaning
pendingRow inserted in launched_crews; on-chain init tx not yet finalized.
liveBonding curve initialized; trading open.
migration_triggeredQuote reserve crossed migrationQuoteThreshold from the curve config.
migratedLiquidity moved to DAMM v2; bonding curve closed.
failedInit tx failed on-chain.

Events: pool.created, pool.live, pool.migration_triggered, pool.migrated, pool.failed.

Airdrop

tree_built ──init confirmed──▶ initialized ──first claim──▶ claiming ──all leaves claimed──▶ fully_claimed
                                     │                          │
                                     └──── admin withdraw ──────┴──▶ vault_drained

Events: airdrop.tree_built, airdrop.initialized, airdrop.claim_started, airdrop.claimed (fires per claim), airdrop.fully_claimed, airdrop.vault_drained.

Stake

unstaked ──stake_nft──▶ staked ──unstake_nft──▶ unstaked
              │
              └── burn_asset ──▶ burned

Events: stake.acquired, stake.released. (Note: nft.burned is fired on the NFT resource, not on the stake.)

Gold Lock

unlocked ──lock_gold──▶ locked ──duration elapsed──▶ eligible_for_unlock ──unlock_gold──▶ unlocked

Events: gold.locked, gold.unlock_eligible, gold.unlocked.

NFT

                  ┌──stake_nft──▶ staked ──unstake_nft──▶ minted
mint_nft ──▶ minted
                  └──burn_asset──▶ burned

Events: nft.created, nft.staked, nft.unstaked, nft.burned.

Token

created ──revoke mint─────▶ mint_authority_revoked
       │
       └─revoke freeze───▶ freeze_authority_revoked ──remaining revoke──▶ fully_immutable

Events: token.created, token.mint_authority_revoked, token.freeze_authority_revoked, token.fully_immutable.

Transaction

unknown ──signature observed──▶ submitted ──landed in block──▶ processing ──supermajority──▶ confirmed ──slot finalized──▶ finalized
                                                                                    │
                                                                                    └── on-chain error ──▶ failed

Events: transaction.submitted, transaction.confirmed, transaction.finalized, transaction.failed.

Fee claims (action events)

Fee claims are not a long-lived resource — they're one-shot actions against a pool. They don't carry a status field, but each successful claim emits an event you can subscribe to:

  • fee_claim.executed — a DBC, DAMM v2, or surplus claim transaction finalized.
  • fee_claim.split_executed — a claim with kind: "split" finalized; the same recipient breakdown that was on the request is included on the event.

Detection modes

Not every transition can be detected from inside the API process. Each event in the catalog (GET /v2/webhook-event-types) carries a detection field:

  • synchronous — fires from the route handler as part of the inbound request. Always reliable. Examples: pool.created, airdrop.tree_built. The catalog also defines webhook.test_event, a meta-event you can fire on-demand via POST /v2/webhook-subscriptions/{id}/test.
  • tx_confirmed — fires after the user-signed transaction we returned finalizes on-chain. Requires the transaction watcher to be online. Examples: pool.live, stake.acquired, gold.locked.
  • polling_required — needs a background poller comparing on-chain state at intervals. Not yet shipped. Examples: pool.migrated, gold.unlock_eligible, airdrop.fully_claimed.

See Webhooks for delivery, signing, and retry semantics.