# Poll and Search Events
Source: https://docs.chain.link/crec/guides/events/poll-and-search
Last Updated: 2026-08-31

> For the complete documentation index, see [llms.txt](/llms.txt).

The events client exposes three read paths:

| Method                                                          | Use case                                                      | Pagination     | Filter surface                                                         |
| --------------------------------------------------------------- | ------------------------------------------------------------- | -------------- | ---------------------------------------------------------------------- |
| `Events.Poll`                                                   | Real-time tail-following of a channel                         | offset / limit | None: pure `GET /channels/{id}/events`                                 |
| `Events.SearchEvents`                                           | Historical queries and analytics                              | offset / limit | Type, date range, chain, watcher, wallet, address, event name, service |
| `apiClient.GetChannelsChannelIdEventsSearchEventIdWithResponse` | Fetch one event by UUID (via the underlying generated client) | —              | —                                                                      |

## Poll for new events

`Poll` is the simplest path: it returns a batch ordered by **descending offset** (newest first) and a `hasMore` flag. Most consumers run it in a loop with a small back-off when the channel is idle.

### Loop pattern

```go
import (
    crecevents "github.com/smartcontractkit/crec-sdk/events"
)

for {
    evts, hasMore, err := client.Events.Poll(ctx, channelID, nil)
    if err != nil {
        if errors.Is(err, crecevents.ErrChannelNotFound) {
            return err
        }
        log.Printf("transient poll error: %v", err)
        time.Sleep(2 * time.Second)
        continue
    }

    for _, ev := range evts {
        if ok, _ := client.Events.Verify(&ev); !ok {
            continue
        }
        process(ev)
    }

    if !hasMore {
        time.Sleep(5 * time.Second)
    }
}
```

The SDK does **not** advance an internal cursor for you. `Poll` returns the most-recent unread events for the channel; persist the largest `Headers.Offset` you have processed so you can resume across restarts.

## Search historical events

For point-in-time queries (date ranges, address filters, event-name filters) use `SearchEvents`. It accepts the full `GetChannelsChannelIdEventsSearchParams` filter set:

```go
import apiClient "github.com/smartcontractkit/crec-api-go/client"

types := []apiClient.EventType{apiClient.EventTypeWatcherEvent}
addresses := []apiClient.EthereumAddress{"0xYourErc20"}
chainSelectors := []string{"16015286601757825753"}
createdGte := time.Now().Add(-24 * time.Hour).Unix()
createdLte := time.Now().Unix()
eventName := "Transfer"

params := &apiClient.GetChannelsChannelIdEventsSearchParams{
    Type:          &types,
    EventName:     &eventName,
    Address:       &addresses,
    ChainSelector: &chainSelectors,
    CreatedGte:    &createdGte,
    CreatedLte:    &createdLte,
}

events, hasMore, err := client.Events.SearchEvents(ctx, channelID, params)
```

curl equivalent (note the dotted query params `created.gte`, `created.lte`):

```bash
curl -sS "$CREC_BASE_URL/channels/$CHANNEL_ID/events/search?type=watcher.event&event_name=Transfer&address=0xYourErc20&chain_selector=16015286601757825753&created.gte=...&created.lte=..." \
  -H "Authorization: Apikey $CREC_API_KEY"
```

### Filter reference

| Filter                                                  | Type                           | Notes                                                                                 |
| ------------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------- |
| `Type`                                                  | `*[]apiClient.EventType`       | Multi-value: `watcher.event`, `watcher.status`, `operation.status`, `wallet.status`.  |
| `EventName`                                             | `*string`                      | Filter to a specific event name (e.g. `"Transfer"`). Applies to `watcher.event` only. |
| `Address`                                               | `*[]apiClient.EthereumAddress` | Multi-value EVM addresses.                                                            |
| `ChainSelector`                                         | `*[]string`                    | Multi-value chain selectors.                                                          |
| `WatcherId` / `WalletId`                                | `*openapi_types.UUID`          | Filter to events from a specific watcher / wallet.                                    |
| `Service`                                               | `*[]string`                    | Multi-value (e.g. `["dta.v2"]`).                                                      |
| `Status`                                                | `*[]string`                    | For `operation.status` / `wallet.status` / `watcher.status` events.                   |
| `WalletOperationId` / `OperationId`                     | `*string`                      | Applies to `operation.status` events.                                                 |
| `CreatedGt` / `CreatedGte` / `CreatedLt` / `CreatedLte` | `*int64`                       | Unix-second range filters (sent as `created.gt`, etc.).                               |
| `Limit` / `Offset`                                      | `*int` / `*int64`              | Pagination (default `limit=50`, max `200`).                                           |

The SDK returns these error shapes from `SearchEvents`:

| Sentinel                                                           | Trigger                                                              |
| ------------------------------------------------------------------ | -------------------------------------------------------------------- |
| `events.ErrSearchEvents` wrapping `events.ErrBadRequest`           | API returned **400** with a `Message` describing the invalid filter. |
| `events.ErrChannelNotFound`                                        | The channel does not exist.                                          |
| `events.ErrSearchEvents` wrapping `events.ErrUnexpectedStatusCode` | Any other non-200.                                                   |

## Get a specific event

There is no typed helper for single-event fetch. Use the underlying API client:

```go
import apiClient "github.com/smartcontractkit/crec-api-go/client"

api, err := crec.NewAPIClient("https://cre-connect.api.chain.link/v1", apiKey)
if err != nil { return err }

resp, err := api.GetChannelsChannelIdEventsSearchEventIdWithResponse(ctx, channelID, eventID)
if err != nil { return err }
if resp.JSON200 == nil { return fmt.Errorf("nil event payload") }
ev := *resp.JSON200
```

## Always verify before processing

> **CAUTION: Don't skip verification**
>
> `Poll` and `SearchEvents` return events **as the API serves them**; verification is a separate step. Treat any event
> whose `Verify` returned `false` as untrusted. The default SDK configuration rejects events not signed by the
> production DON. See [Verify Event Signatures](/crec/guides/events/verify-signatures).

## Next steps

- [Verify Event Signatures](/crec/guides/events/verify-signatures): cryptographically authenticate every event.
- [Decode Event Data](/crec/guides/events/decode-data): turn the verified payload into a Go struct.
- [Event Types and Payloads](/crec/reference/event-payloads): every payload variant in one table.