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

# Boost: the Goldsky CDN in front of your RPC

> Boost puts the Goldsky CDN in front of your existing RPC endpoint.

export const HowItWorks = () => {
  const PURPLE = '#8C54F3';
  const ORANGE = '#F34B13';
  const GRAY = '#6B7280';
  const REQ = '#64748B';
  const card = (stroke, fill) => ({
    fill,
    stroke,
    strokeWidth: 1.2,
    rx: 12
  });
  const title = {
    fontSize: '16px',
    fontWeight: 600
  };
  const tag = color => ({
    fontSize: '11px',
    fontWeight: 500,
    fill: color,
    letterSpacing: '0.01em'
  });
  const wire = color => ({
    fill: 'none',
    stroke: color,
    strokeWidth: 1.2,
    strokeDasharray: '5 5'
  });
  return <div style={{
    border: '1px solid rgba(17,24,39,0.12)',
    borderRadius: '14px',
    padding: '16px',
    margin: '16px 0',
    background: '#fafafa'
  }}>
      <svg viewBox="0 55 780 240" style={{
    width: '100%',
    height: 'auto',
    display: 'block'
  }}>
        <style>{`
          .eb-flow { animation: eb-dash 0.3s linear infinite; }
          @keyframes eb-dash { to { stroke-dashoffset: -10; } }
          @media (prefers-reduced-motion: reduce) { .eb-flow { animation: none; } }
        `}</style>
        <defs>
          <marker id="eb-arrow-gray" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
            <path d="M 0 1 L 9 5 L 0 9 z" fill="rgba(100,116,139,0.8)" />
          </marker>
          <marker id="eb-arrow-orange" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
            <path d="M 0 1 L 9 5 L 0 9 z" fill="rgba(243, 75, 19, 1)" />
          </marker>
          <marker id="eb-arrow-purple" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
            <path d="M 0 1 L 9 5 L 0 9 z" fill="rgba(140, 84, 243, 1)" />
          </marker>
        </defs>
        <path className="eb-flow" d="M 196 165 L 286 165" style={wire('rgba(140, 84, 243, 1)')} markerEnd="url(#eb-arrow-purple)" />
        <path className="eb-flow" d="M 292 185 L 202 185" style={wire('rgba(140, 84, 243, 1)')} markerEnd="url(#eb-arrow-purple)" />
        <text x="241" y="157" textAnchor="middle" style={tag(PURPLE)}>requests</text>
        <path className="eb-flow" d="M 390 145 L 390 107 Q 390 97 400 97 L 582 97" style={wire('rgba(243, 75, 19, 1)')} markerEnd="url(#eb-arrow-orange)" />
        <path className="eb-flow" d="M 586 115 L 494 160" style={wire('rgba(243, 75, 19, 1)')} markerEnd="url(#eb-arrow-orange)" />
        <text x="545" y="152" textAnchor="middle" transform="rotate(-26 545 148)" style={tag(ORANGE)}>CDN hits</text>
        <text x="493" y="89" textAnchor="middle" style={tag(ORANGE)}>CDN lookups</text>
        <path className="eb-flow" d="M 390 205 L 390 245 Q 390 255 400 255 L 582 255" style={wire('rgba(100,116,139,0.7)')} markerEnd="url(#eb-arrow-gray)" />
        <path className="eb-flow" d="M 586 237 L 494 190" style={wire('rgba(100,116,139,0.7)')} markerEnd="url(#eb-arrow-gray)" />
        <text x="493" y="272" textAnchor="middle" style={tag(REQ)}>CDN misses (forwarded)</text>
        <rect x="24" y="147" width="172" height="56" style={card('rgba(107,114,128,0.15)', 'rgba(255,255,255, 1)')} />
        <text x="110" y="181" textAnchor="middle" style={{
    ...title,
    fill: GRAY
  }}>Your app</text>
        <rect x="292" y="147" width="196" height="56" style={card('rgba(140, 84, 243, 1)', 'rgba(255,255,255, 1)')} />
        <text x="390" y="181" textAnchor="middle" style={{
    ...title,
    fill: PURPLE
  }}>Boost</text>
        <rect x="588" y="69" width="176" height="56" style={card('rgba(243, 75, 19,1)', 'rgba(255,255,255, 1)')} />
        <text x="676" y="103" textAnchor="middle" style={{
    ...title,
    fill: ORANGE
  }}>Goldsky index</text>
        <rect x="588" y="227" width="176" height="56" style={card('rgba(107,114,128,0.15)', 'rgba(255,255,255, 1)')} />
        <text x="676" y="261" textAnchor="middle" style={{
    ...title,
    fill: GRAY
  }}>Your RPC endpoint</text>
      </svg>
    </div>;
};

