> For the complete documentation index, see [llms.txt](https://docs.kumbaya.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kumbaya.xyz/developers/building-agents/recipes.md).

# Integration recipes

Short, copy-pasteable examples for the most common things integrators and agents do on Kumbaya. All of these are grounded in the actual API and contract surface - no pseudocode.

> Building an LLM agent rather than a script? Most of these flows already exist as one-call tools and skills in the [Kumbaya Agent Kit](/developers/building-agents/agent-kit.md) - e.g. buying a token (recipe 3) is the `swap` tool, and sweeping creator earnings (recipe 4) is `claim_fees` + `withdraw_tips`. Use these recipes when you want the raw calls; use the kit when you want the model to drive.

## 1. Watch for new launches (live)

Subscribe to the indexer and react as new tokens are deployed.

```ts
import { createClient } from 'graphql-ws'
import { WebSocket } from 'ws'

const client = createClient({
  url: 'wss://ql.kumbaya.xyz/v1/graphql',
  webSocketImpl: WebSocket,
})

const unsubscribe = client.subscribe(
  {
    query: `
      subscription NewLaunches($chainId: Int!) {
        FireToken(
          where: { chainId: { _eq: $chainId } }
          order_by: { createdAt: desc }
          limit: 10
        ) {
          address creator createdAt
          pool { id }
          marketCapUSD graduationProgress
        }
      }
    `,
    variables: { chainId: 4326 },
  },
  {
    next: ({ data }) => {
      const latest = data?.FireToken?.[0]
      if (latest && Date.now() / 1000 - Number(latest.createdAt) < 60) {
        console.log('New launch:', latest.address)
        // your hook: e.g. evaluate, snipe, post a tweet
      }
    },
    error: console.error,
    complete: () => console.log('subscription ended'),
  },
)
```

## 2. "Heating up" - find tokens with rising volume

The indexer tracks 30m/1h/2h-prior buy and sell counts plus velocity ratios. This is exactly how Kumbaya's "Heating up" feed is computed.

```graphql
query HeatingUp($chainId: Int!) {
  FireToken(
    where: {
      chainId:    { _eq: $chainId }
      graduated:  { _eq: false }
      buysLast1h: { _gte: 5 }
      buyVelocity: { _gt: 1.5 }
    }
    order_by: { buyVelocity: desc }
    limit: 20
  ) {
    address graduationProgress marketCapUSD
    buysLast1h buysPrev1h sellsLast1h
    buyVelocity sellVelocity
    netTokenFlowLast1h buyerCount
  }
}
```

## 3. Buy a launchpad token - quote then swap

Use the Exchange API for routing; submit calldata yourself.

```ts
import { createWalletClient, http, parseEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const wallet  = createWalletClient({
  account,
  transport: http('https://mainnet.megaeth.com/rpc'),
})

const tokenIn  = '0x4200000000000000000000000000000000000006' // WETH
const tokenOut = '0xYOUR_FIRE_TOKEN'
const amountIn = parseEther('0.1')

// 1. Quote
const params = new URLSearchParams({
  chainId:         '4326',
  tokenInAddress:  tokenIn,
  tokenOutAddress: tokenOut,
  amount:          amountIn.toString(),
  slippageBps:     '100',                  // 1%
  recipient:       account.address,
  type:            'exactIn',
})
const quote = await fetch(
  `https://exchange.kumbaya.xyz/api/v1/quote?${params}`,
).then(r => {
  if (!r.ok) throw new Error(`quote failed: ${r.status}`)
  return r.json()
})

// 2. Submit
const txHash = await wallet.sendTransaction({
  to:    quote.methodParameters.to,
  value: BigInt(quote.methodParameters.value),
  data:  quote.methodParameters.calldata,
})
```

For native ETH ↔ token swaps the API handles wrapping for you. For pre-approved ERC-20 → ERC-20, do the `approve` once, then run the swap.

## 4. Sweep your creator earnings

For a graduated launchpad token where you (or an address you control) is the creator:

```ts
import { fireStreamAbi } from './abis/fireStream'
import { fuelVaultAbi }  from './abis/fuelVault'

const FIRE_STREAM = '0x94d9582130745d0e2a1757dDEd8e730F5CDAd759'
const FUEL_VAULT  = '0x5aFaB54ac28a3bd485751146470D053b4FF11c81'

// 1. Sweep streaming fees (anyone can call; you receive your share)
await wallet.writeContract({
  address: FIRE_STREAM,
  abi:     fireStreamAbi,
  functionName: 'claimFees',
  args:    [tokenAddress],
})

// 2. Withdraw FuelVault liquid bucket (only you can call; first call after grad also unlocks pre-grad vested)
await wallet.writeContract({
  address: FUEL_VAULT,
  abi:     fuelVaultAbi,
  functionName: 'withdraw',
  args:    [tokenAddress],
})
```

Run on a schedule (e.g. daily) for any token you've launched.

## 5. Find every token *I* created (and what they've earned)

```graphql
query MyTokens($creator: String!, $chainId: Int!) {
  FireToken(
    where: { creator: { _eq: $creator }, chainId: { _eq: $chainId } }
    order_by: { createdAt: desc }
  ) {
    address graduated graduationProgress marketCapUSD
    feesCollectedUSD volumeUSD
    pool { id token0 { symbol } token1 { symbol } }
  }
  FuelCreatorBucket(
    where: { creator: { _eq: $creator }, chainId: { _eq: $chainId } }
  ) {
    token { address }
    liquid vested unlocked
  }
}
```

## 6. Trigger graduation on tokens that are ready

```ts
import { fireLaunchAbi }     from './abis/fireLaunch'
import { fireGraduatorAbi }  from './abis/fireGraduator'

