> ## 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.

# Submitting Equity Transactions

> Submit the signed transaction for an equity direct fill or escrow fill

The submission path depends on the `executionMode` and `submitEndpointRequired` in the [order response](https://pond.dflow.net/equities/orders.md#equity-response-fields).

## Escrow Fill Submission

The transaction of an escrow fill (`async`) is complete after the user signs. The app sends it to Solana through its own RPC and tracks it as in [Track an Escrow Fill](https://pond.dflow.net/equities/recipes/track-order-status.md).

## Direct Fill Submission

A response with `submitEndpointRequired: true` goes to the [submit transaction endpoint](https://pond.dflow.net/resources/equities-submit-api/submit-transaction.md). Any other response goes through the app's own RPC.

Point the app's send call at the endpoint and pass the [API key](https://pond.dflow.net/get-started/endpoints.md) in the `x-api-key` header; it returns the transaction's signature.

```typescript theme={null}
import "dotenv/config";
import { Connection, VersionedTransaction } from "@solana/web3.js";

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; // must be enabled for this endpoint
const headers: Record<string, string> = {};
if (DFLOW_API_KEY) headers["x-api-key"] = DFLOW_API_KEY;

const submitter = new Connection(DFLOW_EQUITIES_SUBMIT_URL, { httpHeaders: headers });

// `orderResponse` is an order response with `submitEndpointRequired: true`, and `userKeypair` signs for the user.
const transaction = VersionedTransaction.deserialize(Buffer.from(orderResponse.transaction, "base64"));
transaction.sign([userKeypair]);

const signature = await submitter.sendRawTransaction(transaction.serialize());
console.log(signature);
```

### Submit Endpoint Differences from a Solana RPC

* The transaction must be the one `/order` returned plus the user's signature (and the sponsor's, when the request sets one). The endpoint rejects a transaction whose terms were changed.
* The endpoint serves `sendTransaction` only, and ignores configuration fields other than `encoding`.
* The returned signature is not yet confirmed, so the app tracks the transaction onchain.

### Submit Endpoint Errors

Errors are JSON-RPC error objects in an HTTP `200` response, as on a Solana RPC.

| Code | Meaning |
| - | - |
| `-32602` | The request or transaction is invalid, for example a transaction that cannot be decoded, is over 1232 bytes, or contains an instruction kind the endpoint does not support. |
| `-32003` | The transaction is not missing exactly one signature, or another signature is invalid. |
| `-32002` | The transaction was rejected, or its blockhash is expired (message `Blockhash not found`). A rejection carries `error.data.reason`. |
| `-32000` | The outcome is unknown. The transaction can still land until its blockhash expires, so the app waits until the block height passes the order response's `lastValidBlockHeight`, then checks for its signature onchain before it calls the order endpoint again. |

`sendRawTransaction` throws with the error message only. To read `error.code` and `error.data.reason`, the app posts the request itself:

```typescript theme={null}
const response = await fetch(DFLOW_EQUITIES_SUBMIT_URL, {
  method: "POST",
  headers: { ...headers, "content-type": "application/json" },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "sendTransaction",
    params: [Buffer.from(transaction.serialize()).toString("base64"), { encoding: "base64" }],
  }),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);

const body = await response.json();
if (body.error) console.error(body.error.code, body.error.data?.reason);
else console.log(body.result);
```

#### Submit Endpoint Rejection Reasons

```json theme={null}
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32002,
    "message": "Transaction rejected",
    "data": { "reason": "quote_expired" }
  },
  "id": 1
}
```

| `reason` | Meaning |
| - | - |
| `quote_expired` | The time allowed to submit this transaction has passed. |
| `quote_unknown` | The endpoint has no live record of this transaction's terms. |
| `quote_already_used` | These terms were already used by a transaction with different bytes. |
| `terms_mismatch` | The transaction does not match the terms the order endpoint returned. |
| `transaction_not_allowed` | The transaction passed the endpoint's instruction checks but contains something that cannot be completed. |
| `simulation_failed` | Simulation failed with a program error. |
| `declined` | The transaction was declined, with no further detail. |

After a rejection, the app calls the order endpoint again and the user signs the new transaction.

### Submit Endpoint HTTP Status Codes

| Status | Meaning |
| - | - |
| `403` | The API key is missing, invalid, or not enabled for this endpoint, or access is denied. |
| `429` | The request exceeds a rate limit, including a second submission for the same fee payer while one is in flight. The `retry-after` header gives the seconds to wait. |
| `503` | The endpoint is overloaded. The `retry-after` header gives the seconds to wait. |
| `504` | The outcome is unknown. Handle it as `-32000`. |
