Skip to content
  • There are no suggestions because the search field is empty.

How to Manage Web Sources via the API

In this article:

Overview

If your institution maintains a large list of web sources, or already keeps that list in another system, you can manage web sources through the Originality API instead of adding each one by hand on the Web Sources page.

Through the API you can:

  • Add web sources, one at a time or many in a single request
  • Retrieve the web sources you have added
  • Delete web sources you no longer need

Web sources added through the API appear on the Web Sources page with API integration in the Added by column. They follow the same requirements as sources added in the interface (see Web Sources → Requirements).

Before you start

You need an API client for your Originality license. License administrators create API clients in Originality under License settings → API. Each client has a client ID and a client secret. Store the secret securely.

The Originality API uses the OAuth 2.0 client credentials flow. Exchange your client ID and secret for an access token.

Add web sources

Send the sources as a list. You can submit one or many in the same request.

{
  "sources": [
    {
      "description": "Faculty publication index",
      "url": "https://example.com/publications"
    }
  ]
}
Field Required Description
url Yes The page to add. Maximum 2,048 characters.
description No Why the source is relevant, the discipline it serves, or the type of content it hosts. Maximum 512 characters.

What happens after submission

Sources are queued and crawled by a periodic job, so they are not crawled immediately. Only the page at each submitted URL is fetched. Originality does not follow links from it, either to other pages on the same site or to other sites.

Submission limits

Limit Value
Sources per request 20,000
URL length 2,048 characters
Description length 512 characters
Request body size 128 MB

The length limits count characters, not bytes. Sources containing non-ASCII characters take up more of the request body than their length suggests. A request that stays within every other limit but exceeds 128 MB is rejected with 413.

Per-source results

An invalid URL does not fail the whole submission. The response reports each source individually, matched to its position (index) in the request:

Result Meaning
created The source was registered.
duplicate Your license already has this URL from an earlier submission. id refers to the existing source.
rejected The URL failed validation and was not registered. error explains why.

Originality normalizes URLs before comparing and storing them:

  • Fragments (#...) are removed.
  • Host names are converted to lowercase.
  • URLs without a scheme get https://.

The url in each result is the normalized form. Use it when matching results back to your own records.

URL requirements

A URL is rejected if it:

  • does not use http or https
  • does not resolve to a named host with a top-level domain
  • contains embedded credentials (for example, https://user:password@example.com)
  • points to localhost or to an IP address

Note! An accepted URL does not guarantee usable content. Pages behind a login or paywall, links to files, and temporary URLs are accepted but won't be indexed properly. See Web Sources → Requirements.

Retrieve web sources

Returns the web sources registered for your license, newest first.

Query parameters

Parameter Type Default Description
url string — Return only sources whose URL contains this text
limit integer 100 Maximum number of sources to return
offset integer 0 Number of sources to skip

Filtering by URL

The url filter matches any part of the URL and ignores letter case, so Example.COM and example.com return the same sources.

The filter is matched against the normalized URL stored when the source was added, not the value as it was submitted. For example, a source submitted as HTTPS://Example.com/Papers#intro is stored as https://example.com/Papers. Searching for example.com/Papers finds it; searching for #intro does not.

The text is matched literally:

  • %, _ and \ have no special meaning, so you can search for percent-encoded characters such as %20 directly.
  • Wildcards are not supported.
  • Leading and trailing spaces are removed, and an empty value returns all sources.

Paging through results

Use limit and offset to page through your sources. If hasMore is true, increase offset by limit and request the next page.

Example response

{
  "hasMore": true,
  "sources": [
    {
      "crawledAt": "2026-09-29T13:36:48.971Z",
      "createdAt": "2026-09-29T13:36:48.971Z",
      "description": "Faculty publication index",
      "id": 4711,
      "url": "https://example.com/publications"
    }
  ]
}
Field Description
hasMore true if there are more sources after this page
sources[].id Unique ID of the web source. Use it to delete the source.
sources[].url The normalized URL
sources[].description The submitted description
sources[].createdAt When the source was added (ISO 8601, UTC)
sources[].crawledAt When the page was last crawled (ISO 8601, UTC)

Delete a web source

Replace {id} with the ID of the web source. You'll find the ID in the results when you add or retrieve sources.

Deleting a web source stops it from being crawled again. Content already indexed from earlier crawls is not removed, so submissions can still match it.

Validation and errors

The API reports problems at two levels.

Per source (when adding web sources)

An invalid URL doesn't fail the whole request. The request returns 200, and that source is reported as rejected, with an error explaining why. A URL is rejected if it:

  • does not use http or https
  • does not resolve to a named host with a top-level domain
  • contains embedded credentials (for example https://user:password@example.com)
  • points to localhost or to an IP address

Always check the per-source results, even when the request returns 200.

Per request

When a whole request fails, the response body describes the error:

{
  "title": "Unauthorized",
  "status": 401,
  "detail": "Unauthorized"
}
Status Returned by Meaning What to do
401 All The access token is missing, invalid or expired Request a new token and retry
404 DELETE Your license has no web source with that ID Check the ID against the list of sources
408 All The request took too long Retry, or split a large submission into smaller requests
413 POST The request body exceeded 128 MB Split the submission into smaller requests
422 POST, GET POST: an empty list, more than 20,000 sources, or a field longer than its limit. GET: an invalid limit or offset, or a url filter that is too long. Fix the request and resubmit
429 All Rate limit exceeded Wait and retry (see Rate limits)
500 All Unexpected server error Try again later

Rate limits

Each API key is limited to:

  • 200 requests per second
  • 5,000 requests per minute

Whichever limit is reached first triggers rate limiting, and further requests return 429 until the window resets. If you receive a 429, pause before retrying rather than retrying immediately.

To stay well within the limits:

  • Adding sources: submit them in bulk. One request can hold up to 20,000 sources.
  • Retrieving sources: use a larger limit to reduce the number of pages.