REST API specification for the Pokédex Image Recognition System.
- Base URL (local):
http://localhost:8000 - Base URL (production):
https://<domain>(V2 — see issue #68) - All responses are JSON.
| Method | Endpoint | Description | Version |
|---|---|---|---|
| GET | /health |
Health check | MVP |
| POST | /identify |
Upload image → identify Pokémon | MVP+ |
| GET | /pokemon |
List / search Pokémon | V2 (optional, US-06) |
| GET | /pokemon/{id} |
Get Pokémon by ID | V2 (optional, US-06) |
Health check endpoint. Used by ALB and ECS to verify the container is running and the model is loaded.
Response 200 — healthy
{"status": "ok", "model_loaded": true}Response 200 — degraded (model failed to load)
{"status": "degraded", "model_loaded": false}Upload an image and receive a Pokémon identification result.
Request
- Content-Type:
multipart/form-data - Field:
image— image file (jpg, png, webp) - Max file size: 10 MB
Response 200 — Pokémon identified
{
"recognition": {
"label": "pikachu",
"confidence": 0.94
},
"pokemon": {
"id": 25,
"name": "pikachu",
"types": ["electric"],
"hp": 35,
"attack": 55,
"defense": 40,
"special_attack": 50,
"special_defense": 50,
"speed": 90,
"height": 4,
"weight": 60,
"sprite_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png"
}
}Response 200 — recognised but not in database
{
"recognition": {
"label": "unknown",
"confidence": 0.61
},
"pokemon": null
}
pokemon: nullmeans YOLO returned a label but no matching Pokémon was found in the database. The frontend is responsible for showing a "not found" message (US-03).
Response 200 — no detection
{
"recognition": {
"label": "unknown",
"confidence": 0.0
},
"pokemon": null
}Returned when no object is detected above the confidence threshold. Default threshold:
0.3(configurable via environment variable).
Multiple detections: If YOLO detects more than one object, the highest-confidence detection is returned. V1 returns a single result only.
Response 400 — invalid file type
{"detail": "Unsupported file type. Accepted: image/jpeg, image/png, image/webp"}Response 413 — file too large
{"detail": "File too large. Maximum size: 10 MB"}Response 422 — corrupted or unprocessable image
{"detail": "Invalid or corrupted image"}Response 503 — inference error
{"detail": "Inference failed"}List all Pokémon in the database. Supports search by name and pagination.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | No | Filter by name (case-insensitive, partial match) |
limit |
integer | No | Max number of results to return (default: 100, max: 100) |
offset |
integer | No | Number of results to skip (default: 0) |
Response 200
[
{"id": 25, "name": "pikachu", "types": ["electric"]},
{"id": 4, "name": "charmander", "types": ["fire"]}
]Returns a lightweight list —
id,name,typesonly. UseGET /pokemon/{id}to retrieve full stats. This avoids over-fetching when browsing a list of Pokémon.
Get full details for a single Pokémon by ID.
Path parameter: id — Pokémon ID (integer)
Response 200
{
"id": 25,
"name": "pikachu",
"types": ["electric"],
"hp": 35,
"attack": 55,
"defense": 40,
"special_attack": 50,
"special_defense": 50,
"speed": 90,
"height": 4,
"weight": 60,
"sprite_url": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png"
}Response 404 — not found
{"detail": "Pokemon not found"}| Field | Type | Description |
|---|---|---|
label |
string | Detected class label from YOLO |
confidence |
float | Detection confidence score (0.0–1.0) |
| Field | Type | Description |
|---|---|---|
id |
int | Pokémon ID (from PokeAPI) |
name |
string | Pokémon name |
types |
list[string] | Type(s) e.g. ["water", "flying"] |
hp |
int | Base HP stat |
attack |
int | Base attack stat |
defense |
int | Base defense stat |
special_attack |
int | Base special attack stat |
special_defense |
int | Base special defense stat |
speed |
int | Base speed stat |
height |
int | Height in decimetres |
weight |
int | Weight in hectograms |
sprite_url |
string | null | URL to front default sprite image |
| Field | Type | Description |
|---|---|---|
recognition |
RecognitionResult | YOLO inference result |
pokemon |
Pokemon | null | Pokémon data from DB, or null if not found |
Casing: All names and types are returned lowercase (as sourced from PokeAPI). The frontend is responsible for display capitalisation.
Pokémon data is sourced from PokeAPI — a free, open REST API with no authentication required.
Endpoint: GET https://pokeapi.co/api/v2/pokemon/{id}
The seed script (scripts/seed_db.py) fetches each Pokémon and extracts only the fields the system needs:
| PokeAPI field | Extracted value | Maps to |
|---|---|---|
id |
integer | Pokemon.id |
name |
string | Pokemon.name |
types[*].type.name |
list of strings | Pokemon.types (stored as JSON string per ADR-015) |
stats[hp].base_stat |
integer | Pokemon.hp |
stats[attack].base_stat |
integer | Pokemon.attack |
stats[defense].base_stat |
integer | Pokemon.defense |
Example — Pikachu (id: 25)
PokeAPI returns (relevant fields only):
{
"id": 25,
"name": "pikachu",
"types": [
{"slot": 1, "type": {"name": "electric"}}
],
"stats": [
{"base_stat": 35, "stat": {"name": "hp"}},
{"base_stat": 55, "stat": {"name": "attack"}},
{"base_stat": 40, "stat": {"name": "defense"}},
{"base_stat": 50, "stat": {"name": "special-attack"}},
{"base_stat": 50, "stat": {"name": "special-defense"}},
{"base_stat": 90, "stat": {"name": "speed"}}
]
}After extraction, stored in the database as:
{
"id": 25,
"name": "pikachu",
"types": "[\"electric\"]",
"hp": 35,
"attack": 55,
"defense": 40
}Note: Only seed Pokémon that the YOLO model is trained to detect. See implementation note on issue #44.
Reference: PokeAPI (2024) PokéAPI — The RESTful Pokémon API. Available at: https://pokeapi.co (Accessed: 19 April 2026).