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

# Equities Quickstart

> End-to-end recipe for buying and selling a tokenized equity with DFlow

**1. Set Up**

```typescript theme={null}
import "dotenv/config";

import { unpackMint } from "@solana/spl-token";
import { Connection, Keypair, PublicKey, VersionedTransaction } from "@solana/web3.js";
import bs58 from "bs58";

const DFLOW_TRADE_API_URL = process.env.DFLOW_TRADE_API_URL ?? "https://dev-quote-api.dflow.net";
const DFLOW_EQUITIES_SUBMIT_URL =
  process.env.DFLOW_EQUITIES_SUBMIT_URL ?? "https://TODO-equities-host.dflow.net/submit-transaction";
const DFLOW_API_KEY = process.env.DFLOW_API_KEY; // the key must be enabled for equities
const SOLANA_RPC_URL = process.env.SOLANA_RPC_URL ?? "https://api.mainnet-beta.solana.com";

const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
const TICKER = "AAPL";
const AMOUNT = 1_000_000; // 1 USDC (6 decimals)

const connection = new Connection(SOLANA_RPC_URL, "confirmed");
const keypair = Keypair.fromSecretKey(
  bs58.decode(process.env.SOLANA_PRIVATE_KEY ?? "")
);

const headers: Record<string, string> = {};
if (DFLOW_API_KEY) headers["x-api-key"] = DFLOW_API_KEY;
```

**2. Find the Equity Mint**

[Find Equities](https://pond.dflow.net/equities/recipes/find-equities.md) adds retries and lookup by mint.

```typescript theme={null}
const equitiesResponse = await fetch(`${DFLOW_TRADE_API_URL}/equities`, { headers });
if (!equitiesResponse.ok) {
  throw new Error(`GET /equities failed: ${equitiesResponse.status} ${await equitiesResponse.text()}`);
}

const equities: { ticker: string; mint: string; provider: string }[] = await equitiesResponse.json();
const equity = equities.find((e) => e.ticker === TICKER);
if (!equity) {
  throw new Error(`${TICKER} is not in the supported equities`);
}
```

**3. Call the Order Endpoint**

Set `inputMint` to USDC and `outputMint` to the equity mint. Pass `userPublicKey` so the [`/order`](https://pond.dflow.net/resources/trading-api/order/order) response includes a `transaction`. [Equity Fills](https://pond.dflow.net/equities/orders.md#equity-response-fields) describes the equity fields in the response.

```typescript theme={null}
const params = new URLSearchParams({
  inputMint: USDC_MINT,
  outputMint: equity.mint,
  amount: AMOUNT.toString(),
  userPublicKey: keypair.publicKey.toBase58(),
});

const buyResponse = await fetch(`${DFLOW_TRADE_API_URL}/order?${params}`, { headers });
const buy = await buyResponse.json();
if (!buyResponse.ok || !buy.transaction) {
  throw new Error(`GET /order failed: ${JSON.stringify(buy)}`);
}

console.log("executionMode:", buy.executionMode, "submitEndpointRequired:", buy.submitEndpointRequired ?? false);
console.log("  outAmount:", buy.outAmount);
console.log("  outAmountScaledUi:", buy.outAmountScaledUi ?? "<mint has no ScaledUiAmount extension>");
```

**4. Sign and Choose the Submission Path**

The user signs the transaction. `submitEndpointRequired` and `executionMode` decide the submission path: [Submit a Direct Fill](#submit-a-direct-fill) for a response with `submitEndpointRequired: true`, and [Submit an Escrow Fill](#submit-an-escrow-fill) for an `async` response. Any other response is an ordinary route, and the app sends it through its own RPC.

```typescript theme={null}
const transaction = VersionedTransaction.deserialize(Buffer.from(buy.transaction, "base64"));
transaction.sign([keypair]);

if (buy.submitEndpointRequired) {
  await submitDirectFill(transaction, buy.lastValidBlockHeight);
} else if (buy.executionMode === "async") {
  await submitEscrowFill(transaction);
} else {
  console.log(await connection.sendRawTransaction(transaction.serialize()));
}
```

## Submit a Direct Fill

The app sends the signed transaction to the [submit transaction endpoint](https://pond.dflow.net/resources/equities-submit-api/submit-transaction.md) and confirms the signature onchain through its own RPC. [Submitting Equity Transactions](https://pond.dflow.net/equities/submitting.md) lists the endpoint's errors.

```typescript theme={null}
async function submitDirectFill(transaction: VersionedTransaction, lastValidBlockHeight: number) {
  const submitter = new Connection(DFLOW_EQUITIES_SUBMIT_URL, { httpHeaders: headers });
  const signature = await submitter.sendRawTransaction(transaction.serialize());
  console.log(`  Tx: https://orbmarkets.io/tx/${signature}`);

  const { value } = await connection.confirmTransaction({
    signature,
    blockhash: transaction.message.recentBlockhash,
    lastValidBlockHeight,
  });
  console.log(value.err ? `Failed: ${JSON.stringify(value.err)}` : "Filled");
}
```

## Submit an Escrow Fill

The transaction of an `async` response is complete after the user signs, so the app sends it through its own RPC. The app then tracks the escrow fill with this signature and the response's `lastValidBlockHeight`, as in [Track an Escrow Fill](https://pond.dflow.net/equities/recipes/track-order-status.md).

```typescript theme={null}
async function submitEscrowFill(transaction: VersionedTransaction) {
  const signature = await connection.sendRawTransaction(transaction.serialize());
  console.log(`  Tx: https://orbmarkets.io/tx/${signature}`);
}
```

## Sell an Equity

A sell sets the equity mint as `inputMint`. `amount` is the raw token amount in the equity mint's decimals, before the ScaledUiAmount multiplier. The app reads the decimals from the mint account, decoding it with the token program that owns the account.

```typescript theme={null}
const mintAddress = new PublicKey(equity.mint);
const mintAccount = await connection.getAccountInfo(mintAddress);
if (!mintAccount) {
  throw new Error(`Mint account ${equity.mint} not found`);
}
const { decimals } = unpackMint(mintAddress, mintAccount, mintAccount.owner);

const sellParams = new URLSearchParams({
  inputMint: equity.mint,
  outputMint: USDC_MINT,
  amount: Math.round(0.5 * 10 ** decimals).toString(),
  userPublicKey: keypair.publicKey.toBase58(),
});

const sellResponse = await fetch(`${DFLOW_TRADE_API_URL}/order?${sellParams}`, { headers });
const sell = await sellResponse.json();
if (!sellResponse.ok || !sell.transaction) {
  throw new Error(`GET /order failed: ${JSON.stringify(sell)}`);
}

console.log("executionMode:", sell.executionMode, "submitEndpointRequired:", sell.submitEndpointRequired ?? false);
console.log("  inAmountScaledUi:", sell.inAmountScaledUi ?? "<mint has no ScaledUiAmount extension>");
console.log("  outAmount (USDC):", sell.outAmount);
```

The user signs `sell.transaction`, and the app then branches as above.
