Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developers.openalex.org/llms.txt

Use this file to discover all available pages before exploring further.

A collection is a private, named list of OpenAlex entities of one type — for example, “Papers I’m tracking for this grant”, “Authors at my consortium”, or “Journals I publish in”. Collections give you a single ID you can drop into the filter parameter anywhere in the API, instead of pasting hundreds of OpenAlex IDs into every request.
Collections are private to the user who creates them. Manage them via authenticated requests against user.openalex.org, and use the collection: filter against api.openalex.org — both authenticated with your OpenAlex API key in the Authorization: Bearer header. You can only filter on collections you own.

Concepts

PropertyValue
One entity type per collectionworks, authors, sources, institutions, topics, sdgs, funders, publishers, keywords, or concepts
Max entities per collection1,000
Max collections per user100
Display-name length1–30 characters; case-insensitive unique per user
Description length0–500 characters
ID shapecol_ followed by 10 alphanumeric characters
A collection holds entities of a single type. To track works and the authors of those works, create two collections.

Creating a collection

The easiest way to create a collection is in the OpenAlex web UI at openalex.org:
  1. Run a search.
  2. Tick the rows you want to save (or use the master checkbox to select the whole page).
  3. Click the folder icon in the results toolbar → Create a new collection.
You can also paste a list of IDs or DOIs straight into the create-collection wizard at https://openalex.org/settings/collections. To create one programmatically, POST to /me/collections:
POST https://user.openalex.org/me/collections
Authorization: Bearer <your-api-key>
Content-Type: application/json

