MENU navbar-image

Introduction

REST API for accessing comic book data, managing collections, and building integrations with VerseDB.

Welcome to the VerseDB API. This documentation provides everything you need to integrate with our comic book database.

Quickstart

  1. Create a token at versedb.com/my/apps/custom. The default read:public scope covers all read endpoints; add lookup:barcode for barcode lookups and the write:* scopes for collection/list management.
  2. Call the API with your token as a Bearer header. The base URL is https://versedb.com/api/v1.
curl -H "Authorization: Bearer $VERSEDB_TOKEN" \
     -H "Accept: application/json" \
     "https://versedb.com/api/v1/series?q=batman&limit=20"

List endpoints return a data array plus a meta object (current_page, last_page, per_page, total); request the next page with ?page=2.

Recipes

Search and paginate the catalog. All list endpoints (/series, /issues, /creators, /characters, ...) accept ?q= for search, limit (per page), and page. Walk meta.last_page to paginate. Detail endpoints are /{id} (e.g. /api/v1/series/123).

Barcode lookup (requires the lookup:barcode scope). GET /api/v1/lookup/upc/{upc} resolves a scanned barcode to a full issue. A 200 is a unique match; 404 means no match; 409 means several issues share that pre-1995 barcode — pick from the returned matches array. GET /api/v1/lookup/isbn/{isbn} covers trades and hardcovers.

Sync a collection (requires the write:collection scope). POST /api/v1/issues/{issue}/collection adds a copy (condition, grading, price paid), PATCH updates it, DELETE removes it, and GET /api/v1/issues/{issue}/collection/check tells you whether an issue is already owned. GET /api/v1/user/collections pages through everything. This is the flow ComicTagger-style tools use: scan barcode → look up issue → add to collection.

Manage lists (requires the write:list scope). POST /api/v1/lists creates a list, POST /api/v1/lists/{list}/items adds entries, PUT .../items/reorder reorders them. Browse public lists with GET /api/v1/lists or the platform-curated GET /api/v1/lists/system.

Official TypeScript SDK

npm install @versedbcom/sdk
import { VerseDB } from "@versedbcom/sdk";

const verseDB = new VerseDB({ token: "<your-api-token>" });
const series = await verseDB.series.listSeries({ q: "batman", limit: 20 });

The SDK is generated from this API's OpenAPI spec: typed models and errors for the full catalog, auth set once on the client, and configurable backoff retries (retryConfig). Source, runnable examples, and issue tracker: github.com/versedbcom/versedb-node (npm).

Machine-Readable Spec

The OpenAPI 3.1 spec is at /api/docs.openapi and a Postman collection at /api/docs.postman.

Token Ownership & Responsibility

API tokens act on behalf of the user who created them. Actions performed with a token are attributed to that user, and tokens inherit the user's permissions. You are responsible for all activity generated by your tokens.

Acceptable Use

This API is intended for integration, automation, and building tools that enhance the VerseDB experience. Bulk crawling, mirroring the dataset, or building competing databases is not permitted without prior approval. High-volume access should leverage caching and conditional requests.

Rate Limits

Two complementary limits apply to reads: an hourly cap that bounds burst speed, and a daily cap that bounds total volume. Both must be satisfied — whichever you reach first returns a 429. Search shares the read limits.

Tier Read / Search (hourly) Read / Search (daily) Write (hourly)
Free 300/hr 4,000/day 150/hr
PRO 1000/hr 20,000/day 500/hr

Exceeding either limit returns an HTTP 429 response with a Retry-After header telling you when to retry. The daily cap keeps the API responsive for everyone and prevents dataset mirroring (see Acceptable Use above) — design integrations to cache and request only what they need rather than walking the full catalog. For handling strategies and best practices, see our API Support Articles.

Versioning & Stability

The API is versioned. Breaking changes only occur in new versions, and deprecated endpoints will be announced before removal. Do not rely on undocumented fields or response shapes.

Security

Keep tokens secret and never embed them in client-side code. Rotate tokens if compromised and revoke tokens that are no longer in use.

Caching & Attribution

Cache responses whenever possible to reduce load. Respect cache headers when provided. If displaying VerseDB data publicly, attribution may be required depending on usage.

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_AUTH_KEY}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

You can retrieve your token by visiting your dashboard and clicking Generate API token. The token should be prefixed with "Bearer ".

Discovery

Dynamic content discovery endpoints for the home screen and new releases.

These endpoints provide curated and time-sensitive content like upcoming releases, FOC (Final Order Cutoff) deadlines, and new first issues.

FOC deadlines.

requires authentication

Returns issues with Final Order Cutoff (FOC) deadline within the next N days. FOC is when retailers must place final orders with distributors (typically 2 weeks before release).

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/discovery/foc?limit=10&days=7&start_date=2026-03-15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"limit\": 1,
    \"days\": 22,
    \"start_date\": \"2026-07-02\"
}"
const url = new URL(
    "https://versedb.com/api/v1/discovery/foc"
);

const params = {
    "limit": "10",
    "days": "7",
    "start_date": "2026-03-15",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "limit": 1,
    "days": 22,
    "start_date": "2026-07-02"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/discovery/foc'
payload = {
    "limit": 1,
    "days": 22,
    "start_date": "2026-07-02"
}
params = {
  'limit': '10',
  'days': '7',
  'start_date': '2026-03-15',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/discovery/foc';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'limit' => '10',
            'days' => '7',
            'start_date' => '2026-03-15',
        ],
        'json' => [
            'limit' => 1,
            'days' => 22,
            'start_date' => '2026-07-02',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 5432,
            "number": "1",
            "title": "Amazing Spider-Man",
            "cover_url": "...",
            "release_date": "2024-02-01",
            "foc_date": "2024-01-18",
            "series": {
                "id": 123,
                "name": "Amazing Spider-Man"
            }
        }
    ],
    "meta": {
        "foc_window_days": 7,
        "foc_start": "2024-01-15",
        "foc_end": "2024-01-22",
        "note": "FOC dates are estimates based on release_date - 14 days"
    }
}
 

Request      

GET api/v1/discovery/foc

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

limit   integer  optional    

Max results (1-50). Example: 10

days   integer  optional    

FOC window in days (1-30). Example: 7

start_date   string  optional    

Start of FOC window (YYYY-MM-DD). Defaults to today. Example: 2026-03-15

Body Parameters

limit   integer  optional    

Must be at least 1. Must not be greater than 50. Example: 1

days   integer  optional    

Must be at least 1. Must not be greater than 30. Example: 22

start_date   string  optional    

Must be a valid date. Must be a valid date in the format Y-m-d. Example: 2026-07-02

Upcoming #1 issues.

requires authentication

Returns upcoming first issues (#1) from new ongoing series within the next N days. Useful for discovering new series launches.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/discovery/upcoming-firsts?limit=10&days=60" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"limit\": 1,
    \"days\": 22
}"
const url = new URL(
    "https://versedb.com/api/v1/discovery/upcoming-firsts"
);

const params = {
    "limit": "10",
    "days": "60",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "limit": 1,
    "days": 22
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/discovery/upcoming-firsts'
payload = {
    "limit": 1,
    "days": 22
}
params = {
  'limit': '10',
  'days': '60',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/discovery/upcoming-firsts';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'limit' => '10',
            'days' => '60',
        ],
        'json' => [
            'limit' => 1,
            'days' => 22,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 9876,
            "number": "1",
            "title": "New Series #1",
            "cover_url": "...",
            "release_date": "2024-02-15",
            "series": {
                "id": 456,
                "name": "New Series",
                "status": "ongoing",
                "publication_type": "regular"
            }
        }
    ],
    "meta": {
        "lookahead_days": 60,
        "window_start": "2024-01-15",
        "window_end": "2024-03-15"
    }
}
 

Request      

GET api/v1/discovery/upcoming-firsts

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

limit   integer  optional    

Max results (1-25). Example: 10

days   integer  optional    

Lookahead window in days (1-90). Example: 60

Body Parameters

limit   integer  optional    

Must be at least 1. Must not be greater than 25. Example: 1

days   integer  optional    

Must be at least 1. Must not be greater than 90. Example: 22

Follow updates.

requires authentication

Returns recent releases from titles, series, characters, and creators the user follows. Each item includes a context string explaining why it's shown (e.g. "New in X-Men", "Featuring Superman").

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/discovery/follow-updates?limit=20&days=30&page=1&per_page=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"days\": 1,
    \"page\": 22,
    \"per_page\": 7
}"
const url = new URL(
    "https://versedb.com/api/v1/discovery/follow-updates"
);

const params = {
    "limit": "20",
    "days": "30",
    "page": "1",
    "per_page": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "days": 1,
    "page": 22,
    "per_page": 7
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/discovery/follow-updates'
payload = {
    "days": 1,
    "page": 22,
    "per_page": 7
}
params = {
  'limit': '20',
  'days': '30',
  'page': '1',
  'per_page': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/discovery/follow-updates';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'limit' => '20',
            'days' => '30',
            'page' => '1',
            'per_page' => '20',
        ],
        'json' => [
            'days' => 1,
            'page' => 22,
            'per_page' => 7,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 5432,
            "issue_number": "26",
            "cover_url": "...",
            "release_date": "2026-03-04",
            "series": {
                "id": 123,
                "name": "X-Men",
                "start_year": 2024
            },
            "follow_context": "New in X-Men",
            "follow_type": "title"
        }
    ],
    "meta": {
        "days": 30,
        "total_follows": 12
    }
}
 

Request      

GET api/v1/discovery/follow-updates

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

limit   integer  optional    

Max results (1-50). Example: 20

days   integer  optional    

Lookback window in days (1-90). Example: 30

page   integer  optional    

Page number for pagination. Example: 1

per_page   integer  optional    

Items per page (1-50). Example: 20

Body Parameters

days   integer  optional    

Must be at least 1. Must not be greater than 90. Example: 1

page   integer  optional    

Must be at least 1. Example: 22

per_page   integer  optional    

Must be at least 1. Must not be greater than 50. Example: 7

Titles

Endpoints for browsing comic book titles (franchises/properties).

A title represents a franchise (e.g., "Batman"), which may have multiple series under it.

List titles

requires authentication

Returns: id, name, slug, start_year, end_year, status, type, image_url, age_rating, is_nsfw, series_count, issues_count, average_rating, total_reviews

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/titles?q=spider-man&publisher=1&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/titles"
);

const params = {
    "q": "spider-man",
    "publisher": "1",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/titles'
params = {
  'q': 'spider-man',
  'publisher': '1',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/titles';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'spider-man',
            'publisher' => '1',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 12,
            "name": "Batman",
            "slug": "batman",
            "start_year": 1939,
            "end_year": null,
            "status": "ongoing",
            "type": "Series",
            "image_url": "https://r2.versedb.com/uploads/titles/batman-12/batman-12-abc123-cover_md.webp",
            "images": {
                "cover_sm": "https://r2.versedb.com/uploads/titles/batman-12/batman-12-abc123-cover_sm.webp",
                "cover_md": "https://r2.versedb.com/uploads/titles/batman-12/batman-12-abc123-cover_md.webp",
                "cover_lg": "https://r2.versedb.com/uploads/titles/batman-12/batman-12-abc123-cover_lg.webp"
            },
            "average_rating": 4.3,
            "series_count": 25,
            "issues_count": 1450,
            "age_rating": "Teen",
            "is_nsfw": false
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 50,
        "per_page": 20,
        "total": 1000
    }
}
 

Request      

GET api/v1/titles

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by title name. Example: spider-man

publisher   integer  optional    

Filter by publisher ID. Example: 1

limit   integer  optional    

Number of results per page (max 50). Example: 20

Get a specific title

requires authentication

Returns: id, name, slug, description, start_year, end_year, status, type, image_url, age_rating, is_nsfw, imprint_id, series_count, issues_count, average_rating, total_reviews, aliases

Use relationship endpoints for richer data:

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/titles/147410" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/titles/147410"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/titles/147410'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/titles/147410';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 12,
        "name": "Batman",
        "slug": "batman",
        "description": "The continuing adventures of the Dark Knight across his many series.",
        "start_year": 1939,
        "end_year": null,
        "status": "ongoing",
        "type": "Series",
        "image_url": "https://r2.versedb.com/uploads/titles/batman-12/batman-12-abc123-cover_md.webp",
        "images": {
            "cover_sm": "https://r2.versedb.com/uploads/titles/batman-12/batman-12-abc123-cover_sm.webp",
            "cover_md": "https://r2.versedb.com/uploads/titles/batman-12/batman-12-abc123-cover_md.webp",
            "cover_lg": "https://r2.versedb.com/uploads/titles/batman-12/batman-12-abc123-cover_lg.webp"
        },
        "age_rating": "Teen",
        "is_nsfw": false,
        "imprint_id": null,
        "series_count": 25,
        "issues_count": 1450,
        "average_rating": 4.3,
        "aliases": [
            "The Dark Knight",
            "The Caped Crusader"
        ]
    }
}
 

Example response (404, Not Found):


{
    "message": "No query results for model [App\\Models\\Title]."
}
 

Request      

GET api/v1/titles/{title_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

title_id   integer     

The ID of the title. Example: 147410

Series

Endpoints for browsing and searching comic book series.

A series represents a specific volume or run of a title (e.g., "Amazing Spider-Man (2018)").

List series.

requires authentication

Returns paginated series with optional search and filtering.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/series?q=spider-man&title_id=1&publisher_id=1&status=Ongoing&sort=start_year&direction=desc&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/series"
);

const params = {
    "q": "spider-man",
    "title_id": "1",
    "publisher_id": "1",
    "status": "Ongoing",
    "sort": "start_year",
    "direction": "desc",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/series'
params = {
  'q': 'spider-man',
  'title_id': '1',
  'publisher_id': '1',
  'status': 'Ongoing',
  'sort': 'start_year',
  'direction': 'desc',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/series';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'spider-man',
            'title_id' => '1',
            'publisher_id' => '1',
            'status' => 'Ongoing',
            'sort' => 'start_year',
            'direction' => 'desc',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 123,
            "title_id": 45,
            "name": "Amazing Spider-Man",
            "slug": "amazing-spider-man-2018",
            "number": 6,
            "start_year": 2018,
            "end_year": 2022,
            "cover_url": "https://...",
            "publication_type": "ongoing",
            "format": "comic",
            "status": "ended",
            "original_language": "en",
            "cached_issues_count": 75,
            "average_rating": 4.2,
            "total_reviews": 150,
            "age_rating": "teen",
            "is_nsfw": false
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 5,
        "per_page": 20,
        "total": 100
    }
}
 

Request      

GET api/v1/series

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by series name. Example: spider-man

title_id   integer  optional    

Filter by title ID. Example: 1

publisher_id   integer  optional    

Filter by publisher ID. Example: 1

status   string  optional    

Filter by series status (Ongoing, Completed, Canceled). Example: Ongoing

sort   string  optional    

Sort field (name, start_year, average_rating, latest_release_date, cached_issues_count). Example: start_year

direction   string  optional    

Sort direction (asc, desc). Example: desc

limit   integer  optional    

Number of results per page (max 50). Example: 20

Get series details.

requires authentication