export const CurlBuilder = () => {
  const chains = [{
    name: 'ethereum',
    label: 'Ethereum (1)'
  }, {
    name: 'base',
    label: 'Base (8453)'
  }, {
    name: 'polygon',
    label: 'Polygon (137)'
  }, {
    name: 'optimism',
    label: 'Optimism (10)'
  }, {
    name: 'avalanche',
    label: 'Avalanche (43114)'
  }, {
    name: 'hyperevm',
    label: 'HyperEVM (999)'
  }, {
    name: 'arc',
    label: 'Arc (5042)'
  }, {
    name: 'robinhood',
    label: 'Robinhood Chain (4663)'
  }, {
    name: 'sepolia',
    label: 'Ethereum Sepolia (11155111)'
  }, {
    name: 'base-sepolia',
    label: 'Base Sepolia (84532)'
  }];
  const [key, setKey] = useState('');
  const [chain, setChain] = useState('ethereum');
  const [copied, setCopied] = useState(false);
  const url = 'https://edge.goldsky.com/boost/' + chain + '?key=' + (key || 'YOUR_KEY');
  const cmd = 'curl "' + url + '" \\\n  -i -X POST \\\n  -H "Content-Type: application/json" \\\n  -d \'{"jsonrpc":"2.0","id":1,"method":"eth_getBlockByNumber","params":["0x0",false]}\'';
  const copy = () => {
    navigator.clipboard.writeText(cmd).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1500);
    });
  };
  const inputStyle = {
    padding: '8px 12px',
    borderRadius: '8px',
    border: '1px solid rgba(17,24,39,0.2)',
    background: '#FFFFFF',
    color: '#111827',
    fontSize: '14px'
  };
  return <div style={{
    border: '1px solid rgba(17,24,39,0.12)',
    borderRadius: '12px',
    padding: '16px',
    margin: '16px 0'
  }}>
      <div style={{
    display: 'flex',
    gap: '8px',
    flexWrap: 'wrap',
    marginBottom: '4px'
  }}>
        <input type="text" value={key} onChange={e => setKey(e.target.value)} placeholder="YOUR_KEY" spellCheck={false} style={{
    ...inputStyle,
    flex: '1 1 280px',
    fontFamily: 'ui-monospace, monospace'
  }} />
        <select value={chain} onChange={e => setChain(e.target.value)} style={{
    ...inputStyle,
    flex: '0 0 auto',
    cursor: 'pointer'
  }}>
          {chains.map(c => <option key={c.name} value={c.name}>{c.label}</option>)}
        </select>
      </div>
      <div style={{
    position: 'relative',
    marginTop: '12px'
  }}>
        <pre style={{
    background: '#F6F6F5',
    color: '#1F2937',
    borderRadius: '8px',
    padding: '12px',
    paddingRight: '76px',
    margin: 0,
    fontSize: '13px',
    lineHeight: '1.5',
    whiteSpace: 'pre-wrap',
    wordBreak: 'break-all',
    fontFamily: 'ui-monospace, monospace'
  }}>
          {cmd}
        </pre>
        <button onClick={copy} style={{
    position: 'absolute',
    top: '8px',
    right: '8px',
    padding: '4px 10px',
    borderRadius: '6px',
    border: '1px solid rgba(17,24,39,0.2)',
    background: '#FFFFFF',
    color: '#374151',
    fontSize: '12px',
    cursor: 'pointer'
  }}>
          {copied ? 'Copied!' : 'Copy'}
        </button>
      </div>
      <div style={{
    fontSize: '13px',
    color: '#6B7280',
    marginTop: '8px'
  }}>
        Block <code>0x0</code> is the genesis block, so it exists on every chain — expect <code>x-cache: HIT</code>. The key must belong to an endpoint configured for the chain you pick.
      </div>
    </div>;
};

export const AGENT_PROMPT = `Use Goldsky Boost to cut the RPC bill on an EVM app I already run. Boost is a CDN that sits in front of the RPC provider I already pay for: reads it can answer come from Goldsky's indexed data, everything else forwards to my own endpoint unchanged and free.

Endpoint: https://edge.goldsky.com/boost/{chain}?key={GOLDSKY_API_KEY}
{chain} is a chain name or a chain ID, case-insensitive — /boost/ethereum and /boost/1 are the same endpoint. Boost is offered on the chains the Boost CDN covers from genesis: Ethereum (1), Base (8453), Polygon (137), Optimism (10), Avalanche (43114), HyperEVM (999), Arc (5042), Robinhood Chain (4663), Ethereum Sepolia (11155111), Base Sepolia (84532). The dashboard's chain picker is the live list.

Setup: in https://app.goldsky.com, either connect a provider account (QuickNode or Alchemy, with a management credential) and Boost creates the endpoints for the chains I pick, or paste my provider's RPC URL plus any auth headers it needs. Then take an API key from the same project. Boost configuration lives on the key, so the key in the URL decides which upstream we forward to. My provider URL is never part of the request.

Drop-in swap — nothing else in the client changes:

import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
  chain: mainnet,
  transport: http('https://edge.goldsky.com/boost/ethereum?key=YOUR_KEY'),
})

Served from the CDN: eth_getBlockByNumber and eth_getBlockReceipts at a concrete hex height, eth_getBlockByHash, eth_getTransactionByHash, eth_getTransactionReceipt, and eth_getLogs with concrete hex fromBlock/toBlock or a blockHash. eth_chainId and net_version are answered at the edge. Block tags (latest, pending, safe, finalized, earliest) always forward and are never served from the CDN, because my endpoint is the authority on the head. Every other method — writes, traces, eth_call, eth_getBalance — forwards free.

Billing: free. CDN hits and forwarded requests both cost nothing from Goldsky; forwarded requests go to my own provider, which I already pay for.

Check who answered from the response headers: x-cache (HIT/MISS), x-edge-source (cache/static/endpoint), x-edge-billable, x-edge-duration-ms, x-edge-region. A JSON-RPC batch is served per item and x-edge-billable counts the items we served, so read it rather than x-cache; give every item a unique id, and keep arrays at 100 items or fewer or the whole array forwards.

Help me point my client at Boost, then measure the hit rate and what it saves. Docs: https://docs.goldsky.com/boost
More context for agents: the Goldsky docs MCP server at https://docs.goldsky.com/mcp, or the skill pack via \`npx skills add goldsky-io/goldsky-agent\`.`;

export const ENCODED_PROMPT = encodeURIComponent(AGENT_PROMPT);

<CardGroup cols={2}>
  <div
    onClickCapture={(e) => {
  if (typeof navigator !== "undefined" && navigator.clipboard) {
    e.preventDefault();
    e.stopPropagation();
    navigator.clipboard.writeText(AGENT_PROMPT);
  }
}}
  >
    <Card title="Copy prompt" icon="copy" href="#" />
  </div>

  <Card title="Open in Claude" icon="https://mintcdn.com/goldsky-38/ZGItD__kHOxygOLb/images/logos/icon-claude.svg?fit=max&auto=format&n=ZGItD__kHOxygOLb&q=85&s=03d140b3922818ce4710109268b60b7f" href={`https://claude.ai/new?q=${ENCODED_PROMPT}`} width="16" height="16" data-path="images/logos/icon-claude.svg" />

  <Card title="Open in ChatGPT" icon="https://mintcdn.com/goldsky-38/ZGItD__kHOxygOLb/images/logos/icon-chatgpt.svg?fit=max&auto=format&n=ZGItD__kHOxygOLb&q=85&s=34f8245d14a73b48e649eed7a232c718" href={`https://chatgpt.com/?q=${ENCODED_PROMPT}`} width="16" height="16" data-path="images/logos/icon-chatgpt.svg" />

  <Card title="Open in Perplexity" icon="https://mintcdn.com/goldsky-38/ZGItD__kHOxygOLb/images/logos/icon-perplexity.svg?fit=max&auto=format&n=ZGItD__kHOxygOLb&q=85&s=bad0886723c9e2c2bc2bfb3485cfea3d" href={`https://www.perplexity.ai/?q=${ENCODED_PROMPT}`} width="15" height="16" data-path="images/logos/icon-perplexity.svg" />
</CardGroup>

Boost is a CDN that sits in front of the RPC endpoint you already use. Every request is checked against Goldsky's indexed data first. If the CDN has the answer, you get it from us: fast, and without touching your provider. If it doesn't, we forward the request to your endpoint unchanged and return its response verbatim.

You keep your existing provider, your existing keys, and your existing behavior. You just stop paying them for the reads we can serve.

## How it works

<HowItWorks />

1. **Register your provider once.** In the [dashboard](https://app.goldsky.com/dashboard/edge/boost), pick a chain and paste your provider's RPC URL plus any auth headers it needs. You get an API key that carries [that setup](#configuring-your-endpoint).
2. **Point your client at Boost.** Swap your provider's RPC URL for your Boost URL. Same methods, same params, same response shape, so nothing else in your code changes.
3. **Your requests now arrive at Boost instead of your provider.** The key in the URL is how we know which upstream to forward to, so your provider's URL and auth stay in the dashboard and never travel with a request.
4. **Boost decides who answers by reading the method and params.** That comes from the request itself, so the routing decision costs no extra round trip.
5. **Reads we already have come back from the Boost CDN.** [Reads the CDN serves](#what-the-cdn-serves) return in single-digit milliseconds. Your provider never sees the request, so it never charges you for it.
6. **Everything else forwards to your provider, unchanged.** Block tags, `eth_call`, writes, and traces go to your endpoint the way they always did. Goldsky charges nothing to pass them through, so your provider bill only ever goes down.
7. **`x-cache` tells you how much you saved.** Every response carries it — it's the standard cache header. Count the `HIT`s and you have the exact number of calls your provider didn't bill you for.

Two things are true of every request:

* **Nothing is interpreted.** A forwarded call reaches your endpoint with its method and params exactly as you sent them, carrying your own headers ([header forwarding](#header-forwarding)), and its result comes back to you untouched.
* **A miss costs you a little latency, never correctness.** If our lookup is slow, errors, or doesn't have the data, we fall back to your endpoint.

## Quickstart

Boost gives you one address per chain:

```text wrap theme={"dark"}
https://edge.goldsky.com/boost/{chain}?key={your-api-key}
```

`{chain}` is a chain name or a chain ID: `/boost/ethereum` and `/boost/1` are the same endpoint, and names are case-insensitive.

Your own endpoint is not part of the URL. You configure it once against your API key, and Boost forwards to it whenever the CDN can't answer.

<Steps>
  <Step title="Configure your endpoint">
    In the [dashboard](https://app.goldsky.com), connect your provider account — QuickNode or Alchemy — and pick the chains to boost; Boost creates the endpoints for you. Or paste your provider's RPC URL yourself, plus any custom headers it needs.

    Then take an API key from the same project. Boost configuration belongs to the key, so an API key *is* a Boost endpoint: the key in the URL decides which upstream we forward to.
  </Step>

  <Step title="Make a request that hits the CDN">
    Drop in your key, pick a chain, and copy the generated command:

    <CurlBuilder />

    <Accordion title="Prefer a static example?">
      ```bash wrap theme={"dark"}
      curl "https://edge.goldsky.com/boost/ethereum?key=YOUR_KEY" \
        -i -X POST \
        -H "Content-Type: application/json" \
        -d '{"jsonrpc":"2.0","id":1,"method":"eth_getBlockByNumber","params":["0x0",false]}'
      ```
    </Accordion>

    <Note>
      The first call for a block we haven't served recently may still come back
      `x-cache: MISS` while the reader warms that range from storage, so run it
      twice. Repeats answer from the CDN in single-digit milliseconds.
    </Note>

    The response headers tell you who answered:

    ```text theme={"dark"}
    x-cache: HIT
    x-edge-source: cache
    x-edge-billable: 1
    x-edge-duration-ms: 14
    x-edge-region: us-west-2
    ```
  </Step>

  <Step title="Compare against a miss">
    Ask for something we don't index (say, a method we don't serve) and the same request forwards to your endpoint:

    ```text theme={"dark"}
    x-cache: MISS
    x-edge-source: endpoint
    x-edge-billable: 0
    ```
  </Step>
</Steps>

Point an existing client at the URL and nothing else changes:

```typescript theme={"dark"}
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'

const client = createPublicClient({
  chain: mainnet,
  transport: http('https://edge.goldsky.com/boost/ethereum?key=YOUR_KEY')
})
```

<Note>
  Your endpoint URL usually embeds a provider API key. It lives in your endpoint configuration rather than riding along on every request, and Boost never writes it to logs, errors, or metrics. Credentials given as URL userinfo (`https://user:pass@…`) are converted to an `Authorization: Basic` header before the request leaves us. Goldsky stores the URL and any headers you configure encrypted at rest; you can replace or remove them in the dashboard at any time.
</Note>

## Configuring your endpoint

Everything about where a request forwards to lives in the dashboard, on the API key, not in the request. There are two ways to tell Boost where to forward:

**Connect a provider account.** Paste a management credential once and Boost creates the endpoints for you, per chain you pick:

| Vendor    | Credential                                                                                                                                       | What Boost creates                                   |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------- |
| QuickNode | An API key with **Admin API** access, from Dashboard → API Keys. Paid plans only                                                                 | One endpoint per chain, in your account              |
| Alchemy   | An **access key** with the Admin API's **App Management** permission, read and write, from Dashboard → Settings → Security. Not an app's API key | One app, with an allowlist for the chains you picked |

Boost only ever touches what it made: disconnecting deletes those endpoints and nothing else, and your existing endpoints and apps are never modified. The credential is encrypted at rest, and you can replace or remove it at any time.

**Or paste a URL.** Any endpoint reachable over `https` works, whoever runs it — including a node you run yourself, or Goldsky's own Edge RPC.

Per chain you then configure:

* **A provider URL**, plus any **custom headers** the provider needs for auth.
* Optional **standby upstreams** for the same chain. Only one is active at a time; you switch with an explicit action, so failover is a configuration change you make, not something we do behind your back.
* An optional **forward timeout**, per chain, for how long we wait on your endpoint before giving up.

The chain picker lists the chains you can configure. A chain with no active upstream is rejected: you can only call chains you've set up.

## What the CDN serves

These read methods can be answered from Goldsky's data:

| Method                      | Served from the CDN when                                                  |
| --------------------------- | ------------------------------------------------------------------------- |
| `eth_getBlockByNumber`      | The block is a concrete hex height                                        |
| `eth_getBlockByHash`        | Always eligible                                                           |
| `eth_getTransactionByHash`  | Always eligible                                                           |
| `eth_getTransactionReceipt` | Always eligible                                                           |
| `eth_getLogs`               | `fromBlock` and `toBlock` are concrete hex heights, or `blockHash` is set |
| `eth_getBlockReceipts`      | The block is a concrete hex height                                        |

`eth_chainId` and `net_version` are answered directly by Boost without touching either backend.

**Every other method forwards to your endpoint.** Writes, traces, state reads like `eth_call` and `eth_getBalance`: all passthrough, all free. Eligible is not the same as guaranteed: a method in this table still forwards if we don't have that specific data yet.

### Block tags always forward

A request for a tagged block (`latest`, `pending`, `safe`, `finalized`, or `earliest`) is always forwarded to your endpoint, never served from the CDN.

This is deliberate. We resolve a tag against our own view of the chain, and our view of the head can trail yours by a block or two. Serving `latest` from the CDN would occasionally hand you a stale or soon-reorged block. Your endpoint is the authority on where the head is, so tags go there. Ask for a concrete height and you get the CDN.

The same rule applies to `eth_getLogs` with a tag as a range bound.

## Batch requests

Send a JSON-RPC batch and Boost serves it **per item**: the calls we hold are answered from the CDN, the rest are forwarded to your endpoint in a single onward batch. Both are free, and the per-item split is what `x-edge-billable` counts. Nothing to enable: post an array to the same address.

For a batch, `x-edge-billable` carries the count of items we served, and `x-cache` is `HIT` only when *every* item was one of ours. A batch where 44 of 45 items came from the CDN still reports `MISS`, so read that count rather than `x-cache` alone.

Two things to know:

* **Give every item a unique `id`.** JSON-RPC doesn't guarantee the order of a batch response, so match results by `id` rather than by position.
* **Arrays over 100 items forward whole.** They reach your endpoint verbatim as one free passthrough call, with no CDN lookups. Split larger arrays into 100-item batches to keep the CDN hits.

## Supported networks

Boost offers the chains the CDN covers **from genesis**. A chain whose coverage starts
at a later block is not offered at all: the CDN would answer recent history
and miss everything below the floor, which is the opposite of what you turn
Boost on for.

| Network          | Path name      | Chain ID |
| ---------------- | -------------- | -------- |
| Ethereum         | `ethereum`     | 1        |
| Base             | `base`         | 8453     |
| Polygon          | `polygon`      | 137      |
| Optimism         | `optimism`     | 10       |
| Avalanche        | `avalanche`    | 43114    |
| HyperEVM         | `hyperevm`     | 999      |
| Arc              | `arc`          | 5042     |
| Robinhood Chain  | `robinhood`    | 4663     |
| Ethereum Sepolia | `sepolia`      | 11155111 |
| Base Sepolia     | `base-sepolia` | 84532    |

Use either the name or the chain ID in the path: `/boost/ethereum` and
`/boost/1` are equivalent.

The chain picker in the [dashboard](https://app.goldsky.com/dashboard/edge/boost)
is the live list — it reads the same coverage this table does, so it is right
the day a chain's backfill lands and this page has not been edited yet.
Chains Goldsky indexes but does not offer for Boost today include Arbitrum,
BNB Chain, Celo, Gnosis, Sei, Tron, Abstract and Monad: each is covered from a
block well above genesis.

## Response headers

Every response carries these:

| Header               | Values                        | Meaning                                                                                                                                                            |
| -------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `x-cache`            | `HIT`, `MISS`                 | Whether we served it (`HIT`) or forwarded it (`MISS`)                                                                                                              |
| `x-edge-source`      | `cache`, `static`, `endpoint` | Who actually answered                                                                                                                                              |
| `x-edge-billable`    | integer                       | How many items we served: `1`/`0` for a single call, or the count for a [batch](#batch-requests). The name predates Boost being free — it is a count, not a charge |
| `x-edge-duration-ms` | integer                       | Wall-clock time we spent serving it                                                                                                                                |
| `x-edge-version`     | build string                  | The Boost build that served it                                                                                                                                     |
| `x-edge-region`      | AWS region, e.g. `us-west-2`  | Which edge region served it                                                                                                                                        |

`x-cache` is the one to graph. It's the same header CDNs use, so most tooling already understands it.

## Header forwarding

Boost is a proxy in the middle of a chain you built: your client, us, your provider. Headers pass through in both directions. We touch only the ones that are ours to manage.

### What reaches your provider

On a forwarded request (`x-cache: MISS`), your provider receives the headers your client sent, plus any custom headers you configured on the endpoint. Your configured headers are applied last, so they win over anything a caller sends under the same name.

We keep back only the headers we manage:

| Header                                                                     | Why                                                                                                                  |
| -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `X-ERPC-Secret-Token`                                                      | Reserved by the edge. Removed from every request, never forwarded.                                                   |
| `Host`                                                                     | Set from your endpoint URL.                                                                                          |
| `Content-Type`, `Accept`                                                   | Pinned to `application/json`. This hop is JSON-RPC.                                                                  |
| `Content-Length`                                                           | Recomputed for the request we send.                                                                                  |
| `Accept-Encoding`                                                          | We ask your provider for gzip on every forward, whatever your client asked us for, and inflate the answer ourselves. |
| `Content-Encoding`                                                         | We send your provider an uncompressed body.                                                                          |
| `Cookie`, `Proxy-Authorization`                                            | Session credentials. Never relayed to a third party.                                                                 |
| Hop-by-hop headers (`Connection`, `TE`, `Upgrade`, `Transfer-Encoding`, …) | They belong to one connection, per RFC 9110.                                                                         |

Everything else passes through unchanged: trace context (`traceparent`, `tracestate`, `b3`, `baggage`), `User-Agent`, and any custom `x-*` header your provider expects.

### The caller's IP

**`X-Forwarded-For` reaches your provider**, relayed as a whole chain, unmodified, on every forwarded request.

Read the **last** entry. That is the address our load balancer observed:

```text theme={"dark"}
x-forwarded-for: 10.0.0.1, 198.51.100.7, 203.0.113.9
                                         ^^^^^^^^^^^ the caller we saw
```

Earlier entries were supplied by the caller and can say anything, so treat them as untrusted, the same rule that applies to any `X-Forwarded-For` you receive.

`X-Real-IP`, `Forwarded`, `CF-Connecting-IP`, and `True-Client-IP` are relayed too if your client sends them. We never set them ourselves.

This was briefly a per-endpoint toggle, and it defaulted to off. It is now the default for every endpoint: your provider is the party that rate-limits you per IP, applies your per-IP allowlists, and draws your per-IP analytics. None of that works if the only address it ever sees is ours.

If you need us to withhold the caller's address from your provider instead, [contact us](/getting-support). It is a per-endpoint setting we can turn off for you.

### Sending auth headers to your provider

Some providers want a bearer token or an API-key header rather than a key in the URL. That works, and it works because **your Goldsky key goes in the query string**:

```text wrap theme={"dark"}
https://edge.goldsky.com/boost/{chain}?key={your-goldsky-key}
```

With our key there, the auth *headers* on the request are unambiguously yours. `Authorization` and `X-API-Key` are forwarded to your provider untouched.

<Warning>
  Always include `?key=`. It is what separates your provider's credential from ours. Without it we have no way to tell that an `Authorization` header was meant for someone else.
</Warning>

For a credential that never changes, prefer the endpoint's custom headers in the dashboard. They are stored once, applied to every forwarded request, and your callers never have to hold them.

### What comes back to you

Your provider's response headers ride back to your client: `Cache-Control`, `Retry-After`, `ETag`, and any custom `x-*` it sets.

These are dropped:

| Header                           | Why                                                                                                                                            |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `Content-Encoding`               | We inflate your provider's gzip and negotiate compression with your client separately. Relaying it would label a plaintext body as compressed. |
| `Content-Type`, `Content-Length` | Set for the response we build.                                                                                                                 |
| `Set-Cookie`                     | Your provider must not set a cookie on the `edge.goldsky.com` origin.                                                                          |
| `x-cache`, `x-edge-*`            | We stamp these ourselves; see [Response headers](#response-headers).                                                                           |
| `x-goldsky-*`                    | The internal accounting between Boost and the edge.                                                                                            |
| `Access-Control-*`               | CORS for `edge.goldsky.com` is answered at the edge; see below.                                                                                |
| Hop-by-hop headers               | Same as above.                                                                                                                                 |

### CORS

Browser access is controlled by the endpoint's **Allowed domains** list in the dashboard, not by your provider. The edge answers the browser's preflight itself and reflects an allowed origin. Credentialed requests (cookies, HTTP auth) are not allowed, so your provider's `Access-Control-*` headers (which describe their origin, not ours) are dropped rather than merged.

Every response header we send is readable from browser JavaScript (`Access-Control-Expose-Headers: *`), so `x-cache` is available to `fetch` and `XHR`.

### Where our requests come from

We forward from AWS Fargate tasks in three regions: `us-east-1`, `us-west-2`, and `eu-central-1`. Those tasks take public addresses from each region's AWS pool and get new ones whenever a task is replaced: on a deploy, a scale-out, or a restart. **There is no fixed list of egress IPs to allowlist.**

So authenticate us rather than allowlisting us. Keep your provider's credential in the endpoint URL, or configure it as a custom header on the endpoint; either reaches your provider on every forwarded request, from whichever task serves it.

If your provider supports *only* IP allowlisting, talk to us before you build on it. A stable egress address is infrastructure we would have to add, not a setting we can turn on.

## Verified organizations

Turning Boost on, and changing it afterwards, is limited to **verified organizations**. Verification is about your Goldsky team, not about a chain or an endpoint, and it happens once.

### How a team becomes verified

Your team qualifies automatically as soon as **one member with a role above Viewer has a business email address**. An address at a public mailbox provider does not count: `gmail.com`, `outlook.com`, `proton.me` and the like are recognised as personal mailboxes, while your own company domain is not. Nothing to submit, no form, and no waiting on a review: the check runs at the moment you act, and a team that already passed is never asked again.

Two details worth knowing:

* **Viewers do not count.** The check reads the login addresses of current members whose role is above Viewer, so inviting a colleague as a Viewer will not verify the team.
* **Approval is permanent.** It does not expire, and it cannot be taken away by a later automatic check. Only Goldsky staff can change a team's standing, which is also how a team gets verified when no automatic route fits.

### What verification gates

| Action                                                 | Needs verification |
| ------------------------------------------------------ | ------------------ |
| Enable Boost for a project                             | Yes                |
| Connect or disconnect a provider account               | Yes                |
| Add, replace, activate or remove an upstream           | Yes                |
| Switch a chain on or off, change its timeouts          | Yes                |
| Reveal the API key                                     | Yes                |
| Read your configuration, chains and metrics            | No                 |
| Disable Boost, or delete it                            | No                 |
| **Serving traffic on an endpoint that already exists** | **No**             |

That last row is the important one. Verification is a control-plane gate, not a runtime one. An endpoint that is already configured keeps answering requests exactly as before, whatever your team's verification state, and nothing about this can interrupt traffic you are already serving. The read and teardown paths stay open for the same reason: a team that cannot verify must still be able to see its own configuration, stop it, and clean it up.

### If a change is refused

The dashboard and the CLI both answer with what to do rather than an error code. The usual fix is adding a team member with a business email address, which takes effect immediately.

If that does not fit your organization — everyone is on a shared domain you do not control, you are evaluating Boost before your accounts are set up, or you believe your domain is misclassified — [contact support](mailto:support@goldsky.com) or reach out in your shared Slack channel. Include your team ID, which is in the dashboard URL when you open your team settings. Goldsky can verify a team directly, and that decision overrides the automatic check in both directions.

<Note>
  If verification cannot be checked at all — a brief outage in the service that stores it — a change is refused with a "try again" rather than a denial, and no state is written. Retry, and contact support if it persists.
</Note>

## Billing

Boost is **free to use**. CDN hits and forwarded requests both cost nothing from Goldsky. Forwarded requests go straight to your endpoint, which you already pay your provider for.

Usage is still measured, and both appear on your invoice as zero-dollar line items: CDN hits (`x-cache: HIT`, equivalently `x-edge-billable: 1`) and forwarded requests, separately. That keeps the economics easy to reason about: the hits line is exactly the calls we saved you from paying your provider for.

## Limits

* Every request needs a `key`. Get one from the [dashboard](https://app.goldsky.com); it carries your Boost configuration
  and your budget. Keyless requests are answered with an
  [x402 payment challenge](/edge-rpc/capabilities/x402) rather than served — that is
  how the edge answers an unauthenticated caller, not a charge for Boost.
* The chain in the URL must be one your key is configured for. A chain with no active upstream comes back as a JSON-RPC error.
* Your configured endpoint must be reachable over `https` from the public internet. Private, loopback, and link-local addresses are rejected.
* **HTTP only.** Boost speaks JSON-RPC over `https`; there is no WebSocket endpoint. Keep subscriptions (`eth_subscribe`, `wss://…`) pointed at your provider.
* **Rate limits are Goldsky-managed.** A Boost endpoint carries a Goldsky-set
  budget rather than one you configure — unlike [Edge RPC](/edge-rpc/introduction),
  the API refuses a rate-limit budget sent for a Boost endpoint. Requests are
  unmetered within fair use; talk to us if you expect volume that needs a number
  in writing.

## Getting help

Can't find what you're looking for? Reach out to us at [support@goldsky.com](mailto:support@goldsky.com) for help.


## Related topics

- [Why Edge RPC](/edge-rpc/why-edge.md)
- [Edge RPC](/edge-rpc/introduction.md)
- [Benefits](/benefits.md)
- [Which product do I need?](/which-product.md)
- [CLI Reference](/reference/cli.md)
