---
title: "Save library sources"
method: POST
path: "/library/sources"
tags: ["Library"]
---

# Save library sources

`POST /library/sources`

## Request

- Base URL: `https://elicit.com/api/v2`
- URL: `https://elicit.com/api/v2/library/sources`
- Auth: HTTP bearer

Saves 1–100 papers. Each item is one of: an `elicitId`; a `pdfUrls` entry, metadata optional; or a `title` with at least one of `doi`, `authors`, `year`, `venue`, `abstract`, `url`. A `doi` alone is rejected. Elicit fills missing metadata from its corpus or the parsed PDF. `pdfUrls` is how to attach a PDF: Elicit fetches and parses it in the background when the paper is not in the corpus. Do not download PDFs yourself; for local files, use imports.

The response lists each item in request order. An item that matches a paper already in your library returns that source with `created: false` and `duplicateOf` set. With `onDuplicate: skip` (default), fields the existing source lacked are filled from the item and listed in `updatedFields`. Existing values do not change. Adding `pdfUrls`, `doi`, or `elicitId` to an existing source starts enrichment for it again. With `onDuplicate: create`, a copy is saved and the pair is recorded as a potential duplicate. `collectionIds` adds every returned source to those collections; each source's `collections` reports, per collection, the id the collection holds for the paper and whether this call added it. A group collection holds its own copy under a different id, so the returned source's `collectionIds` does not list it.

Metadata and full text for new sources arrive asynchronously. A new source starts with `fullTextStatus: pending`. When `fullTextStatus` changes, enrichment is complete. A source that still has `title: null` at that point has an identifier that is not in the corpus.

### Example

```bash
curl -X POST https://elicit.com/api/v2/library/sources \
  -H "Authorization: Bearer elk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"sources":[{"title":"Semaglutide and cardiovascular outcomes in obesity without diabetes","doi":"10.1056/NEJMoa2307563"},{"title":"Attention Is All You Need","authors":["Ashish Vaswani"],"year":2017}],"collectionIds":["b458052a-84e2-4e47-b5c4-00e11390a265"]}'
```

## Request body

- object
  - `sources` CreateLibrarySourceItem[], required
    - union
      - CorpusReferenceItem: A paper from Elicit search, by `elicitId`. Other fields are optional.
        - `title` string
        - `authors` string[]
        - `year` integer
        - `venue` string
        - `abstract` string: Plain text or markdown; blank lines separate paragraphs.
        - `doi` string: Send the title and authors with it, so the record is useful if the DOI is not in Elicit's corpus.
        - `elicitId` string, required
        - `url` string, uri
        - `pdfUrls` string[]: Direct PDF links. Fetched and parsed when the paper is not in the Elicit corpus; a PDF URL alone is enough.
      - DocumentItem: A PDF by URL. Elicit parses it and fills the metadata; other fields are optional.
        - `title` string
        - `authors` string[]
        - `year` integer
        - `venue` string
        - `abstract` string: Plain text or markdown; blank lines separate paragraphs.
        - `doi` string: Send the title and authors with it, so the record is useful if the DOI is not in Elicit's corpus.
        - `elicitId` string
        - `url` string, uri
        - `pdfUrls` string[], required: Direct PDF links. Fetched and parsed when the paper is not in the Elicit corpus; a PDF URL alone is enough.
      - union: A paper by `title` plus at least one of `doi`, `authors`, `year`, `venue`, `abstract`, `url`.
        - object
          - `title` string, required
          - `authors` string[]
          - `year` integer
          - `venue` string
          - `abstract` string: Plain text or markdown; blank lines separate paragraphs.
          - `doi` string, required: Send the title and authors with it, so the record is useful if the DOI is not in Elicit's corpus.
          - `elicitId` string
          - `url` string, uri
          - `pdfUrls` string[]: Direct PDF links. Fetched and parsed when the paper is not in the Elicit corpus; a PDF URL alone is enough.
        - object
          - `title` string, required
          - `authors` string[], required
          - `year` integer
          - `venue` string
          - `abstract` string: Plain text or markdown; blank lines separate paragraphs.
          - `doi` string: Send the title and authors with it, so the record is useful if the DOI is not in Elicit's corpus.
          - `elicitId` string
          - `url` string, uri
          - `pdfUrls` string[]: Direct PDF links. Fetched and parsed when the paper is not in the Elicit corpus; a PDF URL alone is enough.
        - object
          - `title` string, required
          - `authors` string[]
          - `year` integer, required
          - `venue` string
          - `abstract` string: Plain text or markdown; blank lines separate paragraphs.
          - `doi` string: Send the title and authors with it, so the record is useful if the DOI is not in Elicit's corpus.
          - `elicitId` string
          - `url` string, uri
          - `pdfUrls` string[]: Direct PDF links. Fetched and parsed when the paper is not in the Elicit corpus; a PDF URL alone is enough.
        - object
          - `title` string, required
          - `authors` string[]
          - `year` integer
          - `venue` string, required
          - `abstract` string: Plain text or markdown; blank lines separate paragraphs.
          - `doi` string: Send the title and authors with it, so the record is useful if the DOI is not in Elicit's corpus.
          - `elicitId` string
          - `url` string, uri
          - `pdfUrls` string[]: Direct PDF links. Fetched and parsed when the paper is not in the Elicit corpus; a PDF URL alone is enough.
        - object
          - `title` string, required
          - `authors` string[]
          - `year` integer
          - `venue` string
          - `abstract` string, required: Plain text or markdown; blank lines separate paragraphs.
          - `doi` string: Send the title and authors with it, so the record is useful if the DOI is not in Elicit's corpus.
          - `elicitId` string
          - `url` string, uri
          - `pdfUrls` string[]: Direct PDF links. Fetched and parsed when the paper is not in the Elicit corpus; a PDF URL alone is enough.
        - object
          - `title` string, required
          - `authors` string[]
          - `year` integer
          - `venue` string
          - `abstract` string: Plain text or markdown; blank lines separate paragraphs.
          - `doi` string: Send the title and authors with it, so the record is useful if the DOI is not in Elicit's corpus.
          - `elicitId` string
          - `url` string, uri, required
          - `pdfUrls` string[]: Direct PDF links. Fetched and parsed when the paper is not in the Elicit corpus; a PDF URL alone is enough.
  - `collectionIds` string[]: Collections you own or can edit to add every returned source to, duplicates included.
  - `onDuplicate` 'skip' | 'create': skip (default): an item matching an already-saved source returns that source, updating any fields it lacked, instead of creating one. create: saves anyway and records a potential-duplicate pair for the app's review-duplicates flow.