Returns a single series with full details including related title, publishers, and genres. For relationship data (issues, creators, characters), use the relationship endpoints.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/series/123" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/series/123"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/series/123'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/series/123';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 123,
        "title_id": 45,
        "name": "Amazing Spider-Man",
        "slug": "amazing-spider-man-2018",
        "number": 6,
        "start_year": 2018,
        "end_year": 2022,
        "cover_url": "https://...",
        "description": "The sixth volume of Amazing Spider-Man...",
        "publication_type": "ongoing",
        "format": "comic",
        "status": "ended",
        "original_language": "en",
        "cached_issues_count": 75,
        "average_rating": 4.2,
        "total_reviews": 150,
        "age_rating": "teen",
        "is_nsfw": false,
        "cached_creators_count": 12,
        "cached_characters_count": 24,
        "cached_teams_count": 3,
        "lists_count": 8,
        "title": {
            "id": 45,
            "name": "Amazing Spider-Man",
            "url_slug": "amazing-spider-man"
        },
        "publisher": {
            "id": 1,
            "name": "Marvel",
            "slug": "marvel"
        },
        "publishers": [
            {
                "id": 1,
                "name": "Marvel",
                "slug": "marvel"
            }
        ],
        "genres": [
            {
                "id": 1,
                "name": "Superhero"
            }
        ],
        "imprint": null,
        "effective_imprint": null,
        "last_edited_by": {
            "id": 42,
            "name": "Jane Doe",
            "username": "janedoe",
            "avatar_url": "https://..."
        },
        "creators": [
            {
                "id": 789,
                "name": "Nick Spencer",
                "slug": "nick-spencer",
                "photo_url": "https://...",
                "role": "Writer",
                "is_uncredited": false
            }
        ],
        "characters": [
            {
                "id": 456,
                "name": "Spider-Man (Peter Parker)",
                "slug": "spider-man-peter-parker",
                "real_name": "Peter Parker",
                "aliases": [],
                "image_url": "https://...",
                "appearances_count": 75
            }
        ],
        "teams": [
            {
                "id": 33,
                "name": "Avengers",
                "slug": "avengers",
                "image_url": "https://...",
                "members_count": 24
            }
        ],
        "foc_issues": [
            {
                "id": 9912,
                "issue_number": "42",
                "name": "Issue 42",
                "release_date": "2026-06-04",
                "foc_date": "2026-05-12",
                "cover_url": "https://..."
            }
        ],
        "upcoming_issues": [
            {
                "id": 9913,
                "issue_number": "43",
                "name": "Issue 43",
                "release_date": "2026-06-11",
                "cover_url": "https://..."
            }
        ]
    }
}
 

Example response (404, Not Found):


{
    "message": "Not Found"
}
 

Request      

GET api/v1/series/{series_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

series_id   integer     

The series ID. Example: 123

Get series issues.

requires authentication

Returns paginated issues for a specific series.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/series/123/issues?sort=issue_number&direction=asc&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/series/123/issues"
);

const params = {
    "sort": "issue_number",
    "direction": "asc",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/series/123/issues'
params = {
  'sort': 'issue_number',
  'direction': 'asc',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/series/123/issues';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'sort' => 'issue_number',
            'direction' => 'asc',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 5432,
            "number": "1",
            "name": "The Amazing Spider-Man #1",
            "release_date": "2018-07-11",
            "cover_url": "https://...",
            "average_rating": 4.5
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 4,
        "per_page": 20,
        "total": 75
    }
}
 

Request      

GET api/v1/series/{id}/issues

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The series ID. Example: 123

Query Parameters

sort   string  optional    

Sort field (issue_number, release_date, name). Example: issue_number

direction   string  optional    

Sort direction (asc, desc). Example: asc

limit   integer  optional    

Results per page (max 100). Example: 20

Get series creators.

requires authentication

Returns paginated creators associated with a specific series.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/series/123/creators" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/series/123/creators"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/series/123/creators'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/series/123/creators';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 789,
            "name": "Nick Spencer",
            "role": {
                "id": 1,
                "name": "Writer"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 50,
        "total": 15
    }
}
 

Request      

GET api/v1/series/{id}/creators

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The series ID. Example: 123

Get series characters.

requires authentication

Returns paginated characters appearing in a specific series.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/series/123/characters" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/series/123/characters"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/series/123/characters'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/series/123/characters';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 456,
            "name": "Spider-Man (Peter Parker)",
            "alias": "Peter Parker",
            "image_url": "https://..."
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 2,
        "per_page": 50,
        "total": 75
    }
}
 

Request      

GET api/v1/series/{id}/characters

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The series ID. Example: 123

Issues

Endpoints for browsing and searching comic book issues.

An issue is a single publication in a series (e.g., "Amazing Spider-Man #1").

List issues.

requires authentication

Returns paginated issues with optional search, filtering, and sorting.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/issues?q=origin&series_id=123&publisher_id=1&release_date_from=2024-01-01&release_date_to=2024-12-31&include=series&sort=release_date&direction=desc&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/issues"
);

const params = {
    "q": "origin",
    "series_id": "123",
    "publisher_id": "1",
    "release_date_from": "2024-01-01",
    "release_date_to": "2024-12-31",
    "include": "series",
    "sort": "release_date",
    "direction": "desc",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues'
params = {
  'q': 'origin',
  'series_id': '123',
  'publisher_id': '1',
  'release_date_from': '2024-01-01',
  'release_date_to': '2024-12-31',
  'include': 'series',
  'sort': 'release_date',
  'direction': 'desc',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'origin',
            'series_id' => '123',
            'publisher_id' => '1',
            'release_date_from' => '2024-01-01',
            'release_date_to' => '2024-12-31',
            'include' => 'series',
            'sort' => 'release_date',
            'direction' => 'desc',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 5432,
            "slug": "amazing-spider-man-1",
            "series_id": 123,
            "issue_number": "1",
            "name": "The Amazing Spider-Man #1",
            "release_date": "2018-07-11",
            "cover_url": "https://...",
            "is_reprint": false,
            "age_rating": "teen",
            "is_nsfw": false
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 10,
        "per_page": 20,
        "total": 200
    }
}
 

Request      

GET api/v1/issues

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by issue name. Example: origin

series_id   integer  optional    

Filter by series ID. Example: 123

publisher_id   integer  optional    

Filter by publisher ID (via series relationship). Example: 1

release_date_from   string  optional    

Filter by release date (from). Example: 2024-01-01

release_date_to   string  optional    

Filter by release date (to). Example: 2024-12-31

include   string  optional    

Comma-separated relationships to include (series). Example: series

sort   string  optional    

Sort field (issue_number, release_date, name). Example: release_date

direction   string  optional    

Sort direction (asc, desc). Example: desc

limit   integer  optional    

Results per page (max 100). Example: 20

Get issue details.

requires authentication

Returns a single issue with full details including series, title, publishers, creators, characters, teams, and story arcs.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/issues/5432" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 5432,
        "slug": "amazing-spider-man-1",
        "series_id": 123,
        "issue_number": "1",
        "name": "The Amazing Spider-Man #1",
        "description": "Nick Spencer and Ryan Ottley begin a new era...",
        "release_date": "2018-07-11",
        "cover_date": "2018-09-01",
        "cover_url": "https://...",
        "is_reprint": false,
        "age_rating": "teen",
        "is_nsfw": false,
        "page_count": 40,
        "price": "4.99",
        "upc": "75960608936700111",
        "series": {
            "id": 123,
            "name": "Amazing Spider-Man",
            "slug": "amazing-spider-man-2018"
        },
        "title": {
            "id": 45,
            "name": "Amazing Spider-Man"
        },
        "publisher": {
            "id": 1,
            "name": "Marvel",
            "slug": "marvel"
        },
        "creators": [
            {
                "id": 789,
                "name": "Nick Spencer",
                "slug": "nick-spencer",
                "role": "Writer"
            }
        ],
        "characters": [
            {
                "id": 456,
                "name": "Spider-Man",
                "slug": "spider-man"
            }
        ]
    }
}
 

Example response (404, Not Found):


{
    "message": "Not Found"
}
 

Request      

GET api/v1/issues/{issue_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Get issue variants.

requires authentication

Returns all variant covers for a specific issue.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/issues/5432/variants" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/variants"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/variants'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/variants';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 9001,
            "variant_name": "J. Scott Campbell Variant",
            "variant_type": "incentive",
            "ratio": "1:25",
            "cover_url": "https://...",
            "creators": [
                {
                    "id": 101,
                    "name": "J. Scott Campbell",
                    "role": "Cover Artist"
                }
            ]
        }
    ]
}
 

Request      

GET api/v1/issues/{issue_id}/variants

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Get variant details.

requires authentication

Returns a specific variant cover with full details.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/issues/5432/variants/9001" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/variants/9001"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/variants/9001'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/variants/9001';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 9001,
        "issue_id": 5432,
        "variant_name": "J. Scott Campbell Variant",
        "variant_type": "incentive",
        "ratio": "1:25",
        "cover_url": "https://...",
        "price": "49.99",
        "ean": "75960608936700121",
        "creators": [
            {
                "id": 101,
                "name": "J. Scott Campbell",
                "slug": "j-scott-campbell",
                "role": "Cover Artist"
            }
        ]
    }
}
 

Example response (404, Not Found):


{
    "error": "Variant does not belong to this issue"
}
 

Request      

GET api/v1/issues/{issue_id}/variants/{variant_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

variant_id   integer     

The variant ID. Example: 9001

Get issue creators.

requires authentication

Returns paginated creators for a specific issue with their roles.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/issues/5432/creators" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/creators"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/creators'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/creators';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 789,
            "name": "Nick Spencer",
            "role": {
                "id": 1,
                "name": "Writer"
            }
        },
        {
            "id": 790,
            "name": "Ryan Ottley",
            "role": {
                "id": 2,
                "name": "Artist"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 50,
        "total": 8
    }
}
 

Request      

GET api/v1/issues/{id}/creators

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The issue ID. Example: 5432

Get issue characters.

requires authentication

Returns paginated characters appearing in a specific issue.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/issues/5432/characters" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/characters"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/characters'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/characters';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 456,
            "name": "Spider-Man (Peter Parker)",
            "alias": "Peter Parker",
            "image_url": "https://..."
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 50,
        "total": 15
    }
}
 

Request      

GET api/v1/issues/{id}/characters

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The issue ID. Example: 5432

Get key issue reasons.

requires authentication

Returns key issue reasons for a specific issue (e.g., "1st Appearance", "Death").

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/issues/5432/key-reasons" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/key-reasons"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/key-reasons'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/key-reasons';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 1,
            "name": "1st Appearance",
            "category": "appearance",
            "description": "First appearance of a character",
            "notes": "1st full appearance of Wolverine (Logan)",
            "source": "manual"
        }
    ]
}
 

Request      

GET api/v1/issues/{issue_id}/key-reasons

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Publishers

Endpoints for browsing comic book publishers.

List all publishers with optional search

requires authentication

Returns: id, name, founded_year, headquarters, status, logo_url

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/publishers?q=marvel&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/publishers"
);

const params = {
    "q": "marvel",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/publishers'
params = {
  'q': 'marvel',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/publishers';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'marvel',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 1,
            "name": "Marvel Comics",
            "founded_year": 1939,
            "headquarters": "New York, NY",
            "status": "active",
            "series_count": 12500,
            "logo_url": "https://...-full_lg.webp",
            "images": {
                "tile_sm": "https://...-tile_sm.webp",
                "profile_md": "https://...-profile_md.webp",
                "full_lg": "https://...-full_lg.webp"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 25,
        "per_page": 20,
        "total": 500
    }
}
 

Request      

GET api/v1/publishers

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by publisher name. Example: marvel

limit   integer  optional    

Number of results per page (max 50). Example: 20

Get publisher details

requires authentication

Returns: id, name, description, founded_year, first_published_year, website, headquarters, parent_company, status, logo_url, aliases

Use the related endpoints for relationship data:

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/publishers/59241" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/publishers/59241"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/publishers/59241'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/publishers/59241';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 1,
        "name": "Marvel Comics",
        "description": "American comic book publisher, home to Spider-Man, the X-Men, and the Avengers.",
        "founded_year": 1939,
        "website": "https://www.marvel.com",
        "headquarters": "New York, NY",
        "parent_company": "The Walt Disney Company",
        "status": "active",
        "logo_url": "https://r2.versedb.com/uploads/publishers/marvel-1/marvel-1-full_lg.webp",
        "images": {
            "tile_sm": "https://r2.versedb.com/uploads/publishers/marvel-1/marvel-1-tile_sm.webp",
            "profile_md": "https://r2.versedb.com/uploads/publishers/marvel-1/marvel-1-profile_md.webp",
            "full_lg": "https://r2.versedb.com/uploads/publishers/marvel-1/marvel-1-full_lg.webp"
        },
        "first_published_year": 1939,
        "aliases": [
            "Marvel",
            "Timely Comics",
            "Atlas Comics"
        ]
    }
}
 

Example response (404, Not Found):


{
    "message": "No query results for model [App\\Models\\Publisher]."
}
 

Request      

GET api/v1/publishers/{publisher_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

publisher_id   integer     

The ID of the publisher. Example: 59241

Imprints

Endpoints for browsing comic book imprints (publisher sub-brands, e.g., Vertigo under DC, Icon under Marvel).

List imprints

requires authentication

Returns: id, name, slug, description, publisher

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/imprints?q=vertigo&publisher_id=2&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/imprints"
);

const params = {
    "q": "vertigo",
    "publisher_id": "2",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/imprints'
params = {
  'q': 'vertigo',
  'publisher_id': '2',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/imprints';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'vertigo',
            'publisher_id' => '2',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 7,
            "name": "Vertigo",
            "slug": "vertigo",
            "description": "DC's mature readers imprint, home to Sandman, Preacher, and Y: The Last Man.",
            "publisher": {
                "id": 2,
                "name": "DC Comics",
                "slug": "dc-comics"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 3,
        "per_page": 20,
        "total": 45
    }
}
 

Request      

GET api/v1/imprints

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by imprint name. Example: vertigo

publisher_id   integer  optional    

Filter by publisher ID. Example: 2

limit   integer  optional    

Number of results per page (max 50). Example: 20

Get imprint details

requires authentication

Returns: id, name, slug, description, publisher, series_count, titles_count

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/imprints/6" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/imprints/6"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/imprints/6'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/imprints/6';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 7,
        "name": "Vertigo",
        "slug": "vertigo",
        "description": "DC's mature readers imprint, home to Sandman, Preacher, and Y: The Last Man.",
        "publisher": {
            "id": 2,
            "name": "DC Comics",
            "slug": "dc-comics"
        },
        "series_count": 312,
        "titles_count": 145,
        "created_at": "2024-01-15T12:00:00.000000Z",
        "updated_at": "2024-06-01T08:30:00.000000Z"
    }
}
 

Request      

GET api/v1/imprints/{imprint_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

imprint_id   integer     

The ID of the imprint. Example: 6

Creators

Endpoints for browsing and searching comic book creators.

Creators include writers, artists, colorists, letterers, editors, and other roles.

List creators.

requires authentication

Returns paginated creators with optional search and sorting.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/creators?q=alan+moore&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/creators"
);

const params = {
    "q": "alan moore",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/creators'
params = {
  'q': 'alan moore',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/creators';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'alan moore',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 789,
            "name": "Alan Moore",
            "slug": "alan-moore",
            "role": {
                "id": 1,
                "name": "Writer"
            },
            "photo_url": "https://...-full_lg.webp",
            "images": {
                "tile_sm": "https://...-tile_sm.webp",
                "profile_md": "https://...-profile_md.webp",
                "full_lg": "https://...-full_lg.webp"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 100,
        "per_page": 20,
        "total": 2000
    }
}
 

Request      

GET api/v1/creators

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by creator name. Example: alan moore

limit   integer  optional    

Results per page (max 50). Example: 20

Get creator details.

requires authentication

Returns a single creator with full details including biography, role, and awards.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/creators/789" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/creators/789"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/creators/789'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/creators/789';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 789,
        "name": "Alan Moore",
        "slug": "alan-moore",
        "role": {
            "id": 1,
            "name": "Writer"
        },
        "photo_url": "https://...-full_lg.webp",
        "images": {
            "tile_sm": "https://...-tile_sm.webp",
            "profile_md": "https://...-profile_md.webp",
            "full_lg": "https://...-full_lg.webp"
        },
        "biography": "Alan Moore is a British comic book writer...",
        "gender": "male",
        "birth": "1953-11-18",
        "death": null,
        "birth_place": "Northampton, England",
        "country": "United Kingdom",
        "aliases": [],
        "links": {
            "website": "...",
            "twitter": "..."
        },
        "awards": [
            {
                "name": "Eisner Award",
                "year": 1988
            }
        ]
    }
}
 