const FIRE_LAUNCH = '0x69FE0908F1211dE66F7067021998f28A5693ABbD'
const GRADUATOR   = '0xCCA4759167Ef4214dF98Eb7cBbCE47EB9B4F2585'

// Find all tokens whose tick crossed but no condition recorded yet
const { data } = await fetch('https://ql.kumbaya.xyz/v1/graphql', {
  method:  'POST',
  headers: { 'content-type': 'application/json' },
  body:    JSON.stringify({
    query: `query {
      FireToken(
        where: {
          chainId: { _eq: 4326 }
          readyToGraduate: { _eq: true }
          graduationConditionRecordedAt: { _is_null: true }
        }
        limit: 50
      ) { address }
    }`,
  }),
}).then(r => r.json())

for (const { address } of data.FireToken) {
  try {
    // Note: recordGraduationCondition lives on FireLaunch, not FireGraduator.
    await wallet.writeContract({
      address: FIRE_LAUNCH,
      abi:     fireLaunchAbi,
      functionName: 'recordGraduationCondition',
      args:    [address],
    })
    console.log('Recorded grad condition for', address)
  } catch (err) {
    console.warn('Skipped', address, (err as Error).message)
  }
}
```

After `gracePeriodDuration` elapses (read live from `FireRegistry.gracePeriodDuration()` - see [Live registry config](/developers/building-agents/registry-config.md)), call **`FireGraduator.graduate(token)`** to actually finalize.

## 7. Search-as-you-type token picker

Build a token-picker UI without running your own index:

```ts
async function autocomplete(prefix: string, chainId = 4326) {
  const params = new URLSearchParams({ q: prefix, chainId: String(chainId) })
  const res = await fetch(
    `https://search.kumbaya.xyz/api/v1/autocomplete?${params}`,
  )
  const json = await res.json()
  return json.suggestion // { completion, symbol, name, address, matchType } | null
}
```

For full search results (tokens + pools, multiple matches):

```ts
async function search(q: string, chainId = 4326) {
  const params = new URLSearchParams({
    q,
    chainId: String(chainId),
    limit:   '20',
    visibility: 'all',     // or 'verified' / 'trusted'
  })
  const res = await fetch(`https://search.kumbaya.xyz/api/v1/search?${params}`)
  return res.json() // { tokens: [...], pools: [...] }
}
```

Public, no auth, rate-limited per IP.

## 8. Newest swaps for a pool (REST, no GraphQL)

```ts
const swaps = await fetch(
  `https://exchange.kumbaya.xyz/api/v1/pools/${poolId}/swaps?limit=50`,
).then(r => r.json())
```

Where `poolId` is the `address-chainId` composite (e.g. `0xabc...-4326`).

## 9. Read protocol-level config live

Don't hardcode tunables. Read on demand:

```ts
import { fireRegistryAbi } from './abis/fireRegistry'

const REGISTRY = '0x286B4CB284270C6aE2844875BC92ed7E4C21c4C6'
const reads = await client.multicall({
  contracts: [
    { address: REGISTRY, abi: fireRegistryAbi, functionName: 'gracePeriodDuration' },
    { address: REGISTRY, abi: fireRegistryAbi, functionName: 'forceGraduationDelay' },
    { address: REGISTRY, abi: fireRegistryAbi, functionName: 'burnCountdownDuration' },
    { address: REGISTRY, abi: fireRegistryAbi, functionName: 'getStreamingRecipientsTotalBps' },
  ],
  allowFailure: false,
})
```

See [Live registry config](/developers/building-agents/registry-config.md) for the full field list.

## 10. Build a creator-fee dashboard

Combine indexer + on-chain reads:

```ts
// 1. From indexer: every token this creator has launched (and lifetime fees)
const indexed = await graphql(`
  query Creator($creator: String!, $chainId: Int!) {
    FireToken(where: { creator: { _eq: $creator }, chainId: { _eq: $chainId } }) {
      address graduated feesCollectedUSD marketCapUSD
    }
  }
`, { creator, chainId: 4326 })

// 2. From chain: claimable balances right now (FuelVault liquid + FireStream pending)
for (const token of indexed.FireToken) {
  const bucket = await client.readContract({
    address: FUEL_VAULT,
    abi:     fuelVaultAbi,
    functionName: 'creatorBuckets',
    args:    [creator, token.address],
  })
  // bucket.liquid (uint128), bucket.vested (uint128), bucket.unlocked (bool)
  // - for graduated tokens, bucket.vested unlocks on next withdraw
}
```

`FireStream` doesn't expose a "preview pending fees" view - to know what the next `claimFees` would pay out, you'd simulate it (e.g. with `eth_call`) or just call it and parse the `BeneficiaryPaid` event from the receipt.

## More

* [**Auto-launch a token**](/developers/building-agents/launching-programmatically.md) - full programmatic launch recipe
* [**SIWE auth**](/developers/building-agents/siwe.md) - get a JWT for the Client API
* [**Live registry config**](/developers/building-agents/registry-config.md) - every tunable + how to read it