## Response `200`

One entry per item, in request order.

- CreateLibrarySourcesResponse
  - `sources` CreatedLibrarySource[], required
    - `id` string, uuid, required: Stable id of the source.
    - `title` string, nullable, required
    - `authors` string[], required
    - `year` integer, nullable, required
    - `venue` string, nullable, required
    - `abstract` string, nullable, required: Abstract as markdown.
    - `doi` string, nullable, required
    - `url` string, nullable, required
    - `elicitId` string, nullable, required: Elicit corpus id, present once the paper has been matched to the corpus.
    - `pdfUrls` string[], required
    - `collectionIds` string[], required: Collections this source belongs to that are visible to you.
    - `role` 'writer' | 'reader', required: Your role on this source: `writer` for your own sources and for a shared collection's papers when you own or can edit that collection; `reader` for a shared collection's papers you can only view. Any role can read the source and use it in reviews. Writers edit metadata, attach a PDF, delete, and add to collections.
    - `fullTextStatus` 'pending' | 'available' | 'unavailable', required: Whether parsed full text is attached: pending — a PDF is still parsing, or none has been looked for yet; available — parsed and attached; unavailable — looked for, none found.
    - `createdAt` string, required
    - `updatedAt` string, required
    - `links` object, required
      - `self` string, required: API URL of this source.
      - `fullText` string, required: API URL of the parsed full text; 404s until fullTextStatus is available.

## Other responses

- `400`: A malformed id, or an unknown or invalid query parameter.
- `401`: Authentication failed. The API key is missing, invalid, revoked, or expired.
- `403`: API access is unavailable on your plan, or your role does not allow this action.
- `404`: The collection does not exist or is not visible to you.
- `429`: Rate limit exceeded. More than 100 requests per minute were received from your IP address; further requests are blocked for 5 minutes.
- `500`: An unexpected error occurred. Retry reads with backoff; before retrying a write, check whether it took effect. See Error Handling for retry guidance.

## Changes

- **2026-10-13** `27c80b9a3470`: 5 info
  - added the optional property `error/details` to the response with the `400` status
  - added the optional property `error/details` to the response with the `401` status
  - added the optional property `error/details` to the response with the `403` status
  - added the optional property `error/details` to the response with the `404` status
  - …1 more
- **2026-09-27** `9b5b75b828ab`: 5 info
  - added the optional property `error/sessionId` to the response with the `400` status
  - added the optional property `error/sessionId` to the response with the `401` status
  - added the optional property `error/sessionId` to the response with the `403` status
  - added the optional property `error/sessionId` to the response with the `404` status
  - …1 more
- **2026-09-15** `69b6844982c1`: 3 breaking, 9 warning, 3 info
  - removed `subschema #1, subschema #2, subschema #3` from the `sources/items/` request property `anyOf` list
  - the `sources/items/` request property type changed from `object` to no type
  - removed the required property `sources/items/allOf[#/components/schemas/LibrarySource]/ownedByMe` from the response with the `200` status
  - removed the request property `sources/items/abstract`
  - …11 more
- **2026-09-11** `acdbab329322`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/elicit/apis/elicit-api/changes/library/sources/post.md)

---

[API](https://skmtc.dev/elicit/apis/elicit-api.md) - [All operations](https://skmtc.dev/elicit/apis/elicit-api/llms.txt) - [OpenAPI document](https://skmtc.dev/elicit/apis/elicit-api/revisions/78db836edb9c?raw)