Example response (404, Not Found):


{
    "message": "Not Found"
}
 

Request      

GET api/v1/creators/{creator_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

creator_id   integer     

The creator ID. Example: 789

Get creator's blog posts.

requires authentication

Returns paginated published blog posts where this creator is featured.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/creators/789/blog-posts?limit=10" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/creators/789/blog-posts"
);

const params = {
    "limit": "10",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/creators/789/blog-posts'
params = {
  'limit': '10',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/creators/789/blog-posts';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'limit' => '10',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 12,
            "slug": "spotlight-alan-moore",
            "title": "Creator Spotlight: Alan Moore",
            "featured_image_url": "https://...",
            "category": {
                "id": 2,
                "name": "Spotlights",
                "slug": "spotlights"
            },
            "author": {
                "id": 1,
                "name": "VerseDB Editorial"
            },
            "published_at": "2026-04-15T12:00:00+00:00",
            "reading_time": 6
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 10,
        "total": 3
    }
}
 

Request      

GET api/v1/creators/{creator_id}/blog-posts

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

creator_id   integer     

The creator ID. Example: 789

Query Parameters

limit   integer  optional    

Results per page (max 50). Example: 10

Get creator's issues.

requires authentication

Returns paginated issues where the creator has a credit.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/creators/789/issues?limit=20&q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/creators/789/issues"
);

const params = {
    "limit": "20",
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/creators/789/issues'
params = {
  'limit': '20',
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/creators/789/issues';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'limit' => '20',
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 123,
            "slug": "batman-1",
            "series_id": 456,
            "issue_number": "1",
            "name": "Batman #1",
            "release_date": "2023-01-15",
            "cover_url": "https://...",
            "series": {
                "id": 456,
                "name": "Batman",
                "slug": "batman"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 10,
        "per_page": 20,
        "total": 200
    }
}
 

Request      

GET api/v1/creators/{creator_id}/issues

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

creator_id   integer     

The creator ID. Example: 789

Query Parameters

limit   integer  optional    

Results per page (max 50). Example: 20

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Get creator's series.

requires authentication

Returns paginated series where the creator has worked.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/creators/789/series?limit=20&q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/creators/789/series"
);

const params = {
    "limit": "20",
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/creators/789/series'
params = {
  'limit': '20',
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/creators/789/series';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'limit' => '20',
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 456,
            "name": "Batman",
            "slug": "batman",
            "start_year": 2016,
            "end_year": 2020,
            "cover_url": "https://...",
            "cached_issues_count": 85
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 5,
        "per_page": 20,
        "total": 100
    }
}
 

Request      

GET api/v1/creators/{creator_id}/series

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

creator_id   integer     

The creator ID. Example: 789

Query Parameters

limit   integer  optional    

Results per page (max 50). Example: 20

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Characters

Endpoints for browsing and searching comic book characters.

Characters include heroes, villains, and supporting characters across all publishers.

List characters.

requires authentication

Returns paginated characters with optional search and sorting.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/characters?q=spider-man&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/characters"
);

const params = {
    "q": "spider-man",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/characters'
params = {
  'q': 'spider-man',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/characters';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'spider-man',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 456,
            "name": "Spider-Man (Peter Parker)",
            "slug": "spider-man-peter-parker",
            "real_name": "Peter Parker",
            "aliases": [
                "Spidey",
                "Web-Head"
            ],
            "image_url": "https://...-full_lg.webp",
            "images": {
                "tile_sm": "https://...-tile_sm.webp",
                "profile_md": "https://...-profile_md.webp",
                "full_lg": "https://...-full_lg.webp"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 50,
        "per_page": 20,
        "total": 1000
    }
}
 

Request      

GET api/v1/characters

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by character name. Example: spider-man

limit   integer  optional    

Results per page (max 50). Example: 20

Get character details.

requires authentication

Returns a single character with full details including publishers and cached relationship counts (appearances, series, teams, story arcs) so clients can decide which related-entity tabs to expose.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/characters/456" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/characters/456"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/characters/456'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/characters/456';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 456,
        "name": "Spider-Man (Peter Parker)",
        "slug": "spider-man-peter-parker",
        "real_name": "Peter Parker",
        "aliases": [
            "Spidey",
            "Web-Head",
            "Webslinger"
        ],
        "image_url": "https://...-full_lg.webp",
        "images": {
            "tile_sm": "https://...-tile_sm.webp",
            "profile_md": "https://...-profile_md.webp",
            "full_lg": "https://...-full_lg.webp"
        },
        "description": "Peter Parker was bitten by a radioactive spider...",
        "alter_ego": [],
        "gender": "male",
        "race": "Human",
        "birth_place": "Queens, New York",
        "occupation": "Photographer, Scientist",
        "appearances_count": 12500,
        "series_count": 320,
        "teams_count": 8,
        "story_arcs_count": 47,
        "powers": [
            "Super strength",
            "Wall-crawling",
            "Spider-sense"
        ],
        "publisher": {
            "id": 1,
            "name": "Marvel",
            "slug": "marvel"
        }
    }
}
 

Example response (404, Not Found):


{
    "message": "Not Found"
}
 

Request      

GET api/v1/characters/{character_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

character_id   integer     

The character ID. Example: 456

Get character series.

requires authentication

Returns paginated series where the character appears.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/characters/456/series?limit=20&q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/characters/456/series"
);

const params = {
    "limit": "20",
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/characters/456/series'
params = {
  'limit': '20',
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/characters/456/series';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'limit' => '20',
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 123,
            "name": "Amazing Spider-Man",
            "slug": "amazing-spider-man-2018",
            "start_year": 2018,
            "end_year": 2022,
            "image_url": "https://..."
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 5,
        "per_page": 20,
        "total": 100
    }
}
 

Request      

GET api/v1/characters/{character_id}/series

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

character_id   integer     

The character ID. Example: 456

Query Parameters

limit   integer  optional    

Results per page (max 50). Example: 20

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Get character issues.

requires authentication

Returns paginated issues where the character appears, ordered by release date.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/characters/456/issues?limit=20&q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/characters/456/issues"
);

const params = {
    "limit": "20",
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/characters/456/issues'
params = {
  'limit': '20',
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/characters/456/issues';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'limit' => '20',
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 5432,
            "number": "1",
            "name": "The Amazing Spider-Man #1",
            "release_date": "2018-07-11",
            "cover_url": "https://...",
            "series": {
                "id": 123,
                "name": "Amazing Spider-Man"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 100,
        "per_page": 20,
        "total": 2000
    }
}
 

Request      

GET api/v1/characters/{character_id}/issues

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

character_id   integer     

The character ID. Example: 456

Query Parameters

limit   integer  optional    

Results per page (max 50). Example: 20

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Get character teams.

requires authentication

Returns paginated teams the character is a member of, including membership details.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/characters/456/teams?limit=20&q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/characters/456/teams"
);

const params = {
    "limit": "20",
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/characters/456/teams'
params = {
  'limit': '20',
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/characters/456/teams';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'limit' => '20',
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 10,
            "name": "Avengers",
            "slug": "avengers",
            "image_url": "https://...",
            "membership": {
                "role": "Member",
                "joined_date": "2012-05-01",
                "left_date": null
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 20,
        "total": 5
    }
}
 

Request      

GET api/v1/characters/{character_id}/teams

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

character_id   integer     

The character ID. Example: 456

Query Parameters

limit   integer  optional    

Results per page (max 50). Example: 20

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Teams

Endpoints for browsing superhero teams and their members.

List all teams with optional search

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/teams?q=avengers&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/teams"
);

const params = {
    "q": "avengers",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/teams'
params = {
  'q': 'avengers',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/teams';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'avengers',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 12,
            "name": "Avengers",
            "slug": "avengers",
            "aliases": [
                "Earth's Mightiest Heroes"
            ],
            "headquarters": "Avengers Tower, New York City",
            "members_count": 42,
            "appearances_count": 1250,
            "image_url": "https://images.versedb.com/teams/avengers/tile_sm.webp",
            "images": {
                "tile_sm": "https://images.versedb.com/teams/avengers/tile_sm.webp",
                "profile_md": "https://images.versedb.com/teams/avengers/profile_md.webp",
                "full_lg": "https://images.versedb.com/teams/avengers/full_lg.webp"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 8,
        "per_page": 20,
        "total": 156
    }
}
 

Request      

GET api/v1/teams

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by team name. Example: avengers

limit   integer  optional    

Number of results per page (max 50). Example: 20

Get a specific team

requires authentication

Returns team details without relationship data. Use the relationship endpoints for related data:

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/teams/20281" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/teams/20281"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/teams/20281'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/teams/20281';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 78,
        "name": "Avengers",
        "slug": "avengers",
        "aliases": [
            "Earth's Mightiest Heroes"
        ],
        "description": "A team of superheroes formed to confront threats no single hero could withstand.",
        "formation_date": "1963-09-01",
        "disbanded_date": null,
        "headquarters": "Avengers Tower, New York",
        "members_count": 312,
        "series_count": 48,
        "appearances_count": 5200,
        "lists_count": 86,
        "image_url": "https://r2.versedb.com/uploads/teams/avengers-78/avengers-78-full_lg.webp",
        "images": {
            "tile_sm": "https://r2.versedb.com/uploads/teams/avengers-78/avengers-78-tile_sm.webp",
            "profile_md": "https://r2.versedb.com/uploads/teams/avengers-78/avengers-78-profile_md.webp",
            "full_lg": "https://r2.versedb.com/uploads/teams/avengers-78/avengers-78-full_lg.webp"
        }
    }
}
 

Example response (404, Not Found):


{
    "message": "No query results for model [App\\Models\\Team]."
}
 

Request      

GET api/v1/teams/{team_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

team_id   integer     

The ID of the team. Example: 20281

Get characters for a specific team (members)

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/teams/20281/characters?q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/teams/20281/characters"
);

const params = {
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/teams/20281/characters'
params = {
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/teams/20281/characters';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 456,
            "name": "Captain America",
            "slug": "captain-america",
            "real_name": "Steve Rogers",
            "aliases": [
                "Cap",
                "Sentinel of Liberty"
            ],
            "race": "Human",
            "image_url": "https://images.versedb.com/characters/captain-america/full_lg.webp",
            "images": {
                "tile_sm": "https://images.versedb.com/characters/captain-america/tile_sm.webp",
                "profile_md": "https://images.versedb.com/characters/captain-america/profile_md.webp",
                "full_lg": "https://images.versedb.com/characters/captain-america/full_lg.webp"
            },
            "appearances_count": 980,
            "publisher_name": "Marvel Comics",
            "pivot_role": "Leader",
            "pivot_joined_date": "1963-09-01"
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 2,
        "per_page": 50,
        "total": 67
    }
}
 

Request      

GET api/v1/teams/{team_id}/characters

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

team_id   integer     

The ID of the team. Example: 20281

Query Parameters

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Get series for a specific team

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/teams/20281/series?q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/teams/20281/series"
);

const params = {
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/teams/20281/series'
params = {
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/teams/20281/series';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 123,
            "title_id": 45,
            "name": "Avengers",
            "slug": "avengers-2018",
            "start_year": 2018,
            "end_year": 2023,
            "medium": "comic",
            "publication_type": "regular_series",
            "status": "ended",
            "average_rating": 4.1,
            "total_reviews": 150,
            "is_nsfw": false
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 50,
        "total": 12
    }
}
 

Request      

GET api/v1/teams/{team_id}/series

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

team_id   integer     

The ID of the team. Example: 20281

Query Parameters

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Get issues for a specific team

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/teams/20281/issues?q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/teams/20281/issues"
);

const params = {
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/teams/20281/issues'
params = {
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/teams/20281/issues';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 5432,
            "series_id": 123,
            "issue_number": "1",
            "name": "The Final Host",
            "release_date": "2018-05-02",
            "cover_date": "2018-07-01",
            "average_rating": 4.3,
            "is_nsfw": false
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 25,
        "per_page": 50,
        "total": 1250
    }
}
 

Request      

GET api/v1/teams/{team_id}/issues

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

team_id   integer     

The ID of the team. Example: 20281

Query Parameters

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Story Arcs

Endpoints for browsing story arcs and crossover events.

List all story arcs with optional search

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/story-arcs?q=civil+war&status=ended&type=crossover_event&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/story-arcs"
);

const params = {
    "q": "civil war",
    "status": "ended",
    "type": "crossover_event",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/story-arcs'
params = {
  'q': 'civil war',
  'status': 'ended',
  'type': 'crossover_event',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/story-arcs';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'civil war',
            'status' => 'ended',
            'type' => 'crossover_event',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 16,
            "name": "Civil War",
            "slug": "civil-war",
            "type": "crossover_event",
            "status": "ended",
            "image_url": "https://cdn.versedb.com/story_arcs/civil-war-md.jpg",
            "images": {
                "cover_sm": "https://cdn.versedb.com/story_arcs/civil-war-sm.jpg",
                "cover_md": "https://cdn.versedb.com/story_arcs/civil-war-md.jpg",
                "cover_lg": "https://cdn.versedb.com/story_arcs/civil-war-lg.jpg"
            },
            "issues_count": 102,
            "primary_universe": {
                "id": 1,
                "name": "Earth-616"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 12,
        "per_page": 20,
        "total": 230
    }
}
 

Request      

GET api/v1/story-arcs

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by story arc name. Example: civil war

status   string  optional    

Filter by status. Example: ended

type   string  optional    

Filter by type. Example: crossover_event

limit   integer  optional    

Number of results per page (max 50). Example: 20

Get story arc detail.

requires authentication

Returns full story arc detail with the primary and secondary universes, a denormalized characters count, the start/end issue summaries (each with its parent series), and the last user who edited the arc.

Paginated relationship data lives on dedicated nested endpoints:

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/story-arcs/16" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/story-arcs/16"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/story-arcs/16'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/story-arcs/16';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 16,
        "name": "Civil War",
        "slug": "civil-war",
        "description": "A superhero registration act divides the Marvel Universe...",
        "type": "crossover_event",
        "status": "ended",
        "image_url": "https://cdn.versedb.com/story_arcs/civil-war-md.jpg",
        "images": {
            "cover_sm": "https://cdn.versedb.com/story_arcs/civil-war-sm.jpg",
            "cover_md": "https://cdn.versedb.com/story_arcs/civil-war-md.jpg",
            "cover_lg": "https://cdn.versedb.com/story_arcs/civil-war-lg.jpg"
        },
        "primary_universe_id": 1,
        "issues_count": 102,
        "characters_count": 87,
        "primary_universe": {
            "id": 1,
            "name": "Earth-616",
            "description": "The primary continuity of the Marvel Universe."
        },
        "universes": [
            {
                "id": 12,
                "name": "Ultimate Universe"
            }
        ],
        "start_issue": {
            "id": 5432,
            "name": "Civil War #1",
            "slug": "civil-war-1",
            "issue_number": "1",
            "series_id": 412,
            "cover_url": "https://cdn.versedb.com/issues/civil-war-1-md.jpg",
            "images": {
                "cover_md": "https://cdn.versedb.com/issues/civil-war-1-md.jpg"
            },
            "series": {
                "id": 412,
                "name": "Civil War",
                "slug": "civil-war-2006",
                "start_year": 2006
            }
        },
        "end_issue": {
            "id": 5439,
            "name": "Civil War #7",
            "slug": "civil-war-7",
            "issue_number": "7",
            "series_id": 412,
            "cover_url": "https://cdn.versedb.com/issues/civil-war-7-md.jpg",
            "images": {
                "cover_md": "https://cdn.versedb.com/issues/civil-war-7-md.jpg"
            },
            "series": {
                "id": 412,
                "name": "Civil War",
                "slug": "civil-war-2006",
                "start_year": 2006
            }
        },
        "last_edited_by": {
            "id": 42,
            "name": "Jane Doe",
            "username": "janedoe",
            "avatar_url": "https://cdn.versedb.com/users/janedoe-md.jpg"
        }
    }
}
 

