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

# Monitoring and alerting

> Poll actions and transactions to a terminal status, recover from failed or stale ones, and alert on balances and yield health that need attention.

Keep your integration's view of an action current after you submit it, and surface the moments that need a user's attention: a failed transaction, a cooldown that finished, or a yield that stopped accepting entries.

## Poll to a terminal status

An action's `status` and each of its `transactions[]`' `status` are two different enums; poll the one you need. Transaction status gates sequencing within a single action (see [Enter and exit flows](/guides/earn/enter-exit-flows#enter-a-position)); action status tells you when the whole thing is done:

```typescript theme={null}
const ACTION_FINAL = new Set(['SUCCESS', 'FAILED', 'CANCELED']);
const STOP_POLLING = new Set([...ACTION_FINAL, 'STALE']); // STALE is not final; see below

async function pollAction(actionId: string, onUpdate?: (action: any) => void) {
  let delayMs = 3_000;
  const maxDelayMs = 60_000;
  const deadline = Date.now() + 30 * 60 * 1000; // matches the STALE window, below

  while (Date.now() < deadline) {
    const res = await fetch(`https://api.yield.xyz/v1/actions/${actionId}`, {
      headers: { 'x-api-key': process.env.YIELD_API_KEY! },
    });
    const action = await res.json();
    onUpdate?.(action);
    if (STOP_POLLING.has(action.status)) return action;
    await new Promise((r) => setTimeout(r, delayMs));
    delayMs = Math.min(delayMs * 1.5, maxDelayMs);
  }
  throw new Error(`Action ${actionId} did not reach a terminal status in time`);
}
```

Back off between polls instead of polling on a tight loop, and bound the overall wait. `GET /v1/transactions/{id}` works the same way for a single transaction. See [Actions](/documentation/earn/core-concepts/actions#status-lifecycle) for the full status tables.

## Recover from FAILED and STALE

* **`FAILED`** is final. A transaction in the sequence failed or reverted. Do not resubmit a hash or modify the failed transaction. Request a brand new action (`enter`, `exit`, or `manage`, matching the original intent) instead.
* **`STALE`** means no progress for 30 minutes, but it is not final: a transaction that was broadcast late can still confirm and complete the action. Before requesting a replacement, check the stale action's `transactions`. If none was ever broadcast, request a new action. If one was broadcast, confirm it on-chain (or with `GET /v1/transactions/{id}`) first, so a late confirmation doesn't leave the user with two positions.

## List an address's action history

`GET /v1/actions` returns an address's past and in-flight actions, paginated with `offset` / `limit` (default 20, max 100):

| Parameter | Filters by |
| - | - |
| `address` | Required. The wallet to list actions for |
| `status` / `statuses` | One status, or up to 7 (CSV or repeated query params) |
| `intent` | `enter`, `exit`, or `manage` |
| `type` | A specific action type, for example `CLAIM_REWARDS` |
| `yieldId` / `yieldTypes` | One yield, or a set of yield types |
| `network` | A single network |

By default, with no `status` or `statuses` filter, `GET /v1/actions` hides `STALE` actions that never broadcast a single transaction: a stale action with at least one broadcast attempt still appears. Pass `statuses=STALE` (or another explicit filter) to see everything, including stale actions that never left the ground.

```bash cURL theme={null}
curl --request GET \
  --url 'https://api.yield.xyz/v1/actions?address=0xYOUR_WALLET_ADDRESS&statuses=FAILED,STALE&limit=50' \
  --header "x-api-key: $YIELD_API_KEY"
```

## Watch balances for new pending actions

A position's next required step, such as a claim once a cooldown ends or rewards becoming `claimable`, appears as a new entry in that balance's `pendingActions[]` the next time you fetch it. Poll the portfolio endpoint on an interval that fits your product, and diff against what you saw last time:

```typescript theme={null}
function diffPendingActions(previous: any[], current: any[]) {
  const seen = new Set(previous.map((p) => `${p.type}:${p.passthrough}`));
  return current.filter((p) => !seen.has(`${p.type}:${p.passthrough}`));
}
```

Alert the user on anything the diff returns. See [Tracking balances](/guides/earn/tracking-balances) for fetching balances and executing a pending action once you've surfaced it.

## Watch yield health before offering entry

A yield can stop accepting new deposits between the time you last cached its metadata and the time a user tries to enter it. Re-check before offering entry rather than relying on a value fetched earlier in the session:

| Field | Watch for |
| - | - |
| `status.enter` | `false` means entry is closed right now |
| `metadata.underMaintenance` | Protocol-side maintenance; can be `true` even when `status.enter` is still `true` |
| `metadata.deprecated` | The yield is being discontinued |

Treat any of the three as a reason to hide or disable the entry action. See [Discover yields](/guides/earn/discover-yields) for the rest of a yield's fields.

## Rate limits

Every request against a project's API key counts against that project's plan tier, and a sustained polling loop (action status, transaction status, balances) is a common source of avoidable request volume. Back off on `429` responses using the `retry-after` header, and see [Rate limits](/documentation/plans-limits/rate-limits) for your plan's limits and response headers.

## Webhooks as an alternative to polling

yield.xyz also emits `transaction.status_changed` and `position.status_changed` webhook events, so you can react to a status change without polling for it. See [Receive webhooks](/guides/enterprise/webhooks) to set up an endpoint and verify deliveries, and [Webhooks](/documentation/advanced-setup/webhooks) for the event model. Polling remains the fallback: use it for anything a webhook subscription doesn't cover, and to reconcile after a missed or delayed delivery.

## Next steps

<Columns cols={2}>
  <Card title="Tracking balances" icon="wallet" href="/guides/earn/tracking-balances">
    Fetch, group, and act on a user's positions and pending actions.
  </Card>

  <Card title="Enter and exit flows" icon="arrow-right-arrow-left" href="/guides/earn/enter-exit-flows">
    The sign, submit, and poll loop a fresh action needs after you request it.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/documentation/advanced-setup/webhooks">
    Configure endpoints and subscriptions for status-change events.
  </Card>

  <Card title="Rate limits" icon="gauge" href="/documentation/plans-limits/rate-limits">
    Plan limits, response headers, and backoff for 429 responses.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.