> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tipstack.fun/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a Crypto Payment Intent — POST /payments/intent

> Generate a Solana transaction for a supporter to sign and submit. Handles direct transfers and token swaps automatically, with a 2% platform fee.

Generate a signed-ready Solana transaction for a supporter to sign and submit to the network. The endpoint resolves the creator by any supported identifier, selects the optimal execution route — direct transfer or Jupiter swap — and returns a Base64-serialized versioned transaction alongside quote metadata. After the supporter signs and submits the transaction, call [`POST /solana/tips/create`](/api/tips/create) to record the tip on Tip Stack.

## Request

**`POST https://tipstack.fun/api/payments/intent`**

<ParamField body="creatorId" type="string" required>
  The creator to tip. Accepts a Tip Stack user ID, Solana wallet address, Twitter handle (with or without `@`), Discord handle, or `.sol` domain.
</ParamField>

<ParamField body="amount" type="number" required>
  The token amount to send, expressed in human-readable units (e.g. `1.5` for 1.5 SOL or 1.5 USDC). When `amountUsd` is also provided, `amount` is ignored.
</ParamField>

<ParamField body="amountUsd" type="number">
  USD amount to send. When provided, overrides `amount` and is automatically converted to token units using the live Jupiter price feed. Use this for consistent USD-denominated tips regardless of the token the supporter holds.
</ParamField>

<ParamField body="inputTokenMint" type="string" required>
  The Solana mint address of the token the supporter is sending (e.g. `So11111111111111111111111111111111111111112` for native SOL or `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` for USDC).
</ParamField>

<ParamField body="sourceWalletAddress" type="string" required>
  The supporter's wallet public key. This is set as the transaction fee payer and the token source.
</ParamField>

<ParamField body="tokenSymbol" type="string">
  Human-readable symbol for the input token (e.g. `SOL`, `USDC`, `BONK`). Used for display purposes in the response quote and tip record. Does not affect routing.
</ParamField>

## Response

<ResponseField name="success" type="boolean">
  `true` when a transaction was successfully generated.
</ResponseField>

<ResponseField name="intentId" type="string">
  Unique intent identifier prefixed with `pi_`. Pass this to downstream systems for tracking.
</ResponseField>

<ResponseField name="status" type="string">
  Always `requires_action` — the transaction is ready for the supporter to sign but has not been submitted yet.
</ResponseField>

<ResponseField name="transaction" type="string">
  Base64-encoded, serialized Solana `VersionedTransaction`. Deserialize this client-side, sign it with the supporter's wallet, and submit it to the Solana network. See the [usage note](#using-the-transaction) below.
</ResponseField>

<ResponseField name="quote" type="object">
  <Expandable title="quote fields">
    <ResponseField name="quote.outAmount" type="string">
      The amount the creator will receive, in the output token's raw units (lamports or token base units).
    </ResponseField>

    <ResponseField name="quote.priceImpactPct" type="number">
      Estimated price impact as a percentage. `0` for direct transfers.
    </ResponseField>

    <ResponseField name="quote.amountUsd" type="number">
      The USD value of the tip at time of intent creation.
    </ResponseField>

    <ResponseField name="quote.tokenSymbol" type="string">
      Token symbol or mint address used for display.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="executionMode" type="string">
  `sync` for standard on-chain submission; `async` when the transaction uses gasless landing (Jito bundles). For `async` transactions, submit via a Jito-compatible RPC endpoint.
</ResponseField>

<ResponseField name="provider" type="string">
  The routing engine selected by Tip Stack. One of `direct-transfer` (no swap needed), `jupiter-ultra`, or `jupiter-v6`. The engine is chosen automatically based on the token pair and creator settings.
</ResponseField>

<ResponseField name="lastValidBlockHeight" type="number">
  The last Solana block height at which this transaction remains valid. If the transaction is not submitted before this block, it will be rejected. Fetch a fresh intent if expiry is reached.
</ResponseField>

<ResponseField name="settings" type="object">
  <Expandable title="settings fields">
    <ResponseField name="settings.yieldEnabled" type="boolean">
      Whether the creator has enabled yield routing (JitoSOL). When `true`, swaps target JitoSOL as the output token.
    </ResponseField>

    <ResponseField name="settings.gaslessEnabled" type="boolean">
      Whether the creator has enabled gasless tips. When `true`, the transaction uses managed landing and `executionMode` will be `async`.
    </ResponseField>

    <ResponseField name="settings.autoConvertUsdc" type="boolean">
      Whether the creator's account auto-converts incoming tokens to USDC. Reflected here for informational use on the frontend.
    </ResponseField>
  </Expandable>
</ResponseField>

## Using the transaction

After receiving the response, deserialize the Base64 transaction, request the supporter's signature, and submit it to Solana. Once you have a confirmed `txSignature`, call [`POST /solana/tips/create`](/api/tips/create) to record the tip.

```typescript TypeScript theme={null}
import { Transaction, VersionedTransaction, Connection } from '@solana/web3.js';

// 1. Create the intent
const { transaction: txBase64, lastValidBlockHeight } = await fetch(
  'https://tipstack.fun/api/payments/intent',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      creatorId: 'monalisa.sol',
      amount: 0.1,
      inputTokenMint: 'So11111111111111111111111111111111111111112',
      sourceWalletAddress: supporterWallet.publicKey.toBase58(),
      tokenSymbol: 'SOL',
    }),
  }
).then((r) => r.json());

// 2. Deserialize, sign, and submit
const txBytes = Buffer.from(txBase64, 'base64');
const tx = VersionedTransaction.deserialize(txBytes);
const signedTx = await supporterWallet.signTransaction(tx);

const connection = new Connection('https://api.mainnet-beta.solana.com');
const txSignature = await connection.sendRawTransaction(signedTx.serialize());

// 3. Record the tip
await fetch('https://tipstack.fun/api/solana/tips/create', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    creatorWallet: 'CREATOR_WALLET_ADDRESS',
    tipAmount: 100000000, // 0.1 SOL in lamports
    senderWallet: supporterWallet.publicKey.toBase58(),
    txSignature,
    tokenSymbol: 'SOL',
  }),
});
```

## Example request

```json JSON theme={null}
{
  "creatorId": "monalisa.sol",
  "amountUsd": 5,
  "inputTokenMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "sourceWalletAddress": "8xRT3m1KZJPHQQaFGpvDJckJcNhHMbDdBfHHVdFGQS7a",
  "tokenSymbol": "USDC"
}
```

## Example response

```json JSON theme={null}
{
  "success": true,
  "intentId": "pi_4a1b2c3d4e5f6a7b8c9d0e1f",
  "status": "requires_action",
  "transaction": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAHCx...",
  "quote": {
    "outAmount": "4900000",
    "priceImpactPct": 0.002,
    "amountUsd": 5,
    "tokenSymbol": "USDC"
  },
  "executionMode": "sync",
  "provider": "direct-transfer",
  "lastValidBlockHeight": 289471023,
  "settings": {
    "yieldEnabled": false,
    "gaslessEnabled": false,
    "autoConvertUsdc": true
  }
}
```

<Note>
  The `transaction` field is a **Base64-encoded, unsigned** Solana versioned transaction. You must deserialize it with `VersionedTransaction.deserialize()`, have the supporter sign it, and submit it yourself. Tip Stack does not submit transactions on your behalf.
</Note>

<Warning>
  Transactions expire at `lastValidBlockHeight`. If the supporter takes too long to sign, create a fresh intent rather than retrying the expired transaction.
</Warning>