Request      

GET api/v1/story-arcs/{storyArc_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

storyArc_id   integer     

The story arc ID. Example: 16

Get story arcs for a specific issue

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/issues/1087905/story-arcs?q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/issues/1087905/story-arcs"
);

const params = {
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/1087905/story-arcs'
params = {
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/1087905/story-arcs';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 24,
            "name": "The Night Gwen Stacy Died",
            "slug": "the-night-gwen-stacy-died",
            "type": "main_story",
            "status": "ended",
            "image_url": "https://cdn.versedb.com/story_arcs/the-night-gwen-stacy-died-md.jpg",
            "images": {
                "cover_sm": "https://cdn.versedb.com/story_arcs/the-night-gwen-stacy-died-sm.jpg",
                "cover_md": "https://cdn.versedb.com/story_arcs/the-night-gwen-stacy-died-md.jpg",
                "cover_lg": "https://cdn.versedb.com/story_arcs/the-night-gwen-stacy-died-lg.jpg"
            },
            "issues_count": 2
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 15,
        "total": 1
    }
}
 

Request      

GET api/v1/issues/{issue_id}/story-arcs

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The ID of the issue. Example: 1087905

Query Parameters

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Get story arcs for a specific character

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/characters/54014/story-arcs?q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/characters/54014/story-arcs"
);

const params = {
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/characters/54014/story-arcs'
params = {
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/characters/54014/story-arcs';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 16,
            "name": "Civil War",
            "slug": "civil-war",
            "type": "crossover_event",
            "status": "ended",
            "image_url": "https://cdn.versedb.com/story_arcs/civil-war-md.jpg",
            "images": {
                "cover_sm": "https://cdn.versedb.com/story_arcs/civil-war-sm.jpg",
                "cover_md": "https://cdn.versedb.com/story_arcs/civil-war-md.jpg",
                "cover_lg": "https://cdn.versedb.com/story_arcs/civil-war-lg.jpg"
            },
            "issues_count": 102
        },
        {
            "id": 24,
            "name": "The Night Gwen Stacy Died",
            "slug": "the-night-gwen-stacy-died",
            "type": "main_story",
            "status": "ended",
            "image_url": "https://cdn.versedb.com/story_arcs/the-night-gwen-stacy-died-md.jpg",
            "images": {
                "cover_sm": "https://cdn.versedb.com/story_arcs/the-night-gwen-stacy-died-sm.jpg",
                "cover_md": "https://cdn.versedb.com/story_arcs/the-night-gwen-stacy-died-md.jpg",
                "cover_lg": "https://cdn.versedb.com/story_arcs/the-night-gwen-stacy-died-lg.jpg"
            },
            "issues_count": 2
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 3,
        "per_page": 15,
        "total": 41
    }
}
 

Request      

GET api/v1/characters/{character_id}/story-arcs

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

character_id   integer     

The ID of the character. Example: 54014

Query Parameters

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Get story arcs for a specific universe

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/universes/16/story-arcs?q=batman" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/universes/16/story-arcs"
);

const params = {
    "q": "batman",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/universes/16/story-arcs'
params = {
  'q': 'batman',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/universes/16/story-arcs';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'batman',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 88,
            "name": "Crisis on Infinite Earths",
            "slug": "crisis-on-infinite-earths",
            "type": "crossover_event",
            "status": "ended",
            "image_url": "https://cdn.versedb.com/story_arcs/crisis-on-infinite-earths-md.jpg",
            "images": {
                "cover_sm": "https://cdn.versedb.com/story_arcs/crisis-on-infinite-earths-sm.jpg",
                "cover_md": "https://cdn.versedb.com/story_arcs/crisis-on-infinite-earths-md.jpg",
                "cover_lg": "https://cdn.versedb.com/story_arcs/crisis-on-infinite-earths-lg.jpg"
            },
            "issues_count": 12
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 4,
        "per_page": 15,
        "total": 56
    }
}
 

Request      

GET api/v1/universes/{universe_id}/story-arcs

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

universe_id   integer     

The ID of the universe. Example: 16

Query Parameters

q   string  optional    

Optional case-insensitive search within these results. Example: batman

Universes

Endpoints for browsing comic book universes (e.g., Marvel Universe, DC New 52).

List universes

requires authentication

Returns: id, name

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/universes?q=marvel&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/universes"
);

const params = {
    "q": "marvel",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/universes'
params = {
  'q': 'marvel',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/universes';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'marvel',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 1,
            "name": "Marvel Universe (616)"
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 3,
        "per_page": 20,
        "total": 42
    }
}
 

Request      

GET api/v1/universes

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by universe name. Example: marvel

limit   integer  optional    

Number of results per page (max 50). Example: 20

Get a specific universe

requires authentication

Returns: id, name, description

Use the relationship endpoints for related data:

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/universes/16" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/universes/16"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/universes/16'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/universes/16';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 1,
        "name": "Marvel Universe (616)",
        "description": "The primary continuity of Marvel Comics, home to most mainline Marvel stories since 1961."
    }
}
 

Request      

GET api/v1/universes/{universe_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

universe_id   integer     

The ID of the universe. Example: 16

Events

Endpoints for browsing comic conventions and store events.

List events.

requires authentication

Returns: id, slug, name, type, dates, location info, logo_url

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/events?q=comic-con&type=convention&upcoming=1&past=1&is_online=&is_fcbd=1&country_code=US&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/events"
);

const params = {
    "q": "comic-con",
    "type": "convention",
    "upcoming": "1",
    "past": "1",
    "is_online": "0",
    "is_fcbd": "1",
    "country_code": "US",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/events'
params = {
  'q': 'comic-con',
  'type': 'convention',
  'upcoming': '1',
  'past': '1',
  'is_online': '0',
  'is_fcbd': '1',
  'country_code': 'US',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/events';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'comic-con',
            'type' => 'convention',
            'upcoming' => '1',
            'past' => '1',
            'is_online' => '0',
            'is_fcbd' => '1',
            'country_code' => 'US',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 42,
            "slug": "san-diego-comic-con-2026",
            "name": "San Diego Comic-Con 2026",
            "type": "convention",
            "start_date": "2026-07-23",
            "end_date": "2026-07-26",
            "is_online": false,
            "is_fcbd": false,
            "venue_name": "San Diego Convention Center",
            "city": "San Diego",
            "region": "CA",
            "country_code": "US",
            "full_location": "San Diego Convention Center, San Diego, CA, United States",
            "logo_url": "https://...-tile_sm.webp",
            "images": {
                "tile_sm": "https://...-tile_sm.webp",
                "full_md": "https://...-full_md.webp",
                "full_lg": "https://...-full_lg.webp"
            },
            "ticket_price": "$45.00 - $150.00",
            "follower_count": 320
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 8,
        "per_page": 20,
        "total": 156
    }
}
 

Request      

GET api/v1/events

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by event name. Example: comic-con

type   string  optional    

Filter by type (convention, store_event, signing, etc). Example: convention

upcoming   boolean  optional    

Only show upcoming events. Example: true

past   boolean  optional    

Only show past events. Example: true

is_online   boolean  optional    

Filter online/in-person events. Example: false

is_fcbd   boolean  optional    

Filter Free Comic Book Day events. Example: true

country_code   string  optional    

Filter by country code. Example: US

limit   integer  optional    

Number of results per page (max 50). Example: 20

Get an event.

requires authentication

Returns full event details including links and map data.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/events/406" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/events/406"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/events/406'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/events/406';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 42,
        "slug": "san-diego-comic-con-2026",
        "name": "San Diego Comic-Con 2026",
        "type": "convention",
        "start_date": "2026-07-23",
        "end_date": "2026-07-26",
        "timezone": "America/Los_Angeles",
        "is_online": false,
        "is_fcbd": false,
        "venue_name": "San Diego Convention Center",
        "street_address": "111 W Harbor Dr",
        "city": "San Diego",
        "region": "CA",
        "postal_code": "92101",
        "country_code": "US",
        "latitude": 32.7065,
        "longitude": -117.1615,
        "full_location": "San Diego Convention Center, San Diego, CA, United States",
        "google_maps_url": "https://maps.google.com/?q=32.7065,-117.1615",
        "logo_url": "https://cdn.versedb.com/events/42-full_lg.webp",
        "images": {
            "tile_sm": "https://cdn.versedb.com/events/42-tile_sm.webp",
            "full_md": "https://cdn.versedb.com/events/42-full_md.webp",
            "full_lg": "https://cdn.versedb.com/events/42-full_lg.webp"
        },
        "static_map_url": "https://cdn.versedb.com/events/42-static-map.png",
        "event_url": "https://www.comic-con.org",
        "ticket_price_min": "45.00",
        "ticket_price_max": "150.00",
        "ticket_currency": "USD",
        "ticket_price": "$45.00 - $150.00",
        "follower_count": 320,
        "creators": [
            {
                "id": 7,
                "name": "Stan Lee",
                "slug": "stan-lee",
                "photo_url": "https://cdn.versedb.com/creators/7-profile_md.webp",
                "images": {},
                "country": "US",
                "appearance_types": [
                    "Special Guest"
                ]
            }
        ],
        "issues": [],
        "issue_variants": [],
        "attendees_preview": {
            "total": 320,
            "users": [
                {
                    "id": 1024,
                    "username": "comic_fan_42",
                    "name": "Comic Fan",
                    "profile_image_url": "https://cdn.versedb.com/users/1024-profile_sm.webp",
                    "is_private": false
                },
                {
                    "id": 1536,
                    "username": "panel_pusher",
                    "name": "Riley",
                    "profile_image_url": "https://cdn.versedb.com/users/1536-profile_sm.webp",
                    "is_private": false
                }
            ]
        },
        "related_events": []
    }
}
 

Example response (404, Not Found or Archived):


{
    "message": "Not found."
}
 

Request      

GET api/v1/events/{event_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

event_id   integer     

The ID of the event. Example: 406

event   integer     

The event ID. Example: 42

Key Issue Reasons

Endpoints for browsing key issue reasons (e.g., "1st Appearance", "Death", "Origin"). These are reusable labels that can be attached to issues to indicate significance.

List key issue reasons.

requires authentication

Returns all active key issue reasons, optionally filtered by category. Useful for client-side pickers and filters.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/key-issue-reasons?category=appearance" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/key-issue-reasons"
);

const params = {
    "category": "appearance",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/key-issue-reasons'
params = {
  'category': 'appearance',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/key-issue-reasons';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'category' => 'appearance',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 1,
            "name": "1st Appearance",
            "category": "appearance",
            "description": "First appearance of a character"
        }
    ]
}
 

Request      

GET api/v1/key-issue-reasons

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

category   string  optional    

Filter by category (appearance, story, creator, market, media). Example: appearance

Comic Shops

Endpoints for finding and browsing comic book shops.

List comic shops.

requires authentication

Returns paginated shops with optional location-based and text filtering.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/shops?country=US&state=NY&q=manhattan&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/shops"
);

const params = {
    "country": "US",
    "state": "NY",
    "q": "manhattan",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/shops'
params = {
  'country': 'US',
  'state': 'NY',
  'q': 'manhattan',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/shops';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'country' => 'US',
            'state' => 'NY',
            'q' => 'manhattan',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 42,
            "name": "Midtown Comics",
            "city": "New York",
            "state_province": "NY",
            "country": "United States",
            "logo_url": "https://r2.versedb.com/uploads/comic-shops/midtown-comics-42/midtown-comics-42-abc123-tile_sm.webp",
            "images": {
                "tile_sm": "https://r2.versedb.com/uploads/comic-shops/midtown-comics-42/midtown-comics-42-abc123-tile_sm.webp",
                "full_lg": "https://r2.versedb.com/uploads/comic-shops/midtown-comics-42/midtown-comics-42-abc123-full_lg.webp"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 8,
        "per_page": 20,
        "total": 150
    }
}
 

Request      

GET api/v1/shops

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

country   string  optional    

Filter by country — accepts ISO alpha-2 code or canonical country name. Example: US

state   string  optional    

Filter by state or province. Example: NY

q   string  optional    

Search by shop name or city. Example: manhattan

limit   integer  optional    

Number of results per page (max 50). Example: 20

Get a comic shop.

requires authentication

Returns full shop details including services offered.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/shops/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/shops/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/shops/1'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/shops/1';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 42,
        "name": "Midtown Comics",
        "description": "Flagship comic shop in the heart of Manhattan.",
        "address": "200 W 40th St",
        "city": "New York",
        "state_province": "NY",
        "postal_code": "10018",
        "country": "US",
        "website": "https://www.midtowncomics.com",
        "full_address": "200 W 40th St, New York, NY 10018",
        "logo_url": "https://r2.versedb.com/uploads/shops/midtown-42/midtown-42-full_lg.webp",
        "images": {
            "tile_sm": "https://r2.versedb.com/uploads/shops/midtown-42/midtown-42-tile_sm.webp",
            "full_lg": "https://r2.versedb.com/uploads/shops/midtown-42/midtown-42-full_lg.webp"
        },
        "operating_hours": {
            "monday": "10am - 8pm",
            "saturday": "10am - 9pm",
            "sunday": "11am - 6pm"
        },
        "services": [
            "New Comics",
            "Back Issues",
            "Pull Lists",
            "Grading"
        ],
        "events": []
    }
}
 

Example response (404, Not Found):


{
    "message": "No query results for model [App\\Models\\ComicShop]."
}
 

Request      

GET api/v1/shops/{shop_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

shop_id   integer     

The shop ID. Example: 1

Podcasts

Endpoints for browsing comic book podcasts and episodes.

List all podcasts with optional search

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/podcasts?q=comic&type=youtube&language=en&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/podcasts"
);

const params = {
    "q": "comic",
    "type": "youtube",
    "language": "en",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/podcasts'
params = {
  'q': 'comic',
  'type': 'youtube',
  'language': 'en',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/podcasts';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'comic',
            'type' => 'youtube',
            'language' => 'en',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 56,
            "name": "War Rocket Ajax",
            "slug": "war-rocket-ajax",
            "type": "podcast",
            "description": "A weekly comic book podcast covering new releases and creator interviews.",
            "language": "en",
            "logo_url": "https://r2.versedb.com/uploads/podcasts/wra-56/wra-56-full_lg.webp",
            "images": {
                "tile_sm": "https://r2.versedb.com/uploads/podcasts/wra-56/wra-56-tile_sm.webp",
                "full_lg": "https://r2.versedb.com/uploads/podcasts/wra-56/wra-56-full_lg.webp"
            },
            "follower_count": 1240,
            "subscriber_count": 8800,
            "categories": [
                "Comics",
                "Pop Culture"
            ]
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 15,
        "per_page": 20,
        "total": 300
    }
}
 

Request      

GET api/v1/podcasts

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by podcast name. Example: comic

type   string  optional    

Filter by type (podcast or youtube). Example: youtube

language   string  optional    

Filter by language code (e.g., en, ja, fr). Example: en

limit   integer  optional    

Number of results per page (max 50). Example: 20

