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

# Testing

> Test mode, a demo rate that shows dollars in seconds, webhooks on your laptop, and test deliveries.

## Test mode

Use a `sk_test_` key and everything you create lives in test mode: real meters on the test network, escrowed in testnet AUSD — money with no value outside the test network — delivered to your endpoints with real signatures. The flow is exactly live mode's: a subscriber wallet short of the cap sees **Add funds** on the checkout, and unused escrow returns the moment the meter stops. The dashboard has a switch between the two modes; each has its own keys, products, endpoints and events.

Test and live are separate worlds, not a flag on an object. A test id under a live key is a `404`.

## Getting testnet AUSD

A subscriber wallet needs testnet AUSD before a meter can start; the checkout's **Add funds** step shows the wallet's receiving address to send it to. Agora runs a faucet contract for it on Monad testnet — call `requestFunds(address)` on `0xd236c18D274E54FAccC3dd9DDA4b27965a73ee6C` from any wallet holding a little testnet MON for gas, naming the receiving address, and 10,000 testnet AUSD arrives in a block or two:

```bash theme={"system"}
cast send 0xd236c18D274E54FAccC3dd9DDA4b27965a73ee6C \
  "requestFunds(address)" <receiving address from the Add funds step> \
  --rpc-url https://testnet-rpc.monad.xyz --account <any funded keystore>
```

The faucet has a global 60-second cooldown shared by all callers, so a reverted call usually means try again in a minute. It refuses an address already holding 100,000. It is Agora's contract, not ours.

## A demo rate

At `$0.004` a second, a fifteen-second try shows six cents. For a demo, or a screenshot, create a test Product with a rate that makes the counter move visibly:

<CodeGroup>
  ```ts TypeScript theme={"system"}
  await elapse.products.create({ name: "Demo · fast meter", rateUsdPerSecond: "0.25" });
  // 15 seconds → $3.75 on the subscriber's screen; the arithmetic is identical.
  ```

  ```bash cURL theme={"system"}
  curl "$ELAPSE_API_URL/v1/products" \
    -H "Authorization: Bearer $ELAPSE_SECRET_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name":"Demo · fast meter","rate_usd_per_second":"0.25"}'
  ```
</CodeGroup>

Keep the cap short too: `max_duration_seconds: 120` on the checkout session means the subscriber is asked to fund about fifty cents, not the default hour.

## Forward webhooks to your laptop

Elapse cannot reach `localhost`. The CLI opens a stream to the platform and forwards every delivery to your local server, byte for byte, with the platform's own signature, then reports your server's status code back so the dashboard shows it.

```bash theme={"system"}
npx @elapse/cli listen --forward localhost:3000/webhooks
```

```text theme={"system"}
Elapse CLI 0.1.5 · test mode · merchant Acme GPU
Your webhook signing secret is whsec_mock000000000000000000000000000  (put it in ELAPSE_WEBHOOK_SECRET)
Ready. Forwarding to http://localhost:3000/webhooks

14:02:26  evt_2b     subscription.canceled      → 200 OK (8 ms)
          X-Elapse-Signature: t=1700000000,v1=5f1c…e9a2
          {
            "id": "evt_2b",
            "object": "event",
            "type": "subscription.canceled",
            "created": 1756800146,
            "livemode": false,
            "pending_webhooks": 1,
            "data": {
              "object": {
                "id": "sub_4QeABC",
                "object": "subscription",
                "status": "canceled",
                "customer": "cus_7HaXYZ",
                "product": "prod_9f2K",
                "rate_usd_per_second": "0.004",
                "seconds_elapsed": 83,
                "amount_settled": "0.332",
                "ended_reason": "canceled",
                "description": "GPU · 4090  (2 spaces)"
              }
            }
          }
```

The secret it prints is stable for your account and mode, so set `ELAPSE_WEBHOOK_SECRET` once. Deliveries only go to the CLI while it is running; there is no queue of missed events to drain when you come back. `elapse events resend evt_…` replays one.

`ELAPSE_SECRET_KEY` in the environment skips `elapse login`. A live key needs `--live`, on purpose.

## Send a test delivery

Every endpoint in **Developers → Webhooks** has a **Send test delivery** button that fires any of the six event types at it with a sample body and a real signature, and shows the attempt like any other. It is the fastest way to exercise a handler before a subscriber ever presses Start. On the CLI endpoint it works while `elapse listen` is running, and tells you to start it otherwise.

## No test clocks

There is no test-clock API. A meter cannot be fast-forwarded, because accrual is time on a chain, not a counter in a database. The demo rate above is how you see dollars in seconds; a real fifteen-second cancel is how the demo video was made.
