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

# Migrate from Enhanced Transactions to Parsed Events

> Move from the Enhanced Transactions API to Parsed Events. Includes endpoint and parameter mapping, response field mapping, before/after code, and a copy-paste AI agent prompt.

## Why migrate?

The [Enhanced Transactions API](/docs/enhanced-transactions/overview) is a legacy product in maintenance mode: it still works, but it is not receiving new parser types or feature work. Its successor is [Parsed Events](/docs/parsed-events), which decodes instructions through the IDL catalog that also powers [Parsed Streams](/docs/parsed-streams).

The difference is in how transactions are decoded. Enhanced Transactions classifies a transaction into one of a fixed list of event types (`TRANSFER`, `SWAP`, `NFT_SALE`, ...) and returns a pre-built summary for the types it knows. Parsed Events decodes **every instruction** against the program's own IDL — 3,600+ programs — into named arguments and named accounts, and builds the summary on top:

|                           | Enhanced Transactions                              | Parsed Events                                               |
| ------------------------- | -------------------------------------------------- | ----------------------------------------------------------- |
| Decoding model            | Fixed event types, curated parsers                 | IDL catalog, 3,600+ programs                                |
| Instruction detail        | Event summary only                                 | Every instruction, decoded args and accounts, CPIs included |
| Programs without a parser | Generic `UNKNOWN` output                           | Raw data and accounts always returned per instruction       |
| Query interface           | REST                                               | REST and GraphQL                                            |
| Pagination                | Signature cursors, runtime-search errors to handle | `paginationToken` (signature cursors still available)       |
| Decoded program errors    | No                                                 | Yes (`decodedError`)                                        |
| Raw transaction payload   | No                                                 | Optional (`includeRawTransaction`)                          |
| Status                    | Legacy, maintenance mode                           | Open beta, active development                               |

Parsed Events is in open beta on paid plans. The API may still change before general availability; Enhanced Transactions keeps working in the meantime, so you can migrate at your own pace.

## Endpoint mapping

Both Parsed Events methods are `POST` requests to `https://mainnet.helius-rpc.com`, authenticated with the same `api-key` query parameter you already use:

| Enhanced Transactions                      | Parsed Events                                |
| ------------------------------------------ | -------------------------------------------- |
| `POST /v0/transactions`                    | `POST /v1/parsed-events/transactions`        |
| `GET /v0/addresses/{address}/transactions` | `POST /v1/parsed-events/transaction-history` |

The history endpoint moves all inputs from query-string parameters into a JSON body. Request bodies reject unknown fields, so typos fail loudly instead of being silently ignored.

## Before and after

The same task — fetch parsed history for a wallet — in both APIs:

<CodeGroup>
  ```javascript Before (Enhanced Transactions) theme={"system"}
  const walletAddress = "M2mx93ekt1fmXSVkTrUL9xVFHkmME8HTUi5Cyc5aF7K";
  const url = `https://mainnet.helius-rpc.com/v0/addresses/${walletAddress}/transactions?api-key=YOUR_API_KEY&limit=100&sort-order=desc`;

  const response = await fetch(url);
  const transactions = await response.json(); // flat array of enriched transactions

  for (const tx of transactions) {
    console.log(tx.signature, tx.type, tx.description);
  }
  ```

  ```javascript After (Parsed Events) theme={"system"}
  const url = "https://mainnet.helius-rpc.com/v1/parsed-events/transaction-history?api-key=YOUR_API_KEY";

  const response = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      address: "M2mx93ekt1fmXSVkTrUL9xVFHkmME8HTUi5Cyc5aF7K",
      limit: 100,
      sortOrder: "desc",
    }),
  });
  const page = await response.json(); // { data: [...], paginationToken }

  for (const item of page.data) {
    if (item.parserStatus !== "OK") continue;
    console.log(item.signature, item.parsed.summary?.type, item.parsed.summary?.description);
  }
  ```
</CodeGroup>

## Parameter mapping

### Parse Transactions

`POST /v0/transactions` → `POST /v1/parsed-events/transactions`

| Old                   | New                                                                               |
| --------------------- | --------------------------------------------------------------------------------- |
| `transactions` (body) | `transactions` — unchanged                                                        |
| `commitment`          | `commitment` — `confirmed` (default) or `finalized`; `processed` is not supported |

New options with no old equivalent: `includeRawTransaction` returns the original Solana transaction payload alongside the parsed result.

### Transaction History

`GET /v0/addresses/{address}/transactions` → `POST /v1/parsed-events/transaction-history`. Every query parameter becomes a JSON body field:

| Old query parameter | New body field    |
| ------------------- | ----------------- |
| `{address}` (path)  | `address`         |
| `limit`             | `limit`           |
| `before-signature`  | `beforeSignature` |
| `after-signature`   | `afterSignature`  |
| `sort-order`        | `sortOrder`       |
| `commitment`        | `commitment`      |
| `gt-time`           | `time.gt`         |
| `gte-time`          | `time.gte`        |
| `lt-time`           | `time.lt`         |
| `lte-time`          | `time.lte`        |
| `gt-slot`           | `slot.gt`         |
| `gte-slot`          | `slot.gte`        |
| `lt-slot`           | `slot.lt`         |
| `lte-slot`          | `slot.lte`        |

Three defaults change along the way:

* `limit` defaults to 100 instead of 10.
* `commitment` defaults to `confirmed` instead of `finalized`; `processed` is not supported.
* `sortOrder` keeps the same `asc`/`desc` values with `desc` as the default.

For paging, prefer `paginationToken` from the previous response over `beforeSignature` — see [Simplify pagination](#migration-steps) below.

The old `type` parameter has no Parsed Events equivalent — there is no server-side transaction-type filter. Filter client-side on `parsed.summary.type` (`swap`, `transfer`, `add_liquidity`, ...), or on the decoded instructions themselves, which is more precise than the old fixed types. For real-time type-specific feeds, [Parsed Streams](/docs/parsed-streams) filters server-side at the instruction level.

## Response field mapping

Enhanced Transactions returns a flat array of enriched transactions. Parsed Events wraps each result in an envelope — `{ signature, parserStatus, parsed }` — and history responses wrap the array in a page object with `paginationToken`. The parsed fields map as follows:

| Old field                                   | New field                                                                                                                                    |
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `description`                               | `parsed.summary.description` — `summary` is `null` when no transaction-level summary applies                                                 |
| `type` (`TRANSFER`, `SWAP`, ...)            | `parsed.summary.type` (`transfer`, `swap`, ...) — a smaller set; per-instruction detail moved to `parsed.instructions[]`                     |
| `source` (`SYSTEM_PROGRAM`, `JUPITER`, ...) | `parsed.summary.parsedData.protocol`, or per instruction as `instructions[].programName`                                                     |
| `events` (`events.swap`, `events.nft`, ...) | `parsed.summary.parsedData` — structured payload keyed by summary type                                                                       |
| `fee` / `feePayer`                          | `parsed.fee` / `parsed.feePayer` — unchanged                                                                                                 |
| `signature`                                 | `signature` (envelope level)                                                                                                                 |
| `slot`                                      | `parsed.slot`                                                                                                                                |
| `timestamp`                                 | `parsed.blockTime`                                                                                                                           |
| `transactionError`                          | `parsed.error`, plus `parsed.decodedError` with the program's own error name when metadata is available                                      |
| `nativeTransfers`                           | `parsed.nativeTransfers` — same shape (`fromUserAccount`, `toUserAccount`, `amount` in lamports)                                             |
| `tokenTransfers`                            | `parsed.tokenTransfers` — same account fields, but `tokenAmount` (pre-scaled decimal) becomes `rawTokenAmount` (raw integer) plus `decimals` |

And the biggest change is a new field with no old equivalent: `parsed.instructions[]` contains every top-level and inner instruction in execution order, with `decoded.args` and `decoded.accounts` named from the program's IDL. Where Enhanced Transactions gave you one event summary per transaction, Parsed Events gives you the summary *and* the full decoded instruction list. See [Parsed Response](/docs/parsed-events/parsed-response) for every field.

## Migration steps

<Steps>
  <Step title="Swap the endpoints">
    Point Parse Transactions calls at `POST /v1/parsed-events/transactions` and history calls at `POST /v1/parsed-events/transaction-history`. Same host, same `api-key` query parameter. History requests change from `GET` with query parameters to `POST` with a JSON body — move each parameter per the [mapping above](#parameter-mapping).
  </Step>

  <Step title="Update the response handling">
    Unwrap the new envelope: check `parserStatus === "OK"`, then read fields from `parsed` instead of the top level. Rename `timestamp` to `blockTime`, read `description` and `type` from `summary` (guarding for `null`), and divide `rawTokenAmount` by `10^decimals` where the old code read `tokenAmount`.
  </Step>

  <Step title="Replace type filtering">
    Where the old code passed `type=...`, filter the returned items client-side on `parsed.summary.type` or on `parsed.instructions[]` — for example, "instructions where `programId` is Jupiter and `instructionName` is `route`" replaces `type=SWAP` with something you can actually verify. If the type filter existed to drive a real-time feed, move that consumer to [Parsed Streams](/docs/parsed-streams), which filters at the instruction level server-side.
  </Step>

  <Step title="Simplify pagination">
    Replace the `before-signature` cursor loop with `paginationToken`:

    ```javascript theme={"system"}
    let paginationToken = null;
    const results = [];

    do {
      const response = await fetch("https://mainnet.helius-rpc.com/v1/parsed-events/transaction-history?api-key=YOUR_API_KEY", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          address: "YOUR_ADDRESS_HERE",
          limit: 100,
          ...(paginationToken && { paginationToken }),
        }),
      });
      const page = await response.json();
      results.push(...page.data);
      paginationToken = page.paginationToken;
    } while (paginationToken);
    ```

    The loop ends when `paginationToken` is missing. The old runtime-search errors ("Failed to find events within the search period") and their continuation-signature handling disappear entirely — delete that code.
  </Step>

  <Step title="Verify against the old output">
    For a sample address, fetch the same page from both APIs and compare the signature sets, fees, and transfer amounts. Then deploy and remove the old code path. Enhanced Transactions keeps working while you migrate — there is no forced cutoff.
  </Step>
</Steps>

## Behavior differences to review

* **Commitment defaults.** History defaults to `confirmed` where the old endpoint defaulted to `finalized`. Pass `commitment: "finalized"` explicitly if your pipeline depends on finality. `processed` is not supported.
* **Per-item errors.** A signature that cannot be parsed no longer fails the request — it comes back as an item with `parserStatus: "ERROR"` and a `parserError`. Handle it per item instead of per request.
* **Summary coverage.** `summary` is `null` for transactions with no recognized transaction-level action. The old API returned `type: "UNKNOWN"` in that case; the new API still gives you every decoded instruction to work with.
* **Access.** Parsed Events is in open beta on paid plans, and the API may still change before general availability.

## Let an AI agent do the migration

If you use Claude Code, Cursor, or another coding agent, paste the prompt below into your repository's agent session. It finds Enhanced Transactions call sites and rewrites them.

```markdown theme={"system"}
Migrate this codebase from the Helius Enhanced Transactions API to the Helius
Parsed Events API.