Get a specific podcast.

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/podcasts/238" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/podcasts/238"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/podcasts/238'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/podcasts/238';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 56,
        "name": "War Rocket Ajax",
        "slug": "war-rocket-ajax",
        "type": "podcast",
        "description": "A weekly comic book podcast covering new releases, industry news, and creator interviews.",
        "language": "en",
        "logo_url": "https://r2.versedb.com/uploads/podcasts/wra-56/wra-56-full_lg.webp",
        "images": {
            "tile_sm": "https://r2.versedb.com/uploads/podcasts/wra-56/wra-56-tile_sm.webp",
            "full_lg": "https://r2.versedb.com/uploads/podcasts/wra-56/wra-56-full_lg.webp"
        },
        "website_url": "https://warrocketajax.com",
        "rss_feed_url": "https://feeds.example.com/war-rocket-ajax",
        "youtube_channel_id": null,
        "social_links": {
            "website": "https://warrocketajax.com",
            "twitter": "https://twitter.com/warrocketajax"
        },
        "platform_links": {
            "apple": "https://podcasts.apple.com/us/podcast/id123456",
            "spotify": "https://open.spotify.com/show/abc123"
        },
        "follower_count": 1240,
        "subscriber_count": 8800,
        "categories": [
            "Comics",
            "Pop Culture"
        ]
    }
}
 

Example response (404, Not Found):


{
    "message": "No query results for model [App\\Models\\Podcast]."
}
 

Request      

GET api/v1/podcasts/{podcast_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

podcast_id   integer     

The ID of the podcast. Example: 238

Lists

User-generated and curated lists of comic content.

Lists allow users to organize and share collections of issues, series, characters, creators, teams, or story arcs. Users can save and like lists, and lists can be ranked or unranked.

Entity Types: issues, series, characters, creators, story_arcs, teams

List Types:

Browse lists.

requires authentication

Returns paginated public lists with filtering and sorting options. Only shows lists with at least one item.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/lists?q=spider-man&entity_type=issues&sort=popular&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lists"
);

const params = {
    "q": "spider-man",
    "entity_type": "issues",
    "sort": "popular",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists'
params = {
  'q': 'spider-man',
  'entity_type': 'issues',
  'sort': 'popular',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'spider-man',
            'entity_type' => 'issues',
            'sort' => 'popular',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 101,
            "title": "Best Spider-Man Stories",
            "entity_type": "issues",
            "is_ranked": true,
            "items_count": 25,
            "likes_count": 150,
            "saves_count": 89,
            "user": {
                "id": 123,
                "username": "comic_fan",
                "avatar": "https://..."
            },
            "preview_items": [
                {
                    "id": 1,
                    "image_url": "https://...",
                    "is_nsfw": false
                }
            ]
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 5,
        "per_page": 20,
        "total": 100
    }
}
 

Request      

GET api/v1/lists

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string  optional    

Search by list title. Example: spider-man

entity_type   string  optional    

Filter by entity type (issues, series, characters, creators, story_arcs, teams). Example: issues

sort   string  optional    

Sort order (featured, newest, popular, most_saved). Default: featured. Example: popular

limit   integer  optional    

Items per page (max 100). Example: 20

Browse system lists.

requires authentication

Returns platform-curated lists (no user owner). These are editorial picks and featured content.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/lists/system?entity_type=issues&sort=popular&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lists/system"
);

const params = {
    "entity_type": "issues",
    "sort": "popular",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/system'
params = {
  'entity_type': 'issues',
  'sort': 'popular',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/system';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'entity_type' => 'issues',
            'sort' => 'popular',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 1,
            "title": "Essential Batman Reading Order",
            "entity_type": "issues",
            "is_ranked": true,
            "items_count": 50,
            "likes_count": 500,
            "user": null,
            "preview_items": [
                {
                    "id": 1,
                    "image_url": "https://...",
                    "is_nsfw": false
                }
            ]
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 2,
        "per_page": 20,
        "total": 30
    }
}
 

Request      

GET api/v1/lists/system

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

entity_type   string  optional    

Filter by entity type (issues, series, characters, creators, story_arcs, teams). Example: issues

sort   string  optional    

Sort order (newest, popular). Example: popular

limit   integer  optional    

Items per page (max 100). Example: 20

Get list.

requires authentication

Returns a single list with all its items. Private lists are only visible to owners.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/lists/101" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lists/101"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 101,
        "title": "Best Spider-Man Stories",
        "description": "My favorite Spidey moments",
        "entity_type": "issues",
        "is_ranked": true,
        "is_private": false,
        "items_count": 25,
        "likes_count": 150,
        "saves_count": 89,
        "user": {
            "id": 123,
            "username": "comic_fan",
            "name": "John"
        },
        "items": [
            {
                "id": 1,
                "position": 1,
                "note": "Classic!",
                "listable": {
                    "id": 5432,
                    "number": "1"
                }
            }
        ],
        "created_at": "2024-01-15T10:30:00Z"
    }
}
 

Example response (403, Private List):


{
    "message": "This list is private."
}
 

Example response (404, Not Found):


{
    "message": "Not Found"
}
 

Request      

GET api/v1/lists/{list_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

Get user's lists.

requires authentication

Returns a user's public lists. If viewing your own profile, also includes private lists.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/users/123/lists?entity_type=issues&sort=newest&limit=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/users/123/lists"
);

