Zines API
The Zines API provides access to ZineCore2 bibliographic records. All zine metadata follows the ZineCore2 Dublin Core Application Profile.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/zines/ | List all zines (paginated) |
| POST | /api/zines/ | Create new zine |
| GET | /api/zines/{zine_id}/ | Get specific zine |
| PUT | /api/zines/{zine_id}/ | Replace zine (all fields) |
| PATCH | /api/zines/{zine_id}/ | Update zine (partial) |
| DELETE | /api/zines/{zine_id}/ | Delete zine |
List Zines
Get paginated list of all zine records.
Request
GET /api/zines/
Authentication: Not required (public endpoint)
Query parameters:
- page — Page number (default: 1)
- page_size — Results per page (default: 25, max: 100)
- search — Full-text search across title and abstract
- subject — Filter by subject code
- genre — Filter by genre code
- creator — Filter by creator agent ID
- language — Filter by language code
- ordering — Sort field (prefix with - for descending)
Response
{
"count": 142,
"next": "http://localhost:8000/api/zines/?page=2",
"previous": null,
"results": [
{
"zine_id": "zine_mutate_3_1st",
"title": "Mutate Zine #3: Abortion Stories",
"series_title": ["Mutate Zine"],
"issue_designation": "#3",
"creator": [
{
"agent_id": "agent_judith_arcana",
"display_name": "Judith Arcana",
"kind": "Person"
}
],
"subject": [
{
"code": "feminism",
"label": "Feminism",
"uri": "https://zinecore.org/v2/subjects#feminism"
}
],
"genre": [
{
"code": "personal-zine",
"label": "Personal Zine",
"uri": "https://zinecore.org/v2/genres#personal-zine"
}
],
"date": ["2024"],
"language": ["en"],
"rights": ["cc-by-4.0"],
"created_at": "2024-02-25T10:30:00Z",
"updated_at": "2024-02-25T10:30:00Z"
}
]
}
Examples
Basic list:
curl http://localhost:8000/api/zines/
Search by title:
curl "http://localhost:8000/api/zines/?search=mutate"
Filter by subject:
curl "http://localhost:8000/api/zines/?subject=feminism"
Filter by genre:
curl "http://localhost:8000/api/zines/?genre=personal-zine"
Filter by creator:
curl "http://localhost:8000/api/zines/?creator=agent_judith_arcana"
Multiple filters:
curl "http://localhost:8000/api/zines/?subject=feminism&genre=personal-zine&ordering=-created_at"
Custom page size:
curl "http://localhost:8000/api/zines/?page_size=50"
Get Zine
Retrieve a specific zine by its external ID.
Request
GET /api/zines/{zine_id}/
Authentication: Not required (public endpoint)
URL parameters:
- zine_id — Zine's external identifier (e.g., zine_mutate_3_1st)
Response
{
"zine_id": "zine_mutate_3_1st",
"title": "Mutate Zine #3: Abortion Stories",
"series_title": ["Mutate Zine"],
"issue_designation": "#3",
"edition_statement": [],
"alternative_title": [],
"creator": [
{
"agent_id": "agent_judith_arcana",
"display_name": "Judith Arcana",
"kind": "Person",
"pronouns": ["she/her"],
"biography": "Feminist writer and activist."
}
],
"contributor": [],
"subject": [
{
"code": "feminism",
"label": "Feminism",
"definition": "Social, political, and economic equality of the sexes.",
"uri": "https://zinecore.org/v2/subjects#feminism"
},
{
"code": "reproductive-rights",
"label": "Reproductive Rights",
"uri": "https://zinecore.org/v2/subjects#reproductive-rights"
}
],
"genre": [
{
"code": "personal-zine",
"label": "Personal Zine",
"uri": "https://zinecore.org/v2/genres#personal-zine"
}
],
"abstract": "Personal narratives and essays about reproductive rights and abortion access.",
"table_of_contents": "",
"public_notes": [],
"publisher": [],
"date": ["2024"],
"physical_dimensions": "",
"number_of_pages": "32",
"format": ["Photocopy"],
"binding_features": [],
"language": ["en"],
"place_of_publication": [],
"coverage": [],
"source": [],
"relation": [],
"rights": ["cc-by-4.0"],
"identifier": [],
"created_at": "2024-02-25T10:30:00Z",
"updated_at": "2024-02-25T10:30:00Z"
}
Examples
Get zine:
curl http://localhost:8000/api/zines/zine_mutate_3_1st/
Get as JSON-LD:
curl -H "Accept: application/ld+json" \
http://localhost:8000/api/zines/zine_mutate_3_1st/
Get as BibTeX:
curl -H "Accept: application/x-bibtex" \
http://localhost:8000/api/zines/zine_mutate_3_1st/
Create Zine
Create a new zine record.
Request
POST /api/zines/
Content-Type: application/json
Authorization: Token YOUR_TOKEN
Authentication: Required
Body (JSON):
All fields use the write serializer format (simple IDs, not nested objects).
Required Fields
| Field | Type | Description | Example |
|---|---|---|---|
| zine_id | string | Unique external identifier | "zine_mutate_3_1st" |
| title | string | Primary title | "Mutate Zine #3" |
| creator | arraystring | Creator agent IDs | ["agent_judith_arcana"] |
| subject | arraystring | Subject codes | ["feminism"] |
| genre | arraystring | Genre codes | ["personal-zine"] |
| date | arraystring | Publication dates | ["2024"] |
| language | arraystring | Language codes (ISO 639-1) | ["en"] |
| rights | arraystring | Rights statement codes | ["cc-by-4.0"] |
Optional Fields
| Field | Type | Description | Example |
|---|---|---|---|
| series_title | arraystring | Series name(s) | ["Mutate Zine"] |
| issue_designation | string | Issue number/label | "#3" |
| edition_statement | arraystring | Edition info | ["First edition"] |
| alternative_title | arraystring | Subtitles, variants | ["Stories of Choice"] |
| contributor | arraystring | Contributor agent IDs | ["agent_jane_doe"] |
| abstract | string | Summary description | "Personal narratives..." |
| table_of_contents | string | TOC text | "Introduction\nStory 1..." |
| public_notes | arraystring | Public notes | ["Content warning: abortion"] |
| publisher | arraystring | Publisher agent IDs | ["agent_feminist_press"] |
| physical_dimensions | string | Height × width | "8.5 × 5.5 inches" |
| number_of_pages | string | Page count | "32" |
| format | arraystring | Production method | ["Photocopy"] |
| binding_features | arraystring | Binding type | ["Saddle-stitched"] |
| place_of_publication | arraystring | Publication place | ["Seattle, WA"] |
| coverage | arraystring | Spatial/temporal coverage | ["US, 2020s"] |
| source | arraystring | Acquisition info | ["Donated by author"] |
| relation | arraystring | Related works | ["See also: Mutate #2"] |
| identifier | arraystring | Other identifiers | ["OCLC:123456"] |
Request Example
curl -X POST http://localhost:8000/api/zines/ \
-H "Authorization: Token YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"zine_id": "zine_mutate_3_1st",
"title": "Mutate Zine #3: Abortion Stories",
"series_title": ["Mutate Zine"],
"issue_designation": "#3",
"creator": ["agent_judith_arcana"],
"subject": ["feminism", "reproductive-rights", "personal-narratives"],
"genre": ["personal-zine"],
"date": ["2024"],
"language": ["en"],
"rights": ["cc-by-4.0"],
"abstract": "Personal narratives and essays about reproductive rights.",
"number_of_pages": "32",
"format": ["Photocopy"]
}'
Response (201 Created)
Returns the full zine object with all relationships resolved (read serializer format):
{
"zine_id": "zine_mutate_3_1st",
"title": "Mutate Zine #3: Abortion Stories",
"series_title": ["Mutate Zine"],
"issue_designation": "#3",
"creator": [
{
"agent_id": "agent_judith_arcana",
"display_name": "Judith Arcana",
"kind": "Person"
}
],
"subject": [
{
"code": "feminism",
"label": "Feminism",
"uri": "https://zinecore.org/v2/subjects#feminism"
}
],
"created_at": "2024-02-25T10:30:00Z",
"updated_at": "2024-02-25T10:30:00Z"
}
Update Zine
Update an existing zine record.
PATCH (Partial Update)
Update only specific fields.
PATCH /api/zines/{zine_id}/
Content-Type: application/json
Authorization: Token YOUR_TOKEN
Request:
curl -X PATCH http://localhost:8000/api/zines/zine_mutate_3_1st/ \
-H "Authorization: Token YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"abstract": "Updated description with more detail.",
"number_of_pages": "36"
}'
Only provided fields are updated. All other fields remain unchanged.
PUT (Full Replacement)
Replace the entire zine record.
PUT /api/zines/{zine_id}/
Content-Type: application/json
Authorization: Token YOUR_TOKEN
Request:
curl -X PUT http://localhost:8000/api/zines/zine_mutate_3_1st/ \
-H "Authorization: Token YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"zine_id": "zine_mutate_3_1st",
"title": "Mutate Zine #3",
"creator": ["agent_judith_arcana"],
"subject": ["feminism"],
"genre": ["personal-zine"],
"date": ["2024"],
"language": ["en"],
"rights": ["cc-by-4.0"]
}'
All required fields must be provided. Omitted optional fields are cleared.
Response (200 OK)
Returns the updated full zine object.
Delete Zine
Delete a zine record.
Request
DELETE /api/zines/{zine_id}/
Authorization: Token YOUR_TOKEN
Authentication: Required
Example:
curl -X DELETE http://localhost:8000/api/zines/zine_mutate_3_1st/ \
-H "Authorization: Token YOUR_TOKEN"
Response (204 No Content)
No response body.
Cascade behavior:
- All holdings referencing this zine are also deleted
- Agent records are NOT deleted (agents can exist without zines)
Field Details
zine_id
Type: string (max 255 characters) Required: Yes Unique: Yes
External unique identifier for the zine.
Naming convention: zine_{title_slug}_{issue}_{edition}
Examples:
zine_mutate_3_1st
zine_feminist_killjoy_1_2nd
zine_punk_planet_73
title
Type: string (max 500 characters) Required: Yes Repeatable: No
Primary title of the zine issue.
Examples:
"Mutate Zine #3: Abortion Stories"
"Feminist Killjoy #1"
"Punk Planet #73"
series_title
Type: array of strings (max 500 characters each) Required: No Repeatable: Yes
Name of the zine series this issue belongs to.
Examples:
["Mutate Zine"]
["Feminist Killjoy"]
[]
issue_designation
Type: string (max 100 characters) Required: No Repeatable: No
Issue number or label within a series.
Examples:
"#3"
"No. 12"
"Spring 2024"
"Vol. 2, Issue 4"
creator
Type: array of strings (agent IDs) Required: Yes Repeatable: Yes
Agent IDs of primary creators.
Write (POST/PUT/PATCH):
["agent_judith_arcana", "agent_jane_doe"]
Read (GET response):
[
{
"agent_id": "agent_judith_arcana",
"display_name": "Judith Arcana",
"kind": "Person"
}
]
Validation:
- All agent IDs must exist in agents table
- At least one creator required
contributor
Type: array of strings (agent IDs) Required: No Repeatable: Yes
Agent IDs of contributors (illustrators, editors, etc.).
Same format as creator.
subject
Type: array of strings (subject codes) Required: Yes Repeatable: Yes
Subject codes from the subjects vocabulary.
Write:
["feminism", "reproductive-rights", "personal-narratives"]
Read:
[
{
"code": "feminism",
"label": "Feminism",
"uri": "https://zinecore.org/v2/subjects#feminism"
}
]
Validation:
- All codes must exist in subjects vocabulary
- At least one subject required
Available codes: See /api/vocabularies/subjects/
genre
Type: array of strings (genre codes) Required: Yes Repeatable: Yes
Genre codes from the genres vocabulary.
Write:
["personal-zine", "art-zine"]
Read:
[
{
"code": "personal-zine",
"label": "Personal Zine",
"uri": "https://zinecore.org/v2/genres#personal-zine"
}
]
Available codes: See /api/vocabularies/genres/
date
Type: array of strings Required: Yes Repeatable: Yes
Publication or creation dates.
Format: ISO 8601 or text (flexible)
Examples:
["2024"]
["2024-03"]
["2024-03-15"]
["Spring 2024"]
["c. 2020"]
["2019-2020"]
language
Type: array of strings (ISO 639-1 codes) Required: Yes Repeatable: Yes
Language codes for content language(s).
Format: 2-letter ISO 639-1 codes
Examples:
["en"]
["en", "es"]
["fr"]
Common codes:
- en — English
- es — Spanish
- fr — French
- de — German
- zh — Chinese
Full list: See /api/geography/languages/
rights
Type: array of strings (rights codes) Required: Yes Repeatable: Yes
Rights and permissions statements.
Examples:
["cc-by-4.0"]
["all-rights-reserved"]
["public-domain"]
["unknown"]
Available codes: See /api/vocabularies/rights-status/
format
Type: array of strings (format codes) Required: No Repeatable: Yes
Production methods and formats.
Examples:
["Photocopy"]
["Risograph"]
["Offset", "Screen-printed cover"]
Available codes: See /api/vocabularies/formats/
physical_dimensions
Type: string (max 100 characters) Required: No Repeatable: No
Physical dimensions of the zine.
Format: height × width [units]
Examples:
"8.5 × 5.5 inches"
"21 × 14.8 cm"
"Half-letter"
number_of_pages
Type: string (max 50 characters) Required: No Repeatable: No
Page count.
Examples:
"32"
"24 pages"
"Unpaged"
"ca. 40"
Validation Errors
Missing Required Field
Request:
{
"zine_id": "zine_test",
"title": "Test Zine"
// Missing required fields
}
Response (400 Bad Request):
{
"creator": ["This field is required."],
"subject": ["This field is required."],
"genre": ["This field is required."],
"date": ["This field is required."],
"language": ["This field is required."],
"rights": ["This field is required."]
}
Invalid Agent ID
Request:
{
"creator": ["agent_nonexistent"]
}
Response (400 Bad Request):
{
"creator": ["Agent 'agent_nonexistent' does not exist"]
}
Invalid Vocabulary Code
Request:
{
"subject": ["invalid-subject-code"]
}
Response (400 Bad Request):
{
"subject": ["Invalid subject codes: invalid-subject-code"]
}
Duplicate zine_id
Request:
{
"zine_id": "zine_existing"
}
Response (400 Bad Request):
{
"zine_id": ["Zine with this zine_id already exists."]
}
Code Examples
Python
import requests
API_BASE = "http://localhost:8000/api"
TOKEN = "YOUR_TOKEN"
headers = {
"Authorization": f"Token {TOKEN}",
"Content-Type": "application/json"
}
# Create zine
zine_data = {
"zine_id": "zine_my_zine",
"title": "My Zine",
"creator": ["agent_me"],
"subject": ["feminism"],
"genre": ["personal-zine"],
"date": ["2024"],
"language": ["en"],
"rights": ["cc-by-4.0"]
}
response = requests.post(
f"{API_BASE}/zines/",
headers=headers,
json=zine_data
)
if response.status_code == 201:
print(f"Created: {response.json()['title']}")
else:
print(f"Error: {response.json()}")
# Get zine
response = requests.get(f"{API_BASE}/zines/zine_my_zine/")
zine = response.json()
print(f"Title: {zine['title']}")
print(f"Creator: {zine['creator'][0]['display_name']}")
# Update zine
response = requests.patch(
f"{API_BASE}/zines/zine_my_zine/",
headers=headers,
json={"abstract": "Updated description"}
)
JavaScript
const API_BASE = "http://localhost:8000/api";
const TOKEN = "YOUR_TOKEN";
// Create zine
const zineData = {
zine_id: "zine_my_zine",
title: "My Zine",
creator: ["agent_me"],
subject: ["feminism"],
genre: ["personal-zine"],
date: ["2024"],
language: ["en"],
rights: ["cc-by-4.0"]
};
const response = await fetch(`${API_BASE}/zines/`, {
method: "POST",
headers: {
"Authorization": `Token ${TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify(zineData)
});
const zine = await response.json();
console.log(`Created: ${zine.title}`);
// Get zine
const getResponse = await fetch(`${API_BASE}/zines/zine_my_zine/`);
const fetchedZine = await getResponse.json();
console.log(`Title: ${fetchedZine.title}`);
Next Steps
- Agents API — Agent endpoints reference
- Holdings API — Holdings endpoints reference
- Filtering — Advanced filtering and search
- Output Formats — Export as JSON-LD, CSV, BibTeX, etc.