# QUIC Transaction Submission

Use QUIC when you already have signed Solana transaction bytes and want a low-overhead submission path from Node.js or TypeScript.

This example uses [`@matrixai/quic`](https://www.npmjs.com/package/@matrixai/quic) and follows the same flow as the other languages:

1. Connect to a regional endpoint with ALPN `nb-tx/1`
2. Authenticate once with your API key on a bidirectional stream
3. Reuse the connection and send each transaction on a unidirectional stream

## Example

```typescript
import { randomFillSync } from "node:crypto";
import { QUICClient } from "@matrixai/quic";

const AUTH_OK = 0x00;
const MAX_TX_SIZE = 1232;

class NextblockQuicClient {
  constructor(private readonly client: QUICClient) {}

  static async connect(serverAddr: string, apiKey: string): Promise<NextblockQuicClient> {
    const [host, portString] = serverAddr.split(":");
    const port = Number(portString);

    const client = await QUICClient.createQUICClient({
      host,
      port,
      serverName: host,
      crypto: {
        ops: {
          async randomBytes(data: ArrayBuffer): Promise<void> {
            randomFillSync(new Uint8Array(data));
          },
        },
      },
      config: {
        applicationProtos: ["nb-tx/1"],
        maxIdleTimeout: 60_000,
        keepAliveIntervalTime: 15_000,
      },
    });

    const authStream = client.connection.newStream("bidi");
    const authWriter = authStream.writable.getWriter();
    await authWriter.write(new TextEncoder().encode(apiKey));
    await authWriter.close();

    const authReader = authStream.readable.getReader();
    const { value } = await authReader.read();
    if (!value || value[0] !== AUTH_OK) {
      await client.destroy();
      throw new Error("Authentication rejected");
    }

    return new NextblockQuicClient(client);
  }

  async sendTransaction(rawTx: Uint8Array): Promise<void> {
    if (rawTx.byteLength > MAX_TX_SIZE) {
      throw new Error(`Transaction too large: ${rawTx.byteLength}`);
    }

    const txStream = this.client.connection.newStream("uni");
    const txWriter = txStream.writable.getWriter();
    await txWriter.write(rawTx);
    await txWriter.close();
  }

  async close(): Promise<void> {
    await this.client.destroy();
  }
}

async function main(): Promise<void> {
  const apiKey = process.env.NEXTBLOCK_API_KEY;
  if (!apiKey) {
    throw new Error("Set NEXTBLOCK_API_KEY before running");
  }

  const client = await NextblockQuicClient.connect(
    "amsterdam.nextblock.io:11100",
    apiKey,
  );

  try {
    // Replace this with the serialized bytes of your signed transaction.
    // Example with @solana/web3.js: const rawTx = signedTransaction.serialize();
    const rawTx = new Uint8Array([0, 1, 2, 3]);
    await client.sendTransaction(rawTx);
    console.log("transaction queued");
  } finally {
    await client.close();
  }
}

void main();
```

## What To Replace

* Replace `amsterdam.nextblock.io:11100` with the region closest to you.
* Read the API key from `NEXTBLOCK_API_KEY` or your own config source.
* Replace `rawTx` with the serialized bytes of your signed transaction.

## Notes

* Send raw transaction bytes, not base64.
* Reuse one `NextblockQuicClient` for many sends.
* QUIC does not support the extra gRPC submission flags or atomic bundle submission.
* If you build transactions with `@solana/web3.js`, serialize the signed transaction first and pass the resulting `Uint8Array` into `sendTransaction()`.

See [QUIC Transaction Submission](/api/quic-transaction-submission.md) for the full endpoint list and protocol summary.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.nextblock.io/api/examples/javascript/quic.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