{
  "display_name": "My altmetrics papers",
  "entity_type": "works",
  "description": "Papers I'm tracking for the altmetrics review",
  "entity_ids": [
    "https://openalex.org/W2755968057",
    "https://openalex.org/W4404012345"
  ]
}
entity_ids is optional — you can create an empty collection and add entities later. IDs may be supplied in full-URL form (https://openalex.org/W123…) or short form (W123…); the API normalizes them. Every ID must match the collection’s entity_type — adding A123… to a works collection returns a 400 naming the offending ID. A successful create returns 201 with the saved collection:
{
  "id": "col_beNWUTw6qY",
  "user_id": "user-TSamuHxDbnhn",
  "entity_type": "works",
  "display_name": "My altmetrics papers",
  "description": "Papers I'm tracking for the altmetrics review",
  "entity_count": 2,
  "created_at": "2026-05-26T14:00:00",
  "updated_at": "2026-05-26T14:00:00"
}

Filtering search results by collection

Once a collection exists, drop its ID into any search on the matching entity type using the collection: filter:
# Every work in the col_beNWUTw6qY collection
GET https://api.openalex.org/works?filter=collection:col_beNWUTw6qY
Authorization: Bearer <your-api-key>
This works on every entity type the collection system supports — /works, /authors, /sources, /institutions, /topics, /sdgs, /funders, /publishers, /keywords, /concepts — as long as the collection and the endpoint match. Filtering an authors collection on /works returns a 400:
collection col_beNWUTw6qY is type 'authors', not valid for /works
The collection ID resolves to the underlying entity IDs at query time, so the filter combines normally with other filters and with sorting, grouping, selecting, and pagination:
# Open-access papers in this collection, newest first
GET https://api.openalex.org/works?filter=collection:col_beNWUTw6qY,is_oa:true&sort=publication_date:desc

Negation

Prepend ! to exclude the entities in the collection instead of including them:
GET https://api.openalex.org/works?filter=collection:!col_beNWUTw6qY

Limits

  • One collection: filter per request. Repeated or |-OR’d collection values return a 400. To combine collections, snapshot the resolved IDs client-side and pass them via the openalex: filter.
  • Per-request entity-list ceiling: 10,000. With the per-collection cap of 1,000 entities, a single collection is always within budget.
  • Authentication required. Pass your OpenAlex API key in the Authorization: Bearer … header. Anonymous requests return 401; requests by a user who doesn’t own the collection return 403.
The collection: filter above matches a collection against the endpoint of the same type — a sources collection on /sources, an authors collection on /authors. But collections are often most useful across types: filtering one kind of entity by a collection of a different kind. Any filter field whose value is an OpenAlex ID also accepts a col_… collection of the matching type. OpenAlex resolves the collection to its member IDs at query time and matches that field against them — so the collection ID behaves exactly like a value for that field. Example — the library-subscription workflow. A librarian builds a sources collection of the ~1,000 journal IDs in their Elsevier (or Wiley, Springer, …) package, then filters works by it through the primary_location.source.id field:
# Every work published in a journal in your subscription collection
GET https://api.openalex.org/works?filter=primary_location.source.id:col_beNWUTw6qY
Authorization: Bearer <your-api-key>
Because the collection resolves to ordinary field values, it composes with every other filter, plus sorting, grouping, selecting, and pagination. For example, “open-access works from 2024 in my subscribed journals, grouped by author institution”:
GET https://api.openalex.org/works?filter=primary_location.source.id:col_beNWUTw6qY,is_oa:true,publication_year:2024&group_by=authorships.institutions.id
Authorization: Bearer <your-api-key>
The same pattern works for any ID-valued filter field, on any endpoint:
Filter clauseCollection typeMeaning
/works?filter=primary_location.source.id:col_…sourcesWorks published in these journals/sources
/works?filter=authorships.author.id:col_…authorsWorks by any of these authors
/works?filter=authorships.institutions.id:col_…institutionsWorks affiliated with these institutions
/works?filter=primary_topic.id:col_…topicsWorks on these topics
/works?filter=funders.id:col_…fundersWorks funded by these funders
This covers the ID-valued fields on /works, /authors, /sources, and /institutions — including author and institution fields such as last_known_institutions.id and affiliations.institution.id.

Type matching

The collection’s type must match the type the filter field expects. A sources collection works on primary_location.source.id but not on authorships.author.id; a mismatch returns a 400 naming both sides:
collection col_beNWUTw6qY is type 'sources', not valid for the `authorships.author.id` filter (expects 'authors').
A field that doesn’t take an entity ID (for example a date or boolean field) can’t take a collection at all:
The `publication_year` filter does not support cross-type collection references (col_...). Use a same-type `collection:` filter or a literal value list.

Negation

Prepend ! to the collection ID to exclude its members, just like any other filter value:
# Works NOT published in your subscribed journals
GET https://api.openalex.org/works?filter=primary_location.source.id:!col_beNWUTw6qY
Authorization: Bearer <your-api-key>

Limits

  • One collection per filter field. You can’t OR two collections onto the same field (field:col_a|col_b) or repeat the field with a second collection — either returns a 400. Use one collection per field; different fields in the same request can each carry their own collection.
  • Don’t mix a collection with literal IDs in one clause. primary_location.source.id:col_…|S12345 returns a 400. Pass the collection alone, or pass literal IDs alone.
  • The per-collection cap of 1,000 entities still applies, and a single request resolves to at most 10,000 entity IDs across all of its collection filters.

Managing collections

All endpoints below live on user.openalex.org and require your OpenAlex API key in the Authorization: Bearer header. Anonymous requests return 401; requests for a collection owned by another user return 403 (admins bypass this).

List your collections

GET https://user.openalex.org/me/collections
Supports ?page= and ?per_page= (max 100). Pass ?entity_id=W2755968057 to filter to collections that contain a specific entity — used by the collection-chip strip on entity pages in the OpenAlex UI. Response:
{
  "meta": {
    "page": 1, "per_page": 25, "total_count": 3, "total_pages": 1
  },
  "results": [
    {
      "id": "col_beNWUTw6qY",
      "user_id": "user-TSamuHxDbnhn",
      "entity_type": "works",
      "display_name": "My altmetrics papers",
      "description": "Papers I'm tracking for the altmetrics review",
      "entity_count": 4,
      "created_at": "2026-05-20T16:00:00",
      "updated_at": "2026-05-26T14:00:00"
    }
  ]
}

Get a single collection

GET https://user.openalex.org/collections/{collection_id}
Returns the same shape as one row in results above. The collection’s entities are paged separately to keep response sizes bounded:
GET https://user.openalex.org/collections/{collection_id}/entities?per_page=200
Returns the collection metadata plus the page of entity_ids (max per_page=200).

Update name, description, or entity type

PATCH https://user.openalex.org/me/collections/{collection_id}
Content-Type: application/json

{ "display_name": "Renamed", "description": "Updated notes" }
entity_type can be changed only while the collection is empty.

Delete a collection

DELETE https://user.openalex.org/me/collections/{collection_id}
Returns {"deleted_collection_id": "col_…"}. All collection_entities rows cascade-delete.

Add or remove entities

# Bulk add
POST https://user.openalex.org/me/collections/{collection_id}/entities
Content-Type: application/json

{ "entity_ids": ["W123…", "W456…"] }
Returns { "added": N, "already_present": M, "rejected_wrong_type": 0 }. Wrong-type IDs (e.g. an A… in a works collection) fast-fail with 400 naming the first offender, so rejected_wrong_type is always 0 on success — it’s preserved in the response shape for backward compatibility.
# Bulk remove
DELETE https://user.openalex.org/me/collections/{collection_id}/entities
Content-Type: application/json

{ "entity_ids": ["W123…"] }
# Single remove via URL
DELETE https://user.openalex.org/me/collections/{collection_id}/entities/W123…

Admin endpoints

OpenAlex admins can list, read, edit, or delete any user’s collection:
MethodPathNotes
GET/admin/collections?q=&owner_id=&entity_type=Cross-user search, paged
GET/admin/collections/{collection_id}Read any collection
PATCH/admin/collections/{collection_id}Same body as the user PATCH
DELETE/admin/collections/{collection_id}Hard-delete with cascade
Non-admin callers get 403.

Validation rules

Collections are validated before they hit the database. The most common 400s:
CodeCause
entity_type_invalidentity_type missing or not one of the 10 supported types
display_name_invalidEmpty after trim, contains control characters, URL-shaped, or profane
display_name_too_longMore than 30 characters
display_name_duplicateYou already have a collection with this name (case-insensitive)
description_invalidNot a string, or contains control characters, or URL-shaped
entity_id_invalidAn ID doesn’t look like any OpenAlex ID shape
entity_id_wrong_typeAn ID’s type doesn’t match the collection’s entity_type
collection_fullAdding entities would exceed the 1,000-entity cap
too_many_collectionsYou already own 100 collections