# One Piece API Documentation

Source: https://pokewallet.io/api-docs/one-piece

Complete REST reference for the One Piece Card Game API. Real-time prices from TCGPlayer and CardMarket, full card and set database for all OPCG sets.

In short

The One Piece Card Game API returns every OPCG set and card, from OP01 to the latest releases, with TCGPlayer (USD) and CardMarket (EUR) prices refreshed daily. Sets, cards, search and images are free (100 requests/hour); prices by set, set statistics and the other analytics endpoints need the Pro plan (€20/month) or its 7-day trial.

At a glance

- **Base path:** `https://api.pokewallet.io/op`
- **Sets:** All OPCG sets, from OP01 to the latest releases
- **Card IDs:** `op_` + hex
- **Prices:** TCGPlayer (USD) and CardMarket (EUR), refreshed daily
- **Free on every plan:** Sets, set cards, card details, search and images
- **Pro plan or 7-day trial:** Prices by set, set statistics, completion value, trending sets and top cards
- **API key:** The same key as the Pokémon API and the other games, with shared rate limits

Updated Oct 19, 2026

## Quick Start

Start fetching One Piece card data in seconds:

### Get an API Key

Sign up for free to get your API key. No credit card required.

[Sign Up Free](https://pokewallet.io/auth/login?source=one_piece)

### Make Your First Request

Fetch all One Piece sets with a single call:

*cURL*

```bash
curl https://api.pokewallet.io/op/sets \
    -H "X-API-Key: YOUR_API_KEY"
```

### Fetch a Specific Set

Get all cards in OP01 — Romance Dawn:

*cURL*

```bash
curl https://api.pokewallet.io/op/sets/OP01 \
    -H "X-API-Key: YOUR_API_KEY"
```

## Authentication

All API requests (except `/health`) require authentication using an API key.

### API Key Format

API keys follow this format:

- **Production keys:** `pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
- **Development keys:** `pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`

> **Security Warning:** Never expose your API keys in client-side code, public repositories, or logs. Always use environment variables.

### Authentication Methods

You can authenticate using either the `X-API-Key` header or `Authorization` header:

*X-API-Key Header (Recommended)*

```bash
curl -H "X-API-Key: pk_live_your_key_here" \
     "https://api.pokewallet.io/search?q=pikachu"
```

*Authorization Header*

```bash
curl -H "Authorization: Bearer pk_live_your_key_here" \
     "https://api.pokewallet.io/search?q=pikachu"
```

## Rate Limits

Rate limits vary depending on your subscription plan:

Rate limits are shared across Pokémon and One Piece endpoints.

| Plan | Per hour | Per day | Paid endpoints | Price |
| --- | --- | --- | --- | --- |
| Free | 100 | 1,000 | — | €0 |
| Coffee | 1,000+ | 10,000+ | — | Buy a coffee on Ko-fi |
| Pro | 5,000 | 50,000 | Pokémon + One Piece | €20/month |
| Ultra | 7,000 | 70,000 | All 12 games | €29/month |
| Business | Custom | Custom | All 12 games | Contact us |
| Early Access | 1,000 | 10,000 | — | No longer available |

> All new users start on the **Free plan**. Upgrade from your [dashboard](https://pokewallet.io/dashboard). Early Access was our initial launch tier and is no longer available for new users.

> **Please note:** After upgrading your plan, activation may require a couple of hours.

[See all plans, pricing and FAQs](https://pokewallet.io/pricing)

### Rate Limit Headers

Every API response includes rate limit information:

```
X-RateLimit-Limit-Hour: 100
X-RateLimit-Remaining-Hour: 95
X-RateLimit-Limit-Day: 1000
X-RateLimit-Remaining-Day: 823
```

### Rate Limit Exceeded (429)

When you exceed your rate limit, you'll receive a `429 Too Many Requests` response:

```json
{
  "error": "Rate limit exceeded",
  "message": "Hourly limit exceeded",
  "limits": {
    "hourly": {
      "limit": 100,
      "used": 100,
      "remaining": 0
    },
    "daily": {
      "limit": 1000,
      "used": 523,
      "remaining": 477
    }
  }
}
```

## Public Endpoints

> **No Authentication Required:** These endpoints are publicly accessible.

### GET /health (No Auth Required)

Check API status, database, cache, and storage health with response times.

### Example Request:

*cURL*

```bash
curl "https://api.pokewallet.io/health"
```

### Response Example (Healthy):

*200 OK*

```json
{
  "status": "healthy",
  "timestamp": "2025-12-16T10:30:00.000Z",
  "version": "1.1.0",
  "checks": {
    "database": {
      "status": "healthy",
      "responseTime": 45
    },
    "cache": {
      "status": "healthy",
      "responseTime": 3
    },
    "storage": {
      "status": "healthy",
      "responseTime": 12
    }
  },
  "responseTime": 60,
  "region": "FRA"
}
```

### Response Example (Unhealthy):

*503 Service Unavailable*

```json
{
  "status": "unhealthy",
  "timestamp": "2025-12-16T10:30:00.000Z",
  "version": "1.1.0",
  "message": "Critical services unavailable - API may not function correctly",
  "checks": {
    "database": {
      "status": "unhealthy",
      "responseTime": null,
      "message": "Connection failed"
    },
    "cache": {
      "status": "healthy",
      "responseTime": 3
    },
    "storage": {
      "status": "healthy",
      "responseTime": 12
    }
  },
  "responseTime": 1050,
  "region": "FRA"
}
```

### GET / (No Auth Required)

Get API information, version, and available endpoints.

### Example Request:

*cURL*

```bash
curl "https://api.pokewallet.io/"
```

### Response Example:

*200 OK*

```json
{
  "name": "PokeWallet API",
  "version": "1.1.0",
  "status": "production",
  "authentication": {
    "required": true,
    "method": "API Key",
    "header": "X-API-Key",
    "format": "pk_live_xxxxxxxxxxxxx"
  },
  "endpoints": {
    "health": { "path": "/health", "auth_required": false },
    "search": { "path": "/search?q=charizard&limit=20", "auth_required": true },
    "cardDetail": { "path": "/cards/:id", "auth_required": true },
    "sets": { "path": "/sets", "auth_required": true },
    "setDetails": { "path": "/sets/:setCode?page=1&limit=50", "auth_required": true },
    "images": { "path": "/images/:id?size=high", "auth_required": true }
  },
  "rate_limits": {
    "per_hour": 100,
    "per_day": 1000,
    "plan": "free"
  }
}
```

### GET /games (No Auth Required)

Lists the games available under their own prefix (`/mtg`, `/ygo`, …) with their routes. Pokémon and One Piece are not in this list: they use `/cards`, `/sets`… and `/op/…`.

### Example Request:

*cURL*

```bash
curl "https://api.pokewallet.io/games"
```

### Response Example (first of ten games):

*200 OK*

```json
{
  "success": true,
  "data": [
    {
      "code": "mtg",
      "name": "Magic: the Gathering",
      "endpoints": {
        "sets": "/mtg/sets",
        "set": "/mtg/sets/:set",
        "card": "/mtg/cards/:id",
        "search": "/mtg/search?q=",
        "image": "/mtg/images/:id"
      }
    }
  ]
}
```

> **One Piece Card Game PRO endpoints: Pro or Ultra plan**
>
> Pro (€20/month) covers Pokémon and One Piece only. Ultra (€29/month) includes everything in Pro plus the paid endpoints of the other 10 games: Magic, Yu-Gi-Oh!, Lorcana and more.
>
> [Compare plans →](https://pokewallet.io/pricing)

## Sets Endpoints

### GET /op/sets

Returns all One Piece sets ordered by release date.

### Parameters:

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `language` | string | Optional | Filter by language: `en` or `jp` |

### Example Request:

*cURL*

```bash
curl -H "X-API-Key: pk_live_your_key_here" \
     "https://api.pokewallet.io/op/sets?language=en"
```

### Response Example:

*200 OK*

```json
{
  "success": true,
  "data": [
    {
      "name": "Romance Dawn",
      "set_code": "OP01",
      "group_id": "3188",
      "language": "en",
      "release_date": "2022-12-02"
    },
    {
      "name": "Paramount War",
      "set_code": "OP02",
      "group_id": "3189",
      "language": "en",
      "release_date": "2023-03-10"
    }
  ],
  "total": 100
}
```

> `group_id` is the numeric identifier for the set in the DB. Positive = TCG set, negative = CM-only set (no TCGPlayer data). Set images are not available for One Piece sets.

### GET /op/sets/:setCode

Returns a paginated card list for a specific One Piece set.

### Path Parameter:

| Value | Behavior |
| --- | --- |
| `OP01` | Lookup by `set_code` (case-insensitive) |
| `3188` | Lookup by numeric `group_id` |
| `-8` | CM-only set (negative group_id) |
| `EB01` | Fuzzy fallback: automatically tries `EB-01` |

### Query Parameters:

| Parameter | Default | Max |
| --- | --- | --- |
| `page` | 1 | — |
| `limit` | 50 | 200 |

### Example Request:

*cURL*

```bash
curl -H "X-API-Key: pk_live_your_key_here" \
     "https://api.pokewallet.io/op/sets/OP01?page=1&limit=50"
```

### Response Example:

*200 OK*

```json
{
  "success": true,
  "set": {
    "set_code": "OP01",
    "group_id": "3188",
    "name": "Romance Dawn",
    "language": "en",
    "release_date": "2022-12-02"
  },
  "total": 50,
  "page": 1,
  "limit": 50,
  "data": [
    {
      "id": "op_3f8a12c4e9b7d02f...",
      "card_number": "OP01-001",
      "name": "Roronoa Zoro",
      "clean_name": "Roronoa Zoro",
      "sub_type_name": "Normal",
      "rarity": "L",
      "card_type": "Leader",
      "ext_color": "Red",
      "ext_cost": null,
      "ext_power": "5000",
      "ext_life": "5",
      "ext_subtypes": "Straw Hat Crew;Supernovas",
      "ext_attribute": "Slash",
      "ext_counterplus": null,
      "ext_description": "[DON!! x1] ...",
      "tcgplayer": {
        "url": "https://www.tcgplayer.com/product/...",
        "prices": {
          "low_price": 1.20,
          "market_price": 1.76,
          "high_price": 3.50
        }
      },
      "cardmarket": {
        "product_name": "Roronoa Zoro (OP01-001)",
        "product_url": "https://www.cardmarket.com/...",
        "prices": { "avg": 1.64, "low": 0.50, "trend": 1.70 }
      }
    }
  ]
}
```

> **CM-only sets** (negative `group_id`): cards have `tcgplayer: null` and no `ext_*` fields. `total` is the full card count for the set (not just the current page). Each card also includes a `clean_name` field (normalized name without special characters).

## Cards Endpoints

### GET /op/cards/:id

Returns details for a single One Piece card. The `id` must use the `op_` prefix.

### Parameters:

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Required | Card ID with `op_` prefix. Obtained from `/op/search`, `/op/sets/:setCode`, or `/op/prices`. |

### Example Request:

*cURL*

```bash
curl -H "X-API-Key: pk_live_your_key_here" \
     "https://api.pokewallet.io/op/cards/op_3f8a12c4e9b7d02f..."
```

### Response Example:

*200 OK*

```json
{
  "id": "op_3f8a12c4e9b7d02f...",
  "card_number": "OP01-001",
  "name": "Roronoa Zoro",
  "clean_name": "Roronoa Zoro",
  "sub_type_name": "Normal",
  "rarity": "L",
  "card_type": "Leader",
  "ext_color": "Red",
  "ext_cost": null,
  "ext_power": "5000",
  "ext_life": "5",
  "ext_subtypes": "Straw Hat Crew;Supernovas",
  "ext_attribute": "Slash",
  "ext_counterplus": null,
  "ext_description": "[DON!! x1] [Activate: Main] ...",
  "tcgplayer": {
    "url": "https://www.tcgplayer.com/product/...",
    "prices": {
      "low_price": 1.20,
      "market_price": 1.76,
      "high_price": 3.50
    }
  },
  "cardmarket": {
    "product_name": "Roronoa Zoro (OP01-001)",
    "product_url": "https://www.cardmarket.com/...",
    "prices": { "avg": 1.64, "low": 0.50, "trend": 1.70 }
  }
}
```

### Error Codes:

| HTTP | Condition |
| --- | --- |
| `400` | ID missing `op_` prefix |
| `400` | Corrupted or undecryptable payload |
| `404` | Card not found in DB |

> **CM-only cards** (`group_id < 0`): `tcgplayer: null`, all `ext_*` fields are `null`. **SP reprints**: cards whose `card_number` belongs to a different set return `cardmarket: null` to avoid cross-set price collisions.

## Search Endpoints

### GET /op/search

Full-text search on One Piece card name and `card_number`.

### Parameters:

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `q` | string | Required | `ILIKE %q%` on card name and `card_number` (e.g. `zoro`, `OP01-001`) |
| `page` | number | Optional | Page number (default: 1, min: 1) |
| `limit` | number | Optional | Results per page (default: 20, max: 100) |

### Example Request:

*cURL*

```bash
curl -H "X-API-Key: pk_live_your_key_here" \
     "https://api.pokewallet.io/op/search?q=zoro&page=1&limit=20"
```

### Response Example:

*200 OK*

```json
{
  "success": true,
  "data": [
    {
      "id": "op_3f8a12c4e9b7d02f...",
      "card_number": "OP01-001",
      "name": "Roronoa Zoro",
      "sub_type_name": "Normal",
      "rarity": "L",
      "card_type": "Leader",
      "tcgplayer": {
        "url": "https://www.tcgplayer.com/product/...",
        "prices": { "low_price": 1.20, "market_price": 1.76, "high_price": 3.50 }
      },
      "cardmarket": {
        "product_name": "Roronoa Zoro (OP01-001)",
        "product_url": "https://www.cardmarket.com/...",
        "prices": { "avg": 1.64, "low": 0.50, "trend": 1.70 }
      }
    }
  ],
  "total": 12,
  "page": 1,
  "limit": 20
}
```

> **Known limitation:** Queries containing apostrophes (e.g. `d'artagnan`) return 0 results due to `ILIKE` handling of special characters. CM-only cards are not indexed for name search — only TCG cards appear in results.

## Prices Endpoints

### GET /op/prices?set_code={set_code} (PRO)

Raw prices for an entire One Piece set, all variants, no filtering. The set is identified via **query parameters** — `set_code` or `group_id` — not as a path segment. At least one is required.

> **Query parameters only.** `/op/prices?set_code=OP01` ✓ `/op/prices/OP01` ✗

> **Pro feature — 7-day free trial available.** Activate your free trial from the [dashboard](https://pokewallet.io/dashboard) to access this endpoint at no cost.

### Parameters:

| Parameter | Type | Required | Examples |
| --- | --- | --- | --- |
| `set_code` | string | One of these | `OP01`, `EB-01`, `EB01` (fuzzy → `EB-01`) |
| `group_id` | number | One of these | `3188`, `-8` (CM-only set) |

### Example Request:

*cURL*

```bash
# by set_code (case-insensitive)
curl -H "X-API-Key: pk_live_your_key_here" \
     "https://api.pokewallet.io/op/prices?set_code=OP01"

# by group_id (numeric)
curl -H "X-API-Key: pk_live_your_key_here" \
     "https://api.pokewallet.io/op/prices?group_id=3188"
```

### Response Example:

*200 OK*

```json
{
  "success": true,
  "group_id": "3188",
  "total": 159,
  "data": [
    {
      "card_number": "OP01-001",
      "name": "Roronoa Zoro (001)",
      "variant": "Normal",
      "tcgplayer": {
        "low_price": 1.20,
        "market_price": 1.76,
        "high_price": 3.50,
        "mid_price": 2.10,
        "direct_low_price": 1.50,
        "updated_at": "2026-05-14T00:00:00Z"
      },
      "cardmarket": {
        "avg": 1.64,
        "low": 0.50,
        "trend": 1.70,
        "avg1": 1.60,
        "avg7": 1.65,
        "avg30": 1.70,
        "updated_at": "2026-05-14T00:00:00Z"
      }
    },
    {
      "card_number": "OP01-001",
      "name": "Roronoa Zoro (001) (Foil)",
      "variant": "Foil",
      "tcgplayer": { "low_price": 3.50, "market_price": 4.20, "high_price": 6.00, "...": "..." },
      "cardmarket": { "avg": 3.80, "low": 2.50, "trend": 3.90, "...": "..." }
    }
  ]
}
```

### Error Codes:

| HTTP | Condition |
| --- | --- |
| `400` | Neither `set_code` nor `group_id` provided |
| `404` | Set not found |

> For CM-only sets (`group_id < 0`): `tcgplayer: null` on all cards and `variant: null` (CM does not expose `sub_type_name`). The `cardmarket` object is always present with real prices.

## One Piece Pro endpoints

Available on Pro, Ultra and Business plans, or during the 7-day trial. Same rules and response format as the Pokémon and other games' endpoints of the same name. Sealed products (booster boxes, packs) are excluded from statistics, completion value and rankings; DON!! cards count as cards.

| Endpoint | What it returns |
| --- | --- |
| `GET /op/sets/:set/statistics` | Price statistics and rarity breakdown of a set. `:set` = set code (`OP01`) or group id. `?variant=normal\|foil` |
| `GET /op/sets/:set/completion-value` | Cost of one copy of every card in the set, TCGPlayer (USD) and CardMarket (EUR) |
| `GET /op/sets/trending` | Sets whose CardMarket prices moved most: 7-day average against 30-day average, cards from 1 € up. `?period=7d` `?limit=` (max 50) |
| `GET /op/analytics/top-cards` | Most expensive cards, or fastest-growing on CardMarket. `?metric=price\|growth` `?source=tcg\|cm` (growth: `cm` only) `?limit=` (max 100) |

> Price history is a Pokémon feature: `/op/cards/:id/price-history` answers 404. Current prices are in `/op/cards/:id` and `/op/prices`.

### Statistics

*200 OK — /op/sets/OP01/statistics*

```json
{
  "set_info": {
    "name": "Romance Dawn",
    "set_code": "OP01",
    "set_id": "3188",
    "total_cards": 159
  },
  "price_statistics": {
    "tcgplayer": {
      "avg_market_price": "53.37",
      "min_price": 0.07,
      "max_price": 3998.74,
      "most_expensive": {
        "id": "op_7816ebfb908c6a34cd6feabbf11c84943582bbc7d8109009e47917e7e499e84b245a31a536a5865d5663ccaa201c9f7f",
        "name": "Shanks (Parallel) (Manga) (Alternate Art)",
        "price": 3998.74
      }
    },
    "cardmarket": {
      "avg_price": "59.17",
      "min_price": 0.03,
      "max_price": 4566.67,
      "most_expensive": {
        "id": "op_7816ebfb908c6a34cd6feabbf11c84943582bbc7d8109009e47917e7e499e84b245a31a536a5865d5663ccaa201c9f7f",
        "name": "Shanks (Parallel) (Manga) (Alternate Art)",
        "price": 4566.67
      },
      "trend_direction": "up"
    }
  },
  "rarity_breakdown": {
    "L": 16,
    "R": 35,
    "UC": 32,
    "C": 49,
    "SR": 20,
    "SEC": 5,
    "DON!!": 2
  }
}
```

### Completion value

*200 OK — /op/sets/OP01/completion-value*

```json
{
  "set_info": {
    "name": "Romance Dawn",
    "set_code": "OP01",
    "set_id": "3188",
    "total_cards": 159
  },
  "completion_cost": {
    "tcgplayer": {
      "currency": "USD",
      "low_estimate": 7238.83,
      "market_estimate": 8485.5,
      "high_estimate": 38920.95
    },
    "cardmarket": {
      "currency": "EUR",
      "low_estimate": 6489.33,
      "avg_estimate": 9408,
      "trend_estimate": 9123.63
    },
    "note": "One copy per card (base finish). TCGPlayer prices in USD, CardMarket prices in EUR. Cross-currency comparison not available."
  },
  "breakdown_by_rarity": {
    "L": {
      "count": 16,
      "total_cost": 2758.99
    },
    "R": {
      "count": 35,
      "total_cost": 567.22
    },
    "UC": {
      "count": 32,
      "total_cost": 47.61
    },
    "C": {
      "count": 49,
      "total_cost": 21.23
    },
    "SR": {
      "count": 20,
      "total_cost": 859.62
    },
    "SEC": {
      "count": 5,
      "total_cost": 4225.13
    },
    "DON!!": {
      "count": 2,
      "total_cost": 5.7
    }
  }
}
```

### Trending sets (first entry)

*200 OK — /op/sets/trending?limit=3*

```json
{
  "period": "7d",
  "trending_sets": [
    {
      "set_name": "Extra Booster: Anime 25th Collection (Japanese)",
      "set_code": "EB-02-JP",
      "set_id": "-7",
      "card_count": 46,
      "cardmarket": {
        "price_change": "+91.3%",
        "avg_price_current": 208.2,
        "avg_price_previous": 108.85,
        "top_movers": [
          {
            "name": "Monkey.D.Luffy (OP05-060)",
            "change": "+197.9%"
          },
          {
            "name": "Tony Tony.Chopper (OP08-001)",
            "change": "+191.2%"
          },
          {
            "name": "Hannyabal (EB01-021)",
            "change": "+163.1%"
          }
        ]
      },
      "tcgplayer": null
    }
  ]
}
```

### Top cards by price (first entry)

*200 OK — /op/analytics/top-cards?limit=3*

```json
{
  "metric": "price",
  "source": "tcg",
  "top_cards": [
    {
      "id": "op_4efc83a71371699af41ffc592c2c1c2076567bcff30c224518260e7ad036150f0156f916c677e9abc3804cefaaf233c9c9",
      "card_info": {
        "name": "Monkey.D.Luffy (119) (SP) (Gold)",
        "clean_name": "Monkey.D.Luffy (119) (SP) (Gold)",
        "set_name": "A Fist of Divine Speed",
        "set_code": "OP11",
        "set_id": "24241",
        "card_number": "OP05-119",
        "rarity": "SEC",
        "card_type": null,
        "product_type": "card",
        "variants": [
          "Foil"
        ],
        "card_text": null
      },
      "current_price": 13000
    }
  ]
}
```

## Images Endpoint

### GET /images/:id

Returns card images served via CDN. Use the card's `id` as the path parameter.

### Path Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `id` | string | Card identifier (e.g. `OP01-001`) |

### Example Request:

*cURL*

```bash
curl https://api.pokewallet.io/images/OP01-001 \
  -H "X-API-Key: YOUR_API_KEY"
```

> Images are served as binary content. Use the `image_url` field returned by card endpoints to construct the URL directly.

## Code Examples

### JavaScript / Node.js

*javascript*

```javascript
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.pokewallet.io';

// Fetch all OP sets
const res = await fetch(`${BASE_URL}/op/sets`, {
  headers: { 'X-API-Key': API_KEY }
});
const { sets } = await res.json();

// Get a specific set
const setRes = await fetch(`${BASE_URL}/op/sets/OP01`, {
  headers: { 'X-API-Key': API_KEY }
});
const setData = await setRes.json();

// Search for a card
const searchRes = await fetch(
  `${BASE_URL}/op/search?q=Luffy`,
  { headers: { 'X-API-Key': API_KEY } }
);
const { results } = await searchRes.json();
```

### Python

*python*

```python
import requests

API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://api.pokewallet.io'
HEADERS = {'X-API-Key': API_KEY}

# Fetch all OP sets
sets = requests.get(f'{BASE_URL}/op/sets', headers=HEADERS).json()

# Get bulk prices for OP07
prices = requests.get(
    f'{BASE_URL}/op/prices',
    params={'set_code': 'OP07'},
    headers=HEADERS
).json()
```

## Error Handling

The API uses standard HTTP status codes to indicate success or failure:

- **200 OK** — Request successful
- **400 Bad Request** — Invalid parameters or malformed request
- **401 Unauthorized** — Missing or invalid API key
- **403 Forbidden** — Paid endpoint without the required plan or an active trial: Pro for Pokémon and One Piece, Ultra for the other games. The body includes `redeem_url` (trial not activated yet) or `upgrade_url` (trial expired).
- **404 Not Found** — Card, set or image does not exist
- **405 Method Not Allowed** — The API only accepts `GET` requests.
- **409 Conflict** — `/sets/:setCode/image`: the set code matches several sets. Retry with `?language=` or the numeric `set_id`.
- **429 Too Many Requests** — Rate limit exceeded
- **500 Internal Server Error** — Something went wrong on our side
- **502 Bad Gateway** — An image could not be fetched from its source. Temporary: retry later.

### Errors on game endpoints (`/mtg`, `/ygo`, …)

| Status | `error` | When |
| --- | --- | --- |
| 400 | `Invalid or corrupted card ID` | ID is neither `<game>_…` nor 64 hex, or belongs to another game |
| 400 | `Query parameter required` | `q` missing, shorter than 2 or longer than 100 characters |
| 400 | `Search query rejected` | `q` contains SQL-like text: rephrase it |
| 400 | `Invalid or corrupted card ID` + `did_you_mean` | The ID belongs to another game (e.g. a `lor_…` ID on `/mtg/cards`): `did_you_mean` has the right path |
| 404 | `Set not found` + `suggestions` | No set with that `set_id`/`set_code`. If you wrote the set *name*, `suggestions` lists the matching sets with their `set_id` |
| 404 | `Card not found`, `Image not found` | Card or image does not exist |
| 502 | `Image not available` | Image source temporarily unreachable |
| 503 | `Search temporarily unavailable` | The search took too long under load. Retry after the seconds in the `Retry-After` header, or use more specific words |

### Error Response Format

Every error has `error` (short, stable) and `message` (what to fix). When the API can tell what you meant, `did_you_mean` contains the corrected path:

```
// GET /magic/sets
  {
    "error": "Endpoint not found",
    "message": "Did you mean /mtg/sets?",
    "did_you_mean": "/mtg/sets",
    "docs": "https://pokewallet.io/api-docs"
  }
```

Authentication errors (401) also include an `example` request. A trailing slash is ignored: `/sets/` and `/sets` are the same endpoint.

## Best Practices

### Use Environment Variables

Never hardcode API keys. Always use environment variables or secure secret management.

### Handle Rate Limits Gracefully

Implement exponential backoff when you receive a 429 response. Check rate limit headers to avoid hitting limits.

### Cache Results

Cache API responses when appropriate to reduce requests and improve performance.

### Use Search Endpoint

Always use `/search` for the most complete and accurate data.

### Monitor Your Usage

Check your dashboard regularly to track API usage and avoid unexpected rate limit hits.

### Error Handling

Always implement proper error handling for network failures, rate limits, and invalid responses.

> **Security Reminder:** Keep your API keys secure. If you suspect a key has been compromised, revoke it immediately from your dashboard and generate a new one.

## One Piece Card Game API FAQ

### Is there a One Piece Card Game API?

Yes. BerryWallet, the One Piece Card Game API of PokéWallet, is a REST API with TCGPlayer and CardMarket prices for every English and Japanese set from OP01 Romance Dawn onward. The free tier needs no credit card.

### Is there a free One Piece card price API?

Yes. The free tier (100 requests/hour, 1,000/day) opens /op/sets, /op/cards/:id, /op/search and the card images, with TCGPlayer and CardMarket prices refreshed daily. Prices by set, set statistics, completion value, trending sets and top cards need the Pro plan (€20/month) or its 7-day trial.

### Does the One Piece Card Game API include CardMarket prices?

Yes. Every card returns its TCGPlayer (USD) and CardMarket (EUR) prices where that market lists it, refreshed daily. Card ids start with op_ and work with /op/cards/:id.

### Is BerryWallet the same as the PokéWallet One Piece API?

Yes. BerryWallet is the One Piece Card Game API of PokéWallet: same account, same API key and the /op/ endpoints documented on this page.

### Can I use the same API key for other games?

Yes. One PokéWallet API key works for all 12 games, Pokémon and One Piece included, and the rate limits are shared across them.

## Need Help?

If you have questions or run into issues, we're here to help!

[Go to Dashboard](https://pokewallet.io/dashboard)

[Contact Support](mailto:hello@pokewallet.io)

[Join Discord](https://discord.gg/znDxEjmDVP)
