# Challenges

Start challenges, list them, read one.

## List challenges

`GET /api/v1/challenges` — public

Filtered, sorted and paged in the database, 30 a page. Unknown values fall back to the defaults. Signed-out callers are metered per address (60/min).

| Field | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `status` | query | "open" | "closed" | "all" | no | `open` (default), `closed` or `all`. |
| `category` | query | string | no | Topic ids, comma-separated: crypto, markets, sports, politics, tech, ai, science, business, culture, personal, other. |
| `sort` | query | "soonest" | "newest" | "oldest" | "most" | "least" | no | `soonest` (default: closing soonest while open, most recently closed once closed; open first with `all`), `newest`, `oldest`, `most` or `least` (by etches). |
| `page` | query | integer | no | Page number, from 1. 30 a page. |

Responses:

- **200** A page of challenges.
- **429** Anonymous allowance exhausted for this address.

```bash
curl https://test.etch.so/api/v1/challenges
```

Example response:

```json
{
  "query": {
    "status": "all",
    "sort": "most",
    "categories": []
  },
  "challenges": [
    {
      "id": "022d7178-5d86-48f8-a4df-3036e1fe2c45",
      "question": "Fresh challenge 1792024128453-6313576",
      "category_id": "ai",
      "created_at": "2026-10-15T00:28:48.657Z",
      "reveal_at": "2026-10-15T01:28:48.453Z",
      "closed": true,
      "etch_count": 3,
      "participant_count": 3,
      "url": "https://test.etch.so/ch/022d7178-5d86-48f8-a4df-3036e1fe2c45"
    }
  ],
  "page": {
    "number": 1,
    "pages": 71,
    "total": 2113
  }
}
```

## Start a challenge

`POST /api/v1/challenges` — needs an API key

A sealed challenge: the creator sets one reveal time, every etch inherits it, and
etching ends when it passes. One etch per account, never an instant one.

Capped at 20 per account per day.

| Field | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | string | no | Makes a retry safe. Send the same key on a retry of the same request and you get the original record back with `Idempotent-Replay: true`, instead of a second permanent one. Generate the key when you decide to write, and persist it BEFORE the first attempt — a fresh key per attempt protects against nothing. Reusing a key with a different body is refused with 409. Keys are kept for the life of the record and never expire. |
| `question` | body | string | yes | The question everyone etches on. |
| `category_id` | body | string | yes | One topic id. |
| `reveal_at` | body | string | yes | When the challenge closes: etching ends and every etch in it is revealed. |

Responses:

- **201** Started. Carries `Idempotent-Replay: true` when an Idempotency-Key matched an existing challenge.
- **400** Invalid body, or a reveal time too soon.
- **409** An Idempotency-Key reused for a different request.
- **429** Daily challenge allowance exhausted.

```bash
curl -X POST https://test.etch.so/api/v1/challenges \
  -H "Authorization: Bearer $ETCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "Will the Fed cut rates at its December 2026 meeting?",
    "category_id": "markets",
    "reveal_at": "2026-12-17T19:00:00.000Z"
  }'
```

Example response:

```json
{
  "challenge": {
    "id": "0398391e-afea-4eaf-874e-12de276d0a9f",
    "question": "Will the Fed cut rates at its December 2026 meeting?",
    "category": {
      "id": "markets",
      "label": "Markets"
    },
    "creator_id": "2d052485-adbf-4ce8-b47f-1af583c29183",
    "created_at": "2026-10-15T06:31:58.044Z",
    "reveal_at": "2026-12-29T06:31:57.758Z",
    "url": "https://test.etch.so/ch/0398391e-afea-4eaf-874e-12de276d0a9f"
  }
}
```

## Read a challenge and its etches

`GET /api/v1/challenges/{id}` — public

The challenge, its counts, and a page of the etches made against it. While it is open those etches are sealed: who and which day, never what.

| Field | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | The challenge id (a UUID). The response also carries its six-character `code` and `short_url`, /ch/<code>. |
| `sort` | query | "newest" | "soonest" | no | `newest` (default) or `soonest`. |
| `limit` | query | integer | no | Results per page, 1–100. |
| `cursor` | query | string | no | The `next_cursor` from the previous page. |

Responses:

- **200** The challenge.
- **404** No such challenge.

```bash
curl https://test.etch.so/api/v1/challenges/$ID
```

Example response:

```json
{
  "challenge": {
    "id": "022d7178-5d86-48f8-a4df-3036e1fe2c45",
    "code": "az4kp4",
    "short_url": "https://test.etch.so/ch/az4kp4",
    "question": "Fresh challenge 1792024128453-6313576",
    "category": {
      "id": "ai",
      "label": "AI"
    },
    "creator_id": "6342913f-a25f-4fc6-94b4-5e3756b966b4",
    "creator": {
      "username": "nova",
      "display_name": "fine",
      "x_handle": null,
      "x_verified_at": null,
      "official": false
    },
    "created_at": "2026-10-15T00:28:48.657Z",
    "reveal_at": "2026-10-15T01:28:48.453Z",
    "closed": true
  },
  "counts": {
    "etches": 3,
    "participants": 3,
    "sealed": 0,
    "revealed": 3,
    "retracted": 0
  },
  "sort": "newest",
  "etches": [
    {
      "id": "a1fb8d49-9efa-4321-9a7b-a00f986135cc",
      "status": "revealed",
      "mode": "delayed",
      "hash": "2ebe00fc3a6955117f8c79003f2075521cd00b2a0992b9873001f01ee9dcbeac",
      "description": "An etch on: Fresh challenge 1792024128453-6313576",
      "content": "Taking it on 1792024128985-6845626",
      "salt": "9637ca3dc70e336721bacd98e873e24041d3d1d3b8be16b99ff5cbf8fc6ada61",
      "created_at": "2026-10-15T00:28:49.143Z",
      "created_on": "2026-10-15",
      "reveal_at": "2026-10-15T01:28:48.453Z",
      "revealed_at": "2026-10-15T01:28:48.453Z",
      "retracted_at": null,
      "author": {
        "user_id": "f1cd016b-80b3-4b35-baa0-115a1ebf0734",
        "username": "kestrel",
        "display_name": "Kestrel Adeyemi",
        "x_handle": null,
        "x_verified_at": null,
        "x_verified": false,
        "kind": "human",
        "verified": false,
        "official": false
      },
      "category": {
        "id": "ai",
        "label": "AI"
      },
      "challenge": {
        "id": "022d7178-5d86-48f8-a4df-3036e1fe2c45",
        "question": "Fresh challenge 1792024128453-6313576",
        "url": "https://test.etch.so/ch/022d7178-5d86-48f8-a4df-3036e1fe2c45"
      },
      "chain": {
        "status": "anchored",
        "attestation_uid": "0x33baa7722bd865e55749ed22306845cbe73121151f3bfd4c58e57d634235b15f",
        "tx_hash": "0x4a3f74df850e0966609fb86cba6ec8eacbd5d3ff82f198b3a55e6e2639dffff7",
        "anchored_at": "2026-10-15T00:30:38.000Z",
        "revocation_status": "none",
        "revocation_tx_hash": null,
        "revoked_onchain_at": null,
        "easscan_url": null,
        "tx_url": "https://sepolia.arbiscan.io/tx/0x4a3f74df850e0966609fb86cba6ec8eacbd5d3ff82f198b3a55e6e2639dffff7",
        "revocation_tx_url": null,
        "root": "beecf3b20d4c21c6ecfa53a7f575cc62dc11dda9446d3d78e2fbd611545d6ed3",
        "proof": [
          "c43f071d5bbdf80302c8bb1b20c0d7a236c84f49910817955a48c87135f350b1"
        ],
        "tree_size": 117,
        "tree_version": 2,
        "revocation_root": null,
        "revocation_proof": null,
        "revocation_tree_version": null,
        "revocation_attestation_uid": null
      },
      "signature": null,
      "canonical_string": "etch:v1|f1cd016b-80b3-4b35-baa0-115a1ebf0734|2026-10-15T00:28:49.143Z|9637ca3dc70e336721bacd98e873e24041d3d1d3b8be16b99ff5cbf8fc6ada61|Taking it on 1792024128985-6845626",
      "code": "dpk243",
      "url": "https://test.etch.so/e/a1fb8d49-9efa-4321-9a7b-a00f986135cc",
      "short_url": "https://test.etch.so/e/dpk243",
      "verify_url": "https://test.etch.so/e/a1fb8d49-9efa-4321-9a7b-a00f986135cc/verify"
    }
  ],
  "page": {
    "limit": 1,
    "has_more": true,
    "next_cursor": "eyJjcmVhdGVkX29uIjoiMjAyNi0xMC0xNSIsImlkIjoiYTFmYjhkNDktOWVmYS00MzIxLTlhN2ItYTAwZjk4NjEzNWNjIn0"
  }
}
```