const params = {
    "entity_type": "issues",
    "sort": "newest",
    "limit": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/users/123/lists'
params = {
  'entity_type': 'issues',
  'sort': 'newest',
  'limit': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/users/123/lists';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'entity_type' => 'issues',
            'sort' => 'newest',
            'limit' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 101,
            "title": "My Reading List",
            "entity_type": "issues",
            "items_count": 15,
            "is_private": false,
            "user": {
                "id": 123,
                "username": "comic_fan"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 20,
        "total": 5
    }
}
 

Request      

GET api/v1/users/{user_id}/lists

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

user_id   integer     

The user ID. Example: 123

Query Parameters

entity_type   string  optional    

Filter by entity type (issues, series, etc.). Example: issues

sort   string  optional    

Sort order (newest, popular, most_saved). Example: newest

limit   integer  optional    

Items per page (max 100). Example: 20

Create list.

requires authentication

Creates a new user list.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/lists" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"title\": \"Best Spider-Man Stories\",
    \"description\": \"My favorite Spidey moments ranked\",
    \"entity_type\": \"issues\",
    \"is_ranked\": true,
    \"is_private\": false
}"
const url = new URL(
    "https://versedb.com/api/v1/lists"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "title": "Best Spider-Man Stories",
    "description": "My favorite Spidey moments ranked",
    "entity_type": "issues",
    "is_ranked": true,
    "is_private": false
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists'
payload = {
    "title": "Best Spider-Man Stories",
    "description": "My favorite Spidey moments ranked",
    "entity_type": "issues",
    "is_ranked": true,
    "is_private": false
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'title' => 'Best Spider-Man Stories',
            'description' => 'My favorite Spidey moments ranked',
            'entity_type' => 'issues',
            'is_ranked' => true,
            'is_private' => false,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (201, Success):


{
    "data": {
        "id": 102,
        "title": "Best Spider-Man Stories",
        "description": "My favorite Spidey moments ranked",
        "entity_type": "issues",
        "is_ranked": true,
        "is_private": false,
        "items_count": 0,
        "user": {
            "id": 123,
            "username": "comic_fan"
        }
    }
}
 

Example response (403, Limit Reached):


{
    "message": "You have reached the maximum number of lists. Upgrade to PRO for more."
}
 

Request      

POST api/v1/lists

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

title   string     

List title (max 100 chars). Example: Best Spider-Man Stories

description   string  optional    

List description (max 500 chars). Example: My favorite Spidey moments ranked

entity_type   string     

Entity type (issues, series, characters, creators, story_arcs, teams). Example: issues

is_ranked   boolean  optional    

Whether items are ranked/ordered. Example: true

is_private   boolean  optional    

Whether the list is private. Example: false

Update list.

requires authentication

Updates a list's metadata. Wishlists can only update privacy settings.

Example request:
curl --request PUT \
    "https://versedb.com/api/v1/lists/101" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"title\": \"Updated Title\",
    \"description\": \"Updated description\",
    \"is_ranked\": false,
    \"is_private\": true,
    \"status\": \"published\"
}"
const url = new URL(
    "https://versedb.com/api/v1/lists/101"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "title": "Updated Title",
    "description": "Updated description",
    "is_ranked": false,
    "is_private": true,
    "status": "published"
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101'
payload = {
    "title": "Updated Title",
    "description": "Updated description",
    "is_ranked": false,
    "is_private": true,
    "status": "published"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('PUT', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101';
$response = $client->put(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'title' => 'Updated Title',
            'description' => 'Updated description',
            'is_ranked' => false,
            'is_private' => true,
            'status' => 'published',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 101,
        "title": "Updated Title",
        "description": "Updated description"
    }
}
 

Example response (403, Unauthorized):


{
    "message": "This action is unauthorized."
}
 

Request      

PUT api/v1/lists/{list_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

Body Parameters

title   string  optional    

List title (max 100 chars). Example: Updated Title

description   string  optional    

List description (max 500 chars). Example: Updated description

is_ranked   boolean  optional    

Whether items are ranked. Example: false

is_private   boolean  optional    

Whether the list is private. Example: true

status   string  optional    

The list status. One of: published, draft. Example: published

Must be one of:
  • published
  • draft

Convert a list to mixed.

requires authentication

One-way: broadens a single-type list so it can hold items of any type. Existing items keep their own type. A mixed list cannot be narrowed back, and wishlists cannot be converted.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/lists/101/convert-to-mixed" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lists/101/convert-to-mixed"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101/convert-to-mixed'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101/convert-to-mixed';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Converted):


{
    "data": {
        "id": 101,
        "entity_type": "mixed"
    }
}
 

Example response (403, Unauthorized):


{
    "message": "This action is unauthorized."
}
 

Example response (422, Not convertible):


{
    "message": "This list is already a mixed list."
}
 

Request      

POST api/v1/lists/{list_id}/convert-to-mixed

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

Merge a list into this one.

requires authentication

Pulls every item from the source list into this (destination) list — skipping items already present (by entity + variant) and appending the rest. Both lists must be owned by the authenticated user. Merging items of a different type converts this list to mixed.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/lists/101/merge" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"source_list_id\": 207,
    \"delete_source\": false
}"
const url = new URL(
    "https://versedb.com/api/v1/lists/101/merge"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "source_list_id": 207,
    "delete_source": false
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101/merge'
payload = {
    "source_list_id": 207,
    "delete_source": false
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101/merge';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'source_list_id' => 207,
            'delete_source' => false,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Merged):


{
    "data": {
        "id": 101,
        "title": "Best Batman Runs",
        "item_types": [
            "issues"
        ]
    },
    "merge": {
        "moved": 4,
        "skipped_duplicates": 1,
        "converted_to_mixed": false,
        "source_deleted": false
    }
}
 

Example response (403, Unauthorized):


{
    "message": "You can only merge into your own lists."
}
 

Example response (422, Invalid merge):


{
    "message": "The source list has no items to merge."
}
 

Request      

POST api/v1/lists/{list_id}/merge

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The destination list ID. Example: 101

Body Parameters

source_list_id   integer     

The list to merge in. Example: 207

delete_source   boolean  optional    

Delete the source list after merging. Defaults to false. Example: false

Delete list.

requires authentication

Permanently deletes a list and all its items. Wishlists cannot be deleted.

Example request:
curl --request DELETE \
    "https://versedb.com/api/v1/lists/101" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lists/101"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (204, Success):

Empty response
 

Example response (403, Wishlist):


{
    "message": "Wishlists cannot be deleted."
}
 

Example response (403, Unauthorized):


{
    "message": "You are not authorized to delete this list."
}
 

Request      

DELETE api/v1/lists/{list_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

Add item to list.

requires authentication

Adds an entity to a list. Free users: 100 items/list, PRO users: 500 items/list.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/lists/101/items" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"entity_id\": 5432,
    \"entity_type\": \"issues\",
    \"position\": 1,
    \"note\": \"My favorite issue!\"
}"
const url = new URL(
    "https://versedb.com/api/v1/lists/101/items"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "entity_id": 5432,
    "entity_type": "issues",
    "position": 1,
    "note": "My favorite issue!"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101/items'
payload = {
    "entity_id": 5432,
    "entity_type": "issues",
    "position": 1,
    "note": "My favorite issue!"
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101/items';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'entity_id' => 5432,
            'entity_type' => 'issues',
            'position' => 1,
            'note' => 'My favorite issue!',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (201, Added):


{
    "data": {
        "id": 501,
        "position": 1,
        "note": "My favorite issue!",
        "listable": {
            "id": 5432,
            "number": "1"
        }
    }
}
 

Example response (403, Item Limit):


{
    "message": "This list has reached its item limit. Upgrade to PRO for more."
}
 

Example response (409, Already Exists):


{
    "message": "This item is already in the list.",
    "item": {
        "id": 501,
        "position": 1
    }
}
 

Request      

POST api/v1/lists/{list_id}/items

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

Body Parameters

entity_id   integer     

The entity ID to add. Example: 5432

entity_type   string  optional    

Required only for mixed lists: the type of the entity being added (issues, series, characters, creators, story_arcs, teams). Ignored on single-type lists. Example: issues

position   integer  optional    

Position in list (auto-assigned if omitted). Example: 1

note   string  optional    

Personal note for this item (max 500 chars). Example: My favorite issue!

Remove item from list.

requires authentication

Removes an item from a list. Other items' positions are automatically adjusted.

Example request:
curl --request DELETE \
    "https://versedb.com/api/v1/lists/101/items/501" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lists/101/items/501"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101/items/501'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101/items/501';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (204, Success):

Empty response
 

Example response (403, Unauthorized):


{
    "message": "You are not authorized to remove items from this list."
}
 

Example response (404, Not Found):


{
    "message": "Item does not belong to this list."
}
 

Request      

DELETE api/v1/lists/{list_id}/items/{item_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

item_id   integer     

The list item ID. Example: 501

Reorder items.

requires authentication

Reorders items in a list by providing the new order of item IDs.

Example request:
curl --request PUT \
    "https://versedb.com/api/v1/lists/101/items/reorder" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"item_ids\": [
        503,
        501,
        502
    ]
}"
const url = new URL(
    "https://versedb.com/api/v1/lists/101/items/reorder"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "item_ids": [
        503,
        501,
        502
    ]
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101/items/reorder'
payload = {
    "item_ids": [
        503,
        501,
        502
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('PUT', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101/items/reorder';
$response = $client->put(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'item_ids' => [503, 501, 502],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "message": "Items reordered successfully.",
    "items": [
        {
            "id": 503,
            "position": 1,
            "note": null,
            "entity_type": "issues",
            "entity": {
                "id": 5432,
                "name": "The Amazing Spider-Man #1",
                "issue_number": "1",
                "image_url": "https://..."
            }
        },
        {
            "id": 501,
            "position": 2,
            "note": null,
            "entity_type": "issues",
            "entity": {
                "id": 5433,
                "name": "The Amazing Spider-Man #2",
                "issue_number": "2",
                "image_url": "https://..."
            }
        },
        {
            "id": 502,
            "position": 3,
            "note": null,
            "entity_type": "issues",
            "entity": {
                "id": 5434,
                "name": "The Amazing Spider-Man #3",
                "issue_number": "3",
                "image_url": "https://..."
            }
        }
    ]
}
 

Request      

PUT api/v1/lists/{list_id}/items/reorder

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

Body Parameters

item_ids   integer[]     

Array of item IDs in desired order.

Save list.

requires authentication

Saves a list to the user's saved lists for quick access. Cannot save your own lists.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/lists/101/save" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lists/101/save"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101/save'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101/save';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Already Saved):


{
    "message": "List is already saved.",
    "saved": true
}
 

Example response (201, Saved):


{
    "message": "List saved successfully.",
    "saved": true,
    "saves_count": 90
}
 

Example response (403, Own List):


{
    "message": "You cannot save your own list."
}
 

Request      

POST api/v1/lists/{list_id}/save

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

Unsave list.

requires authentication

Removes a list from the user's saved lists.

Example request:
curl --request DELETE \
    "https://versedb.com/api/v1/lists/101/save" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lists/101/save"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101/save'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101/save';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Unsaved):


{
    "message": "List unsaved successfully.",
    "saved": false,
    "saves_count": 89
}
 

Example response (200, Not Saved):


{
    "message": "List is not saved.",
    "saved": false
}
 

Request      

DELETE api/v1/lists/{list_id}/save

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

Like list.

requires authentication

Likes a list. Cannot like your own lists.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/lists/101/like" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lists/101/like"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101/like'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101/like';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Already Liked):


{
    "message": "List is already liked.",
    "liked": true
}
 

Example response (201, Liked):


{
    "message": "List liked successfully.",
    "liked": true,
    "likes_count": 151
}
 

Example response (403, Own List):


{
    "message": "You cannot like your own list."
}
 

Request      

POST api/v1/lists/{list_id}/like

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

Unlike list.

requires authentication

Removes the user's like from a list.

Example request:
curl --request DELETE \
    "https://versedb.com/api/v1/lists/101/like" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lists/101/like"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lists/101/like'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lists/101/like';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Unliked):


{
    "message": "List unliked successfully.",
    "liked": false,
    "likes_count": 150
}
 

Example response (200, Not Liked):


{
    "message": "List is not liked.",
    "liked": false
}
 

Request      

DELETE api/v1/lists/{list_id}/like

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

list_id   integer     

The list ID. Example: 101

Barcode Lookup

Endpoints for looking up comics by barcode (UPC or ISBN). Used by the mobile app's barcode scanning feature and exposed to User API tokens via the lookup:barcode ability.

Requires the mobile:lookup or lookup:barcode token ability.

Lookup by UPC.

requires authentication

Find an issue by its UPC barcode (typically 12-17 digits). Returns full issue details including series information.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/lookup/upc/75960608936700111" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lookup/upc/75960608936700111"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lookup/upc/75960608936700111'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lookup/upc/75960608936700111';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 5432,
        "slug": "amazing-spider-man-1",
        "series_id": 123,
        "title_id": 45,
        "issue_number": "1",
        "name": "The Amazing Spider-Man #1",
        "description": "Nick Spencer and Ryan Ottley begin a new era...",
        "release_date": "2018-07-11",
        "cover_date": "2018-09-01",
        "cover_url": "https://...",
        "upc": "75960608936700111",
        "series": {
            "id": 123,
            "name": "Amazing Spider-Man",
            "slug": "amazing-spider-man-2018",
            "start_year": 2018,
            "volume_number": 5
        },
        "publisher": {
            "id": 1,
            "name": "Marvel",
            "slug": "marvel"
        }
    },
    "suggested_variant_id": 789,
    "variants": [
        {
            "variant_id": null,
            "variant_name": "Cover A",
            "cover_url": "https://..."
        },
        {
            "variant_id": 789,
            "variant_name": "Cover B",
            "cover_url": "https://..."
        }
    ]
}
 

Example response (403, Missing Ability):


{
    "message": "Unauthorized"
}
 

Example response (404, Not Found):


{
    "message": "No issue found with UPC: 75960608936700111"
}
 

Example response (409, Multiple Matches):


{
    "message": "Multiple issues share UPC: 075960608936. Pick one below.",
    "count": 3,
    "matches": [
        {
            "issue_id": 5432,
            "series_name": "Amazing Spider-Man",
            "series_id": 123,
            "issue_number": "1",
            "cover_url": "https://...",
            "variant_name": null,
            "suggested_variant_id": null,
            "variants": [
                {
                    "variant_id": null,
                    "variant_name": "Cover A",
                    "cover_url": "https://..."
                }
            ],
            "publisher_name": "Marvel",
            "release_date": "1990-04-01",
            "start_year": 1963
        }
    ]
}
 

Request      

GET api/v1/lookup/upc/{upc}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

upc   string     

The UPC barcode. Example: 75960608936700111

Lookup by ISBN.

requires authentication

Find an issue by its ISBN (10 or 13 digits, with or without dashes). Commonly used for trade paperbacks and hardcovers. Returns full issue details including series information.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/lookup/isbn/978-1302913847" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/lookup/isbn/978-1302913847"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/lookup/isbn/978-1302913847'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/lookup/isbn/978-1302913847';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 8765,
        "slug": "spider-man-life-story-tp",
        "series_id": 456,
        "title_id": 45,
        "issue_number": "1",
        "name": "Spider-Man: Life Story TP",
        "description": "A story of Peter Parker...",
        "release_date": "2019-10-02",
        "isbn": "978-1302913847",
        "format": "trade_paperback",
        "series": {
            "id": 456,
            "name": "Spider-Man: Life Story",
            "slug": "spider-man-life-story"
        },
        "publisher": {
            "id": 1,
            "name": "Marvel",
            "slug": "marvel"
        }
    }
}
 

Example response (403, Missing Ability):


{
    "message": "Unauthorized"
}
 

Example response (404, Not Found):


{
    "message": "No issue found with ISBN: 978-1302913847"
}
 

Request      

GET api/v1/lookup/isbn/{isbn}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

isbn   string     

The ISBN (10 or 13 digits). Example: 978-1302913847

User

Endpoints for managing the authenticated user's pull list, follows, and reading progress.

All endpoints in this group require authentication via a mobile session token.

Get the authenticated user.

requires authentication

Returns the profile of the user the token belongs to.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/user" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/user"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/user'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/user';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200):

Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 300
x-ratelimit-remaining: 299
access-control-allow-origin: *
 

{
    "data": {
        "id": 14,
        "name": "Scribe Test User",
        "username": "scribe-test-user",
        "email": "[email protected]",
        "bio": null,
        "avatar": null,
        "profile_image": null,
        "profile_image_url": null,
        "glow_color": "#FF5722",
        "banner_path": null,
        "banner_url": null,
        "country_code": null,
        "city": null,
        "region": null,
        "postal_code": null,
        "formatted_location": null,
        "is_private": false,
        "is_wishlist_public": false,
        "public_wishlist_id": null,
        "email_notifications": true,
        "content_edit_notifications": true,
        "comment_reply_notifications": true,
        "push_notifications_enabled": true,
        "inapp_notifications_enabled": true,
        "show_nsfw_warnings": true,
        "birth_date": null,
        "can_view_nsfw": false,
        "show_reading_list": true,
        "show_collection": true,
        "show_activity": true,
        "show_spoilers": false,
        "preferred_mediums": [
            "comic"
        ],
        "preferred_genres": [],
        "preferred_languages": [
            "en"
        ],
        "locale": null,
        "onboarding_completed_at": "2025-04-11T01:29:50.000000Z",
        "onboarding_step": 5,
        "ai_discovery_enabled": true,
        "is_pro": false,
        "level": 1,
        "xp": 0,
        "xp_for_next_level": 100,
        "xp_progress_percent": 0,
        "contributions_count": 0,
        "level_name": "Bystander",
        "created_at": "2025-04-11T01:29:50.000000Z",
        "updated_at": "2025-04-11T01:29:50.000000Z",
        "has_password": true,
        "deletion_requested_at": null,
        "deletion_confirmed_at": null,
        "deletion_scheduled_for": null
    }
}
 

Request      

GET api/v1/user

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Collections

List collection.

requires authentication

Returns all issues in the user's collection with series and publisher info.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/user/collections?per_page=20&page=1&search=spider&format=single&graded=1&is_signed=1&condition=NM&for_sale=1&for_trade=1&read_status=unread&publisher_id=1&grade_min=9&grade_max=9.8&sort_by=title&sort_order=asc" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/user/collections"
);

const params = {
    "per_page": "20",
    "page": "1",
    "search": "spider",
    "format": "single",
    "graded": "1",
    "is_signed": "1",
    "condition": "NM",
    "for_sale": "1",
    "for_trade": "1",
    "read_status": "unread",
    "publisher_id": "1",
    "grade_min": "9",
    "grade_max": "9.8",
    "sort_by": "title",
    "sort_order": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/user/collections'
params = {
  'per_page': '20',
  'page': '1',
  'search': 'spider',
  'format': 'single',
  'graded': '1',
  'is_signed': '1',
  'condition': 'NM',
  'for_sale': '1',
  'for_trade': '1',
  'read_status': 'unread',
  'publisher_id': '1',
  'grade_min': '9',
  'grade_max': '9.8',
  'sort_by': 'title',
  'sort_order': 'asc',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/user/collections';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'per_page' => '20',
            'page' => '1',
            'search' => 'spider',
            'format' => 'single',
            'graded' => '1',
            'is_signed' => '1',
            'condition' => 'NM',
            'for_sale' => '1',
            'for_trade' => '1',
            'read_status' => 'unread',
            'publisher_id' => '1',
            'grade_min' => '9',
            'grade_max' => '9.8',
            'sort_by' => 'title',
            'sort_order' => 'asc',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 1001,
            "user_id": 42,
            "collectable_type": "Issue",
            "collectable_id": 5432,
            "variant_id": null,
            "condition": "NM",
            "purchased_at": "2024-01-15",
            "notes": "First print",
            "format": "single",
            "storage_location": "Long box 3",
            "price_paid": 3.99,
            "is_variant": false,
            "variant_description": null,
            "variant_type": null,
            "graded": true,
            "grade_score": "9.8",
            "grading_company": "CGC",
            "grading_number": "1234567001",
            "label_type": "universal",
            "page_quality": "white",
            "grader_notes": null,
            "purchase_source": "lcs",
            "comic_shop_id": 17,
            "comic_shop": {
                "id": 17,
                "name": "Comic Corner",
                "slug": "comic-corner",
                "city": "Portland",
                "state_province": "OR"
            },
            "acquisition_method": "purchased",
            "is_signed": false,
            "signed_by": null,
            "signature_witness": null,
            "signature_authenticated": false,
            "is_cgc_ss": false,
            "print_number": 1,
            "estimated_value": 25,
            "value_last_updated": "2024-06-01T00:00:00Z",
            "for_sale": false,
            "for_trade": false,
            "is_public": true,
            "cover_scan_url": null,
            "cover_scan_url_lg": null,
            "cover_scan_uploaded_at": null,
            "created_at": "2024-01-15T10:30:00Z",
            "updated_at": "2024-01-15T10:30:00Z",
            "collectable": {
                "id": 5432,
                "slug": "example-series-1",
                "series_id": 123,
                "issue_number": "1",
                "name": "First Issue",
                "cover_date": "2023-11-01",
                "release_date": "2023-11-08",
                "foc_date": "2023-10-16",
                "cover_url": "https://versedb.com/storage/issues/5432/cover_lg.jpg",
                "images": {
                    "thumb": "https://versedb.com/storage/issues/5432/thumb.jpg",
                    "cover_sm": "https://versedb.com/storage/issues/5432/cover_sm.jpg",
                    "cover_md": "https://versedb.com/storage/issues/5432/cover_md.jpg",
                    "cover_lg": "https://versedb.com/storage/issues/5432/cover_lg.jpg"
                },
                "is_reprint": false,
                "age_rating": null,
                "is_nsfw": false,
                "average_rating": 4.5,
                "series": {
                    "id": 123,
                    "name": "Example Series",
                    "slug": "example-series",
                    "start_year": 2023,
                    "end_year": null,
                    "volume_number": 1,
                    "publication_type": "ongoing",
                    "format": "single",
                    "cached_issues_count": 12,
                    "cover_url": "https://versedb.com/storage/series/123/cover_lg.jpg",
                    "images": {
                        "cover_sm": "https://versedb.com/storage/series/123/cover_sm.jpg",
                        "cover_md": "https://versedb.com/storage/series/123/cover_md.jpg",
                        "cover_lg": "https://versedb.com/storage/series/123/cover_lg.jpg"
                    },
                    "publisher_name": "Example Publisher"
                },
                "key_issue_reasons": [
                    {
                        "id": 7,
                        "name": "First appearance",
                        "category": "appearance",
                        "slug": "first-appearance",
                        "notes": null
                    }
                ]
            }
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": "..."
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 5,
        "path": "...",
        "per_page": 20,
        "to": 20,
        "total": 100
    }
}
 

Request      

GET api/v1/user/collections

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Items per page (max 100). Example: 20

page   integer  optional    

Page number. Example: 1

search   string  optional    

Filter by issue name, issue number, or series name. Example: spider

format   string  optional    

Filter by stored format. Example: single

graded   boolean  optional    

Filter to graded (true) or raw (false) copies. Example: true

is_signed   boolean  optional    

Filter to signed (true) or unsigned (false) copies. Example: true

condition   string  optional    

Filter by condition grade code. Example: NM

for_sale   boolean  optional    

Filter to copies marked for sale. Example: true

for_trade   boolean  optional    

Filter to copies marked for trade. Example: true

read_status   string  optional    

Filter by read state. One of: read, unread. Example: unread

publisher_id   integer  optional    

Filter to issues from a publisher. Example: 1

grade_min   number  optional    

Filter to copies with a numeric grade at or above this value. Example: 9

grade_max   number  optional    

Filter to copies with a numeric grade at or below this value. Example: 9.8

sort_by   string  optional    

Sort field. One of: date_added, title, release_date, estimated_value, price_paid. Example: title

sort_order   string  optional    

Sort direction. One of: asc, desc. Example: asc

Check issue in collection.

requires authentication

Checks if an issue (optionally a specific variant) is in the user's collection.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/issues/5432/collection/check?variant_id=789" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"variant_id\": 789
}"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/collection/check"
);

const params = {
    "variant_id": "789",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "variant_id": 789
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/collection/check'
payload = {
    "variant_id": 789
}
params = {
  'variant_id': '789',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/collection/check';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'variant_id' => '789',
        ],
        'json' => [
            'variant_id' => 789,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, In Collection):


{
    "in_collection": true,
    "copies_count": 1,
    "copies": [
        {
            "id": 1001,
            "variant_id": 789,
            "condition": "NM",
            "graded": true,
            "grade_score": "9.8",
            "grading_company": "CGC",
            "notes": "First print",
            "created_at": "2024-01-15T10:30:00Z"
        }
    ],
    "data": {
        "id": 1001,
        "condition": "NM",
        "price_paid": 4.99,
        "issue": {
            "id": 5432,
            "name": "The Amazing Spider-Man #1",
            "issue_number": "1"
        }
    }
}
 

Example response (200, Not in Collection):


{
    "in_collection": false,
    "copies_count": 0,
    "copies": [],
    "data": null
}
 

Request      

GET api/v1/issues/{issue_id}/collection/check

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Query Parameters

variant_id   integer  optional    

Specific variant ID to check (optional). Example: 789

Body Parameters

variant_id   integer  optional    

Specific variant ID to check (optional). Example: 789

Add issue to collection.

requires authentication

Adds an issue to the user's default collection. Works for all users (no PRO required). This is the recommended endpoint for mobile collection management.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/issues/5432/collection" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"variant_id\": 789,
    \"condition\": \"NM\",
    \"notes\": \"First print, signed\",
    \"price_paid\": 4.99,
    \"format\": \"standard\",
    \"purchase_source\": \"comic_shop\",
    \"comic_shop_id\": 412,
    \"acquisition_method\": \"purchase\",
    \"purchased_at\": \"2024-06-15\",
    \"storage_location\": \"Long box #3\",
    \"is_signed\": false,
    \"signed_by\": \"Stan Lee\",
    \"is_variant\": false,
    \"variant_description\": \"Skottie Young baby variant\",
    \"variant_type\": \"cover_variant\",
    \"graded\": false,
    \"grade_score\": \"9.8\",
    \"grading_company\": \"CGC\",
    \"grading_number\": \"1234567890\",
    \"label_type\": \"universal\",
    \"page_quality\": \"white\",
    \"grader_notes\": \"Marvel Value Stamp #16 intact\",
    \"print_number\": \"1st\",
    \"signature_witness\": \"witnessed_in_person\",
    \"estimated_value\": 25,
    \"for_sale\": false,
    \"for_trade\": false,
    \"is_public\": true
}"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/collection"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "variant_id": 789,
    "condition": "NM",
    "notes": "First print, signed",
    "price_paid": 4.99,
    "format": "standard",
    "purchase_source": "comic_shop",
    "comic_shop_id": 412,
    "acquisition_method": "purchase",
    "purchased_at": "2024-06-15",
    "storage_location": "Long box #3",
    "is_signed": false,
    "signed_by": "Stan Lee",
    "is_variant": false,
    "variant_description": "Skottie Young baby variant",
    "variant_type": "cover_variant",
    "graded": false,
    "grade_score": "9.8",
    "grading_company": "CGC",
    "grading_number": "1234567890",
    "label_type": "universal",
    "page_quality": "white",
    "grader_notes": "Marvel Value Stamp #16 intact",
    "print_number": "1st",
    "signature_witness": "witnessed_in_person",
    "estimated_value": 25,
    "for_sale": false,
    "for_trade": false,
    "is_public": true
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/collection'
payload = {
    "variant_id": 789,
    "condition": "NM",
    "notes": "First print, signed",
    "price_paid": 4.99,
    "format": "standard",
    "purchase_source": "comic_shop",
    "comic_shop_id": 412,
    "acquisition_method": "purchase",
    "purchased_at": "2024-06-15",
    "storage_location": "Long box #3",
    "is_signed": false,
    "signed_by": "Stan Lee",
    "is_variant": false,
    "variant_description": "Skottie Young baby variant",
    "variant_type": "cover_variant",
    "graded": false,
    "grade_score": "9.8",
    "grading_company": "CGC",
    "grading_number": "1234567890",
    "label_type": "universal",
    "page_quality": "white",
    "grader_notes": "Marvel Value Stamp #16 intact",
    "print_number": "1st",
    "signature_witness": "witnessed_in_person",
    "estimated_value": 25,
    "for_sale": false,
    "for_trade": false,
    "is_public": true
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/collection';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'variant_id' => 789,
            'condition' => 'NM',
            'notes' => 'First print, signed',
            'price_paid' => 4.99,
            'format' => 'standard',
            'purchase_source' => 'comic_shop',
            'comic_shop_id' => 412,
            'acquisition_method' => 'purchase',
            'purchased_at' => '2024-06-15',
            'storage_location' => 'Long box #3',
            'is_signed' => false,
            'signed_by' => 'Stan Lee',
            'is_variant' => false,
            'variant_description' => 'Skottie Young baby variant',
            'variant_type' => 'cover_variant',
            'graded' => false,
            'grade_score' => '9.8',
            'grading_company' => 'CGC',
            'grading_number' => '1234567890',
            'label_type' => 'universal',
            'page_quality' => 'white',
            'grader_notes' => 'Marvel Value Stamp #16 intact',
            'print_number' => '1st',
            'signature_witness' => 'witnessed_in_person',
            'estimated_value' => 25.0,
            'for_sale' => false,
            'for_trade' => false,
            'is_public' => true,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (201, Added):


{
    "data": {
        "id": 1001,
        "issue": {
            "id": 5432,
            "number": "1",
            "title": "First Issue"
        },
        "series": {
            "id": 123,
            "name": "Amazing Spider-Man"
        },
        "variant_id": null,
        "condition": "NM",
        "price_paid": 4.99,
        "notes": "First print, signed"
    }
}
 

Example response (403, Account Pending Deletion):


{
    "error": "Cannot add to collection while account is pending deletion."
}
 

Example response (422, Invalid Variant):


{
    "error": "Variant does not belong to this issue."
}
 

Request      

POST api/v1/issues/{issue_id}/collection

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Body Parameters

variant_id   integer  optional    

Specific variant ID (optional). Example: 789

condition   string  optional    

Condition grade (e.g., NM, VF, FN, VG, G, FR, PR). Example: NM

notes   string  optional    

Personal notes (max 1000 chars). Example: First print, signed

price_paid   number  optional    

Price paid (max 999999.99). Example: 4.99

format   string  optional    

Physical format of the copy. Example: standard

Must be one of:
  • standard
  • trade_paperback
  • hardcover
  • omnibus
  • deluxe_edition
  • annual
  • graphic_novel
  • digital
  • treasury
  • magazine
  • prestige
  • digest
  • other
purchase_source   string  optional    

Where the comic was purchased. Example: comic_shop

Must be one of:
  • comic_shop
  • online_retailer
  • auction
  • convention
  • private_seller
  • subscription
  • digital_platform
  • second_hand_store
  • inheritance
  • gift
  • trade
  • other
comic_shop_id   integer  optional    

ID of the specific comic shop the copy was purchased from. Self-reported; independent of purchase_source. The id of an existing record in the comic_shops table. Example: 412

acquisition_method   string  optional    

How the comic was acquired. Example: purchase

Must be one of:
  • purchase
  • trade
  • gift
  • inheritance
  • subscription
  • found
  • other
purchased_at   string  optional    

Date of purchase (YYYY-MM-DD). Must be a valid date. Example: 2024-06-15

storage_location   string  optional    

Where the comic is stored. Must not be greater than 255 characters. Example: Long box #3

is_signed   boolean  optional    

Whether the comic is signed. Example: false

signed_by   string  optional    

Name(s) of the creator(s) who signed the comic. Free-text — comma-separate multiple signers. Must not be greater than 255 characters. Example: Stan Lee

is_variant   boolean  optional    

Whether this copy is a variant cover. Example: false

variant_description   string  optional    

Free-text description of the variant cover. Must not be greater than 500 characters. Example: Skottie Young baby variant

variant_type   string  optional    

Variant classification (standard, cover_variant, retailer_exclusive, incentive_variant, ratio_variant, virgin_variant, etc.). Example: cover_variant

Must be one of:
  • standard
  • cover_variant
  • retailer_exclusive
  • convention_exclusive
  • incentive_variant
  • ratio_variant
  • foil_variant
  • sketch_variant
  • virgin_variant
  • blank_variant
  • artist_variant
  • hologram_variant
  • glow_in_dark_variant
  • facsimile
  • reprint
  • other
graded   boolean  optional    

Whether the comic is professionally graded. Example: false

grade_score   string  optional    

Numeric grade score (e.g. 9.8). Must not be greater than 10 characters. Example: 9.8

grading_company   string  optional    

Grading company (CGC, CBCS, PGX, other, self_graded). Example: CGC

Must be one of:
  • CGC
  • CBCS
  • PGX
  • other
  • self_graded
grading_number   string  optional    

Grading certification number. Must not be greater than 50 characters. Example: 1234567890

label_type   string  optional    

Slab label tier (e.g. universal, signature_series, restored, qualified). Example: universal

Must be one of:
  • universal
  • signature_series
  • qualified
  • restored
  • cgcxjsa
  • standard
  • verified_signature
  • signed
  • conserved
page_quality   string  optional    

Interior page color quality from the slab label. Example: white

Must be one of:
  • white
  • off_white_to_white
  • off_white
  • cream_to_off_white
  • light_tan
  • tan
  • brittle
grader_notes   string  optional    

Free-text notes printed on the slab label. Must not be greater than 2000 characters. Example: Marvel Value Stamp #16 intact

print_number   string  optional    

Which print this copy is (1st, 2nd, 3rd, … or other). Example: 1st

Must be one of:
  • 1st
  • 2nd
  • 3rd
  • 4th
  • 5th
  • 6th
  • 7th
  • 8th
  • 9th
  • 10th
  • other
signature_witness   string  optional    

Authentication of the signature (CGC, CBCS, JSA, PSA/DNA, witnessed_in_person, unwitnessed, other). Example: witnessed_in_person

Must be one of:
  • CGC
  • CBCS
  • JSA
  • PSA/DNA
  • witnessed_in_person
  • unwitnessed
  • other
estimated_value   number  optional    

Current estimated value in dollars. Must be at least 0. Must not be greater than 999999.99. Example: 25

for_sale   boolean  optional    

Whether the item is for sale. Example: false

for_trade   boolean  optional    

Whether the item is available for trade. Example: false

is_public   boolean  optional    

Whether this collection item is publicly visible. Defaults to true. Example: true

Update collection item.

requires authentication

Updates metadata on an existing collection entry for an issue. Supports partial updates — only send the fields you want to change.

Example request:
curl --request PATCH \
    "https://versedb.com/api/v1/issues/5432/collection?variant_id=789&collection_item_id=1001" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"variant_id\": 42,
    \"condition\": \"NM\",
    \"notes\": \"First print, great condition\",
    \"price_paid\": 3.99,
    \"format\": \"standard\",
    \"purchase_source\": \"comic_shop\",
    \"comic_shop_id\": 412,
    \"acquisition_method\": \"purchase\",
    \"purchased_at\": \"2024-06-15\",
    \"storage_location\": \"Long box #3\",
    \"is_signed\": false,
    \"signed_by\": \"Stan Lee\",
    \"is_variant\": false,
    \"variant_description\": \"Skottie Young baby variant\",
    \"variant_type\": \"cover_variant\",
    \"graded\": false,
    \"grade_score\": \"9.8\",
    \"grading_company\": \"CGC\",
    \"grading_number\": \"1234567890\",
    \"label_type\": \"universal\",
    \"page_quality\": \"white\",
    \"grader_notes\": \"Marvel Value Stamp #16 intact\",
    \"print_number\": \"1st\",
    \"signature_witness\": \"witnessed_in_person\",
    \"estimated_value\": 25,
    \"for_sale\": false,
    \"for_trade\": false,
    \"is_public\": true,
    \"is_read\": true,
    \"read_at\": \"2024-06-15\"
}"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/collection"
);

const params = {
    "variant_id": "789",
    "collection_item_id": "1001",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "variant_id": 42,
    "condition": "NM",
    "notes": "First print, great condition",
    "price_paid": 3.99,
    "format": "standard",
    "purchase_source": "comic_shop",
    "comic_shop_id": 412,
    "acquisition_method": "purchase",
    "purchased_at": "2024-06-15",
    "storage_location": "Long box #3",
    "is_signed": false,
    "signed_by": "Stan Lee",
    "is_variant": false,
    "variant_description": "Skottie Young baby variant",
    "variant_type": "cover_variant",
    "graded": false,
    "grade_score": "9.8",
    "grading_company": "CGC",
    "grading_number": "1234567890",
    "label_type": "universal",
    "page_quality": "white",
    "grader_notes": "Marvel Value Stamp #16 intact",
    "print_number": "1st",
    "signature_witness": "witnessed_in_person",
    "estimated_value": 25,
    "for_sale": false,
    "for_trade": false,
    "is_public": true,
    "is_read": true,
    "read_at": "2024-06-15"
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/collection'
payload = {
    "variant_id": 42,
    "condition": "NM",
    "notes": "First print, great condition",
    "price_paid": 3.99,
    "format": "standard",
    "purchase_source": "comic_shop",
    "comic_shop_id": 412,
    "acquisition_method": "purchase",
    "purchased_at": "2024-06-15",
    "storage_location": "Long box #3",
    "is_signed": false,
    "signed_by": "Stan Lee",
    "is_variant": false,
    "variant_description": "Skottie Young baby variant",
    "variant_type": "cover_variant",
    "graded": false,
    "grade_score": "9.8",
    "grading_company": "CGC",
    "grading_number": "1234567890",
    "label_type": "universal",
    "page_quality": "white",
    "grader_notes": "Marvel Value Stamp #16 intact",
    "print_number": "1st",
    "signature_witness": "witnessed_in_person",
    "estimated_value": 25,
    "for_sale": false,
    "for_trade": false,
    "is_public": true,
    "is_read": true,
    "read_at": "2024-06-15"
}
params = {
  'variant_id': '789',
  'collection_item_id': '1001',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('PATCH', url, headers=headers, json=payload, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/collection';
$response = $client->patch(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'variant_id' => '789',
            'collection_item_id' => '1001',
        ],
        'json' => [
            'variant_id' => 42,
            'condition' => 'NM',
            'notes' => 'First print, great condition',
            'price_paid' => 3.99,
            'format' => 'standard',
            'purchase_source' => 'comic_shop',
            'comic_shop_id' => 412,
            'acquisition_method' => 'purchase',
            'purchased_at' => '2024-06-15',
            'storage_location' => 'Long box #3',
            'is_signed' => false,
            'signed_by' => 'Stan Lee',
            'is_variant' => false,
            'variant_description' => 'Skottie Young baby variant',
            'variant_type' => 'cover_variant',
            'graded' => false,
            'grade_score' => '9.8',
            'grading_company' => 'CGC',
            'grading_number' => '1234567890',
            'label_type' => 'universal',
            'page_quality' => 'white',
            'grader_notes' => 'Marvel Value Stamp #16 intact',
            'print_number' => '1st',
            'signature_witness' => 'witnessed_in_person',
            'estimated_value' => 25.0,
            'for_sale' => false,
            'for_trade' => false,
            'is_public' => true,
            'is_read' => true,
            'read_at' => '2024-06-15',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": {
        "id": 1001,
        "condition": "NM",
        "price_paid": 4.99,
        "graded": true
    }
}
 

Example response (404, Not Found):


{
    "error": "Issue not found in your collection."
}
 

Request      

PATCH api/v1/issues/{issue_id}/collection

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Query Parameters

variant_id   integer  optional    

Specific variant ID to update (when user has multiple entries). Example: 789

collection_item_id   integer  optional    

Specific collection item ID to update. Example: 1001

Body Parameters

variant_id   integer  optional    

Link to a specific issue variant. Must belong to the issue. The id of an existing record in the issue_variants table. Example: 42

condition   string  optional    

Comic condition grade (CGC scale). Example: NM

Must be one of:
  • MT
  • NM/MT
  • NM+
  • NM
  • NM-
  • VF/NM
  • VF+
  • VF
  • VF-
  • F/VF
  • F+
  • F
  • F-
  • VG/F
  • VG+
  • VG
  • VG-
  • G/VG
  • G
  • FR
  • PR
notes   string  optional    

User notes about this copy. Must not be greater than 1000 characters. Example: First print, great condition

price_paid   number  optional    

Purchase price in dollars. Must be at least 0. Must not be greater than 999999.99. Example: 3.99

format   string  optional    

Physical format of the copy. Example: standard

Must be one of:
  • standard
  • trade_paperback
  • hardcover
  • omnibus
  • deluxe_edition
  • annual
  • graphic_novel
  • digital
  • treasury
  • magazine
  • prestige
  • digest
  • other
purchase_source   string  optional    

Where the comic was purchased. Example: comic_shop

Must be one of:
  • comic_shop
  • online_retailer
  • auction
  • convention
  • private_seller
  • subscription
  • digital_platform
  • second_hand_store
  • inheritance
  • gift
  • trade
  • other
comic_shop_id   integer  optional    

ID of the specific comic shop the copy was purchased from. Self-reported; independent of purchase_source. The id of an existing record in the comic_shops table. Example: 412

acquisition_method   string  optional    

How the comic was acquired. Example: purchase

Must be one of:
  • purchase
  • trade
  • gift
  • inheritance
  • subscription
  • found
  • other
purchased_at   string  optional    

Date of purchase (YYYY-MM-DD). Must be a valid date. Example: 2024-06-15

storage_location   string  optional    

Where the comic is stored. Must not be greater than 255 characters. Example: Long box #3

is_signed   boolean  optional    

Whether the comic is signed. Example: false

signed_by   string  optional    

Name(s) of the creator(s) who signed the comic. Free-text — comma-separate multiple signers. Must not be greater than 255 characters. Example: Stan Lee

is_variant   boolean  optional    

Whether this copy is a variant cover. Example: false

variant_description   string  optional    

Free-text description of the variant cover. Must not be greater than 500 characters. Example: Skottie Young baby variant

variant_type   string  optional    

Variant classification (standard, cover_variant, retailer_exclusive, incentive_variant, ratio_variant, virgin_variant, etc.). Example: cover_variant

Must be one of:
  • standard
  • cover_variant
  • retailer_exclusive
  • convention_exclusive
  • incentive_variant
  • ratio_variant
  • foil_variant
  • sketch_variant
  • virgin_variant
  • blank_variant
  • artist_variant
  • hologram_variant
  • glow_in_dark_variant
  • facsimile
  • reprint
  • other
graded   boolean  optional    

Whether the comic is professionally graded. Example: false

grade_score   string  optional    

Numeric grade score (e.g. 9.8). Must not be greater than 10 characters. Example: 9.8

grading_company   string  optional    

Grading company (CGC, CBCS, PGX, other, self_graded). Example: CGC

Must be one of:
  • CGC
  • CBCS
  • PGX
  • other
  • self_graded
grading_number   string  optional    

Grading certification number. Must not be greater than 50 characters. Example: 1234567890

label_type   string  optional    

Slab label tier (e.g. universal, signature_series, restored, qualified). Example: universal

Must be one of:
  • universal
  • signature_series
  • qualified
  • restored
  • cgcxjsa
  • standard
  • verified_signature
  • signed
  • conserved
page_quality   string  optional    

Interior page color quality from the slab label. Example: white

Must be one of:
  • white
  • off_white_to_white
  • off_white
  • cream_to_off_white
  • light_tan
  • tan
  • brittle
grader_notes   string  optional    

Free-text notes printed on the slab label. Must not be greater than 2000 characters. Example: Marvel Value Stamp #16 intact

print_number   string  optional    

Which print this copy is (1st, 2nd, 3rd, … or other). Example: 1st

Must be one of:
  • 1st
  • 2nd
  • 3rd
  • 4th
  • 5th
  • 6th
  • 7th
  • 8th
  • 9th
  • 10th
  • other
signature_witness   string  optional    

Authentication of the signature (CGC, CBCS, JSA, PSA/DNA, witnessed_in_person, unwitnessed, other). Example: witnessed_in_person

Must be one of:
  • CGC
  • CBCS
  • JSA
  • PSA/DNA
  • witnessed_in_person
  • unwitnessed
  • other
estimated_value   number  optional    

Current estimated value in dollars. Must be at least 0. Must not be greater than 999999.99. Example: 25

for_sale   boolean  optional    

Whether the item is for sale. Example: false

for_trade   boolean  optional    

Whether the item is available for trade. Example: false

is_public   boolean  optional    

Whether this collection item is publicly visible. Example: true

is_read   boolean  optional    

Whether the issue has been read. Example: true

read_at   string  optional    

When the issue was read (YYYY-MM-DD). Cannot be in the future. Must be a valid date. Must be a date before or equal to today. Example: 2024-06-15

Remove issue from collection.

requires authentication

Removes an issue (optionally a specific variant) from the user's collection.

Example request:
curl --request DELETE \
    "https://versedb.com/api/v1/issues/5432/collection?variant_id=789&collection_item_id=1001" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"variant_id\": 789,
    \"collection_item_id\": 1001
}"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/collection"
);

