Authentication

CRE Connect uses a single header, Authorization: Apikey <key>, for every request. The SDK attaches that header automatically once you construct a client.

Environment variables

Throughout these docs, code samples and curl snippets read from three environment variables. Export them once and the rest of the examples will work as-is:

export CREC_BASE_URL="https://cre-connect.api.chain.link/v1"
export CREC_API_KEY="<your-api-key>"
export CREC_ORG_ID="<your-org-id>"   # e.g. org_example00000000000, see Prerequisites

Construct a client

package main

import (
    "log"
    "os"

    "github.com/smartcontractkit/crec-sdk"
)

func main() {
    apiKey := os.Getenv("CREC_API_KEY")
    if apiKey == "" {
        log.Fatal("CREC_API_KEY must be set")
    }
    orgID := os.Getenv("CREC_ORG_ID")
    if orgID == "" {
        log.Fatal("CREC_ORG_ID must be set")
    }

    client, err := crec.NewClient(
        "https://cre-connect.api.chain.link/v1",
        apiKey,
        crec.WithOrgID(orgID),
    )
    if err != nil {
        log.Fatalf("failed to construct CREC client: %v", err)
    }

    _ = client
}

NewClient validates required inputs and applies these defaults:

ConcernDefault
HTTP clienthttp.DefaultClient
Loggerslog.Default()
Off-Chain Reporting (OCR) signature verificationEnabled, with the production DON signer set and DefaultMinRequiredSignatures (4)
Event-hash bindingOff by default: you must opt in with crec.WithOrgID(...) or crec.WithWorkflowOwner(...)
Watcher pollingPollInterval 2s, EventualConsistencyWindow 2s (override with WithWatcherPolling)

It returns sentinel errors for the two unrecoverable misconfigurations:

  • crec.ErrBaseURLRequired: the base URL was empty.
  • crec.ErrAPIKeyRequired: the API key was empty.

Apply options

Options are applied in order; later options override earlier ones.

import (
    "log/slog"
    "net/http"
    "os"
    "time"

    "github.com/smartcontractkit/crec-sdk"
)

logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

client, err := crec.NewClient(
    "https://cre-connect.api.chain.link/v1",
    os.Getenv("CREC_API_KEY"),
    crec.WithOrgID(os.Getenv("CREC_ORG_ID")),
    crec.WithLogger(logger),
    crec.WithHTTPClient(&http.Client{Timeout: 30 * time.Second}),
    crec.WithWatcherPolling(5*time.Second, 10*time.Second),
)

The full set of options is documented in the SDK Configuration reference. For event verification specifically, see Verify Event Signatures.

Smoke test: ListNetworks

ListNetworks performs a single authenticated GET /networks and returns the list of networks your tenant can use. It confirms in one call that your client, your API key, and the CRE Connect endpoint are all healthy.

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/smartcontractkit/crec-sdk"
)

func main() {
    client, err := crec.NewClient(
        "https://cre-connect.api.chain.link/v1",
        os.Getenv("CREC_API_KEY"),
        crec.WithOrgID(os.Getenv("CREC_ORG_ID")),
    )
    if err != nil {
        log.Fatal(err)
    }

    networks, hasMore, err := client.ListNetworks(context.Background())
    if err != nil {
        log.Fatalf("ListNetworks failed: %v", err)
    }

    for _, n := range networks {
        fmt.Printf("- %-30s  family=%s  chainID=%s  selector=%s\n",
            n.Name, n.ChainFamily, n.ChainId, n.ChainSelector)
    }
    if hasMore {
        fmt.Println("(more results available: paginate)")
    }
}

A successful run prints something like:

- Ethereum Mainnet               family=evm  chainID=1     selector=5009297550715157269
- Base Sepolia                   family=evm  chainID=84532 selector=...

If you instead see an authentication error, double-check:

  • The base URL points to the environment your key was issued for.
  • The key is the full value (no leading/trailing whitespace, no missing characters).
  • Your machine has outbound network access to the API host.

If the request reaches the server but fails with a non-200 status, the SDK wraps the error with crec.ErrListNetworks:

if errors.Is(err, crec.ErrListNetworks) {
    // network reachable, but request was rejected: inspect logs
}

Once ListNetworks returns at least one network, you have everything needed to move on to Quickstart: Watch On-Chain Events.

Get the latest Chainlink content straight to your inbox.