## Background

Parsed Events is the successor to Enhanced Transactions. Same host
(https://mainnet.helius-rpc.com) and api-key query parameter; new paths,
JSON bodies, and response shapes.
Docs: https://www.helius.dev/docs/parsed-events/quickstart.md and
https://www.helius.dev/docs/parsed-events/parsed-response.md

## Step 1: Find the old call sites

Search for:
- POST requests to /v0/transactions
- GET requests to /v0/addresses/<address>/transactions (any query parameters)
- Pagination loops using before-signature / after-signature cursors, and
  handlers for the "Failed to find events within the search period" error

## Step 2: Rewrite each call site

Parse transactions:
- POST /v0/transactions -> POST /v1/parsed-events/transactions
- Body keeps { transactions: [...] }; optionally add commitment
  ("confirmed" default or "finalized") and includeRawTransaction.

Transaction history:
- GET /v0/addresses/{address}/transactions?... ->
  POST /v1/parsed-events/transaction-history with a JSON body.
- Parameter mapping (query -> body): address path segment -> address;
  limit -> limit (default is now 100, not 10);
  before-signature -> beforeSignature (prefer paginationToken, see below);
  after-signature -> afterSignature; sort-order -> sortOrder;
  commitment -> commitment (default is now "confirmed", not "finalized";
  "processed" unsupported);
  gt-time/gte-time/lt-time/lte-time -> time.gt/.gte/.lt/.lte;
  gt-slot/gte-slot/lt-slot/lte-slot -> slot.gt/.gte/.lt/.lte.
- type=... has no server-side equivalent: filter returned items client-side
  on parsed.summary?.type (lowercase: "swap", "transfer", ...) or on
  parsed.instructions[] (programId / instructionName).

Response shape changes:
- Each item is now { signature, parserStatus, parsed } — check
  parserStatus === "OK" and read fields from parsed.
- Field renames: timestamp -> parsed.blockTime; description ->
  parsed.summary?.description; type -> parsed.summary?.type;
  source -> parsed.summary?.parsedData?.protocol or
  parsed.instructions[].programName; events -> parsed.summary?.parsedData.
- nativeTransfers: unchanged shape under parsed.nativeTransfers.
- tokenTransfers: tokenAmount (pre-scaled decimal) is replaced by
  rawTokenAmount (raw integer string/number) plus decimals — divide by
  10**decimals where the old amount was used.
- History responses wrap results as { data, paginationToken }. Loop while
  paginationToken is present, passing it back in the next request body.
  Delete continuation-signature error handling for the old runtime type
  search — it no longer exists.

## Step 3: Constraints and cleanup

- Keep the same Helius API key and host; only paths, methods, bodies, and
  response handling change.
- Never hardcode an API key; keep reading it from the existing config or
  environment variable.
- Preserve the surrounding code style and error handling conventions.
- Leave Enhanced Transaction webhook payload handling unchanged — this
  migration covers only the /v0/transactions and /v0/addresses REST calls.

## Step 4: Verify

- Run the project's type checks and tests.
- Do NOT make any API calls yourself. Instead, write a standalone script
  (e.g. scripts/verify-parsed-events-migration.mjs) that fetches one page of
  history for an address from both APIs — the old
  GET /v0/addresses/{address}/transactions and the new
  POST /v1/parsed-events/transaction-history — and prints whether the
  signature sets, fees, and native transfer amounts match, listing any
  differences. Read the API key from an environment variable and the address
  from a CLI argument.
- Tell the user how to run it, for example:
  HELIUS_API_KEY=... node scripts/verify-parsed-events-migration.mjs <address>
- Summarize every call site changed and flag any you were unsure about.
```

The prompt is self-contained — the agent doesn't need access to this page. For agent-ready docs, MCP search, and skills, see [Helius for AI agents](/docs/agents/overview).

## Next steps

<CardGroup cols={2}>
  <Card title="Parsed Events Quickstart" icon="bolt" href="/docs/parsed-events/quickstart">
    Parse your first transaction, fetch address history, and page through results.
  </Card>

  <Card title="Parsed Response" icon="brackets-curly" href="/docs/parsed-events/parsed-response">
    Field reference for parsed transactions, transfers, and instructions.
  </Card>

  <Card title="Parsed Streams" icon="tower-broadcast" href="/docs/parsed-streams">
    The same decoding in real time over WebSocket, filtered server-side.
  </Card>

  <Card title="getTransactionsForAddress" icon="clock-rotate-left" href="/docs/rpc/gettransactionsforaddress">
    Raw transaction history with token-account support and server-side filters.
  </Card>
</CardGroup>