const params = {
    "variant_id": "789",
    "collection_item_id": "1001",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "variant_id": 789,
    "collection_item_id": 1001
};

fetch(url, {
    method: "DELETE",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/collection'
payload = {
    "variant_id": 789,
    "collection_item_id": 1001
}
params = {
  'variant_id': '789',
  'collection_item_id': '1001',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers, json=payload, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/collection';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'variant_id' => '789',
            'collection_item_id' => '1001',
        ],
        'json' => [
            'variant_id' => 789,
            'collection_item_id' => 1001,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (204, Success):

Empty response
 

Example response (404, Not Found):


{
    "error": "Issue not found in your collection."
}
 

Request      

DELETE api/v1/issues/{issue_id}/collection

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Query Parameters

variant_id   integer  optional    

Specific variant ID to remove (optional). Example: 789

collection_item_id   integer  optional    

Specific collection item ID to remove (optional). Example: 1001

Body Parameters

variant_id   integer  optional    

Specific variant ID to remove (optional). Example: 789

collection_item_id   integer  optional    

Specific collection item ID to remove (optional). Example: 1001

Pull List

List pull list.

requires authentication

Returns all series on the user's pull list (series they're tracking for new releases).

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/user/pull-list?per_page=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/user/pull-list"
);

const params = {
    "per_page": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/user/pull-list'
params = {
  'per_page': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/user/pull-list';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'per_page' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 123,
            "series": {
                "id": 456,
                "name": "Amazing Spider-Man",
                "publisher": {
                    "id": 1,
                    "name": "Marvel"
                },
                "cover_url": "..."
            },
            "added_at": "2024-01-15T10:30:00Z"
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 2,
        "per_page": 20,
        "total": 35
    }
}
 

Request      

GET api/v1/user/pull-list

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Items per page (max 100). Example: 20

Add to pull list.

requires authentication

Adds a series to the user's pull list to track new releases.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/pull-list/items" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"series_id\": 456
}"
const url = new URL(
    "https://versedb.com/api/v1/pull-list/items"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "series_id": 456
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/pull-list/items'
payload = {
    "series_id": 456
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/pull-list/items';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'series_id' => 456,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (201, Success):


{}
 

Example response (422, Series Not Found):


{
    "message": "The selected series id is invalid.",
    "errors": {
        "series_id": [
            "The selected series id is invalid."
        ]
    }
}
 

Request      

POST api/v1/pull-list/items

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

series_id   integer     

The series ID to add. Example: 456

Remove from pull list.

requires authentication

Example request:
curl --request DELETE \
    "https://versedb.com/api/v1/pull-list/items/456" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/pull-list/items/456"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/pull-list/items/456'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/pull-list/items/456';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (204, Removed):

Empty response
 

Request      

DELETE api/v1/pull-list/items/{item_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

item_id   integer     

The series ID of the pull list entry. Example: 456

Read Status

List read status.

requires authentication

Returns all issues the user has marked as read with timestamps.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/user/read-status?per_page=20&unreviewed=1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/user/read-status"
);

const params = {
    "per_page": "20",
    "unreviewed": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/user/read-status'
params = {
  'per_page': '20',
  'unreviewed': '1',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/user/read-status';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'per_page' => '20',
            'unreviewed' => '1',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 1234,
            "issue": {
                "id": 5432,
                "number": "1",
                "title": "First Issue"
            },
            "series": {
                "id": 123,
                "name": "Amazing Spider-Man"
            },
            "variant_id": null,
            "read_at": "2024-01-15T10:30:00Z"
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 10,
        "per_page": 20,
        "total": 200
    }
}
 

Request      

GET api/v1/user/read-status

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Items per page (max 100). Example: 20

unreviewed   boolean  optional    

When true, only returns reads for issues the user has not yet reviewed. Example: true

Mark as read.

requires authentication

Marks an issue (optionally a specific variant) as read with the current timestamp.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/issues/5432/read-status" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"variant_id\": 789
}"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/read-status"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "variant_id": 789
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/read-status'
payload = {
    "variant_id": 789
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/read-status';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'variant_id' => 789,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (201, Success):


{}
 

Example response (422, Invalid Variant):


{
    "error": "Variant does not belong to this issue"
}
 

Request      

POST api/v1/issues/{issue_id}/read-status

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Body Parameters

variant_id   integer  optional    

Specific variant ID (optional). Example: 789

Edit reading date.

requires authentication

Updates the read_at date on an existing read entry, or removes the entry when read_at is null. If no entry exists yet and a date is provided, one is created (upsert).

Example request:
curl --request PATCH \
    "https://versedb.com/api/v1/issues/5432/read-status" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"read_at\": \"2026-03-01\",
    \"variant_id\": 789
}"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/read-status"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "read_at": "2026-03-01",
    "variant_id": 789
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/read-status'
payload = {
    "read_at": "2026-03-01",
    "variant_id": 789
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('PATCH', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/read-status';
$response = $client->patch(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'read_at' => '2026-03-01',
            'variant_id' => 789,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Updated):


{
    "read_at": "2026-03-01T00:00:00+00:00"
}
 

Example response (204, Cleared (read_at was null)):

Empty response
 

Request      

PATCH api/v1/issues/{issue_id}/read-status

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Body Parameters

read_at   string  optional    

Date in YYYY-MM-DD format, must not be in the future. Pass null to mark as unread. Example: 2026-03-01

variant_id   integer  optional    

Specific variant ID (optional). Example: 789

Mark as unread.

requires authentication

Removes the read status for an issue (optionally a specific variant).

Example request:
curl --request DELETE \
    "https://versedb.com/api/v1/issues/5432/read-status" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"variant_id\": 789
}"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/read-status"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "variant_id": 789
};

fetch(url, {
    method: "DELETE",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/read-status'
payload = {
    "variant_id": 789
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/read-status';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'variant_id' => 789,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (204, Success):

Empty response
 

Request      

DELETE api/v1/issues/{issue_id}/read-status

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Body Parameters

variant_id   integer  optional    

Specific variant ID (optional). Example: 789

Wishlist

List wishlist.

requires authentication

Returns the authenticated user's wishlist items (issues), most recently added first.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/user/wishlist?per_page=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/user/wishlist"
);

const params = {
    "per_page": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/user/wishlist'
params = {
  'per_page': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/user/wishlist';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'per_page' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 9876,
            "position": null,
            "note": null,
            "created_at": "2024-01-15T10:30:00Z",
            "updated_at": "2024-01-15T10:30:00Z",
            "variant_id": null,
            "entity_type": "issues",
            "entity": {
                "id": 5432,
                "name": "Amazing Spider-Man #1",
                "issue_number": "1",
                "image_url": "...",
                "publisher": "Marvel",
                "series": {
                    "id": 123,
                    "name": "Amazing Spider-Man",
                    "start_year": 2018
                }
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 20,
        "total": 4
    }
}
 

Request      

GET api/v1/user/wishlist

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Items per page (max 100). Example: 20

Add to wishlist.

requires authentication

Adds the issue to the authenticated user's wishlist. Idempotent — calling with an issue already on the wishlist returns 200 without creating a duplicate.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/issues/5432/wishlist" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/wishlist"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/wishlist'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/wishlist';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Already in Wishlist):


{
    "in_wishlist": true
}
 

Example response (201, Added):


{
    "in_wishlist": true
}
 

Example response (422, Wishlist Full):


{
    "message": "Wishlist is full (max 500 items)."
}
 

Request      

POST api/v1/issues/{issue_id}/wishlist

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Remove from wishlist.

requires authentication

Removes the issue from the authenticated user's wishlist. Idempotent — returns 204 whether or not the issue was on the wishlist.

Example request:
curl --request DELETE \
    "https://versedb.com/api/v1/issues/5432/wishlist" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/issues/5432/wishlist"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/issues/5432/wishlist'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/issues/5432/wishlist';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (204, Removed):

Empty response
 

Request      

DELETE api/v1/issues/{issue_id}/wishlist

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

issue_id   integer     

The issue ID. Example: 5432

Follows

List follows.

requires authentication

Returns all entities the user is following (titles, characters, podcasts, etc.).

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/user/follows?per_page=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/user/follows"
);

const params = {
    "per_page": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/user/follows'
params = {
  'per_page': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/user/follows';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'per_page' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": 789,
            "followable_type": "title",
            "followable_id": 123,
            "followable": {
                "id": 123,
                "name": "Spider-Man",
                "cover_url": "..."
            },
            "created_at": "2024-01-15T10:30:00Z"
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 20,
        "total": 12
    }
}
 

Request      

GET api/v1/user/follows

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Items per page (max 100). Example: 20

Follow content.

requires authentication

Follows a title, character, podcast, creator, publisher, team, story arc, comic shop, event, or user.

Example request:
curl --request POST \
    "https://versedb.com/api/v1/follow" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"type\": \"title\",
    \"id\": 45,
    \"preferences\": {
        \"email_notifications\": true,
        \"push_notifications\": false
    }
}"
const url = new URL(
    "https://versedb.com/api/v1/follow"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "type": "title",
    "id": 45,
    "preferences": {
        "email_notifications": true,
        "push_notifications": false
    }
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/follow'
payload = {
    "type": "title",
    "id": 45,
    "preferences": {
        "email_notifications": true,
        "push_notifications": false
    }
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/follow';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'type' => 'title',
            'id' => 45,
            'preferences' => ['email_notifications' => true, 'push_notifications' => false],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "message": "Following title successfully",
    "is_following": true
}
 

Example response (404, Not Found):


{
    "message": "Title not found"
}
 

Request      

POST api/v1/follow

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

type   string     

The content type (title, character, podcast, creator, publisher, team, story_arc, comic_shop, event, user). Example: title

id   integer     

The ID of the content to follow. Example: 45

preferences   object  optional    

Notification preferences.

email_notifications   boolean  optional    

Receive email notifications. Example: true

push_notifications   boolean  optional    

Receive push notifications. Example: false

Unfollow content.

requires authentication

Example request:
curl --request DELETE \
    "https://versedb.com/api/v1/follow/title/45" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/follow/title/45"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/follow/title/45'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/follow/title/45';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "message": "Unfollowed title successfully",
    "is_following": false
}
 

Example response (404, Not Found):


{
    "message": "Title not found"
}
 

Request      

DELETE api/v1/follow/{type}/{id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

type   string     

The content type (title, character, podcast, creator, publisher, team, story_arc, comic_shop, event, user). Example: title

id   integer     

The ID of the followed content. Example: 45

Check follow status.

requires authentication

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/follow/title/45/check" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/follow/title/45/check"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/follow/title/45/check'
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/follow/title/45/check';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "is_following": true
}
 

Request      

GET api/v1/follow/{type}/{id}/check

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

type   string     

The content type (title, character, podcast, creator, publisher, team, story_arc, comic_shop, event, user). Example: title

id   integer     

The ID of the content. Example: 45

Activity

Get activity feed.

requires authentication

Aggregates recent activity from collections, reads, follows, and reviews.

Example request:
curl --request GET \
    --get "https://versedb.com/api/v1/user/activity?per_page=20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://versedb.com/api/v1/user/activity"
);

const params = {
    "per_page": "20",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://versedb.com/api/v1/user/activity'
params = {
  'per_page': '20',
}
headers = {
  'Authorization': 'Bearer {YOUR_AUTH_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://versedb.com/api/v1/user/activity';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'per_page' => '20',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Success):


{
    "data": [
        {
            "id": "collection_9921",
            "type": "collection",
            "action": "added_to_collection",
            "created_at": "2026-06-20T14:32:00+00:00",
            "data": {
                "issue_id": 5432,
                "issue_name": "Amazing Spider-Man #1",
                "series_name": "Amazing Spider-Man",
                "cover_url": "https://r2.versedb.com/uploads/issues/asm-5432/asm-5432-cover_md.webp"
            }
        },
        {
            "id": "review_312",
            "type": "review",
            "action": "wrote_review",
            "created_at": "2026-06-19T09:10:00+00:00",
            "data": {
                "review_id": 312,
                "issue_id": 5410,
                "issue_name": "Batman #135",
                "series_name": "Batman",
                "rating": 4.5,
                "content_preview": "A strong anniversary issue that pays off years of buildup...",
                "cover_url": "https://r2.versedb.com/uploads/issues/batman-5410/batman-5410-cover_md.webp"
            }
        }
    ],
    "meta": {
        "current_page": 1,
        "per_page": 20,
        "total": 84,
        "last_page": 5
    }
}
 

Request      

GET api/v1/user/activity

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Number of results per page (max 100). Example: 20