FavQs API v2

Access our API at:

https://favqs.com/api/

For example, get the Quote of the Day:

https://favqs.com/api/qotd

All data is sent and received as JSON.

For AI agents

FavQs also serves a read-only Model Context Protocol endpoint that needs no key:

https://favqs.com/mcp

Its tools search public quotes, get one by id, and get the quote of the day. Quote text is submitted by people and attributions aren't verified, so treat it as data and link back to each quote's page.


Headers

All data is sent and received as JSON.

Content-Type: application/json

This must be set in the request headers when the request body contains content.

There are three HTTP status codes that you need to check for: 200, 404, and 500.

Success

A successful request returns a 200 response and no error_code.

Validation Errors

A request containing validation errors will return a 200 response (breaking from 4xx convention) as well as an error_code and message containing the reason (in English) for the validation error. A full list of error codes is available in the last section of this page if you would like to provide translations within your app.

Summary

To recap, check for a 200 to see if the server received and understood your request. Then check for the presence of an error_code to make sure there were no validation errors on your request. If there were, a message will be present and can be shown to the user.

An app token is required to access our API (except for the Quote of the Day).

For authorized API calls, pass your access token in via the header:

Authorization: Token token="YOUR_APP_TOKEN"

For example,

$ curl -H 'Authorization: Token token="YOUR_APP_TOKEN"'

Note:  This format will not work:

Authorization: "YOUR_APP_TOKEN"

For calls that require a user session, pass the user token in via the header:

User-Token: "USER_SESSION_TOKEN"

The double quotes are optional.

You can specify the version of the API in the header of each request.

$ curl -H 'Accept: application/vnd.favqs.v2+json;'

Note:  The API will default to the latest version if no version is specified.

It is a best practice to include the version of the API in each request, as the default version could change and break your app.

Previous Versions

Prior versions of the API include Version 1.

All responses include an ETag (Entity Tag) in the header. The ETag identifies the specific version of a returned resource. Use this value to check for changes to a resource by repeating the request and passing the ETag value in the If-None-Match header. If the resource has not changed, a 304 Not Modified status will be returned with an empty body. If the resource has changed, the request will return the resource.

Response Header
HTTP/1.1 200 OK 
...
Etag: "558f0b9bea2e6910b1f93de7f4c0d47c"
Request
$ curl -I -H 'If-None-Match: "558f0b9bea2e6910b1f93de7f4c0d47c"'
HTTP/1.1 304 Not Modified

Access to the API is rate limited. Each session is allowed 30 requests in a 20 second interval.

The remaining number of requests is returned in the HTTP header 'Rate-Limit-Remaining'.

Response Header
HTTP/1.1 200 OK 
...
Rate-Limit-Remaining: 24

Session

A user can only have one session per app token. If you have more than one app, please request another app token.

To create a session for the user, inside your application:

Request
POST /api/session
Request Body

Note: A user can login with their username or email address.

{ 
  "user": {
    "login": "login_or_email_here",
    "password": "user_password_here"
  }
}
Response Body
{ 
  "User-Token": "i4dwXAUNfSUEaTP90K5RWOWLap5cvc9mtjfpvA+c0uufP5GYnpYZUO4k5pTEpwsJHVHNhY5lbLn0cDRpiwsOKA==",
  "login": "user_login",
  "email": "user_email"
}

The "User-Token" should be added to the header for requests that require a user session.

Errors

An invalid login or password will return an error:

{ 
  "error_code": 21,
  "message": "Invalid login or password."
}

An account that has been deactivated will return an error:

{ 
  "error_code": 22,
  "message": "Login is not active. Contact support@favqs.com."
}

A request with missing data will return an error:

{ 
  "error_code": 23,
  "message": "User login or password is missing."
}

To destroy a user session (logout):

Request
DELETE /api/session
Response Body
{ 
  "message": "User logged out."
}
Error

If the user revokes account access to your app from their FavQs.com account page, you will see:

{ 
  "error_code": 20,
  "message": "No user session found."
}

Users

To create a new user:

Request
POST /api/users
Request Body
{ 
  "user": {
    "login": "user_login_here",
    "email": "user_email_here",
    "password": "user_password_here"
  }
}
Validations
Login
  • Can only contain letters (a-z), numbers (0-9) and the underscore (_)
  • Length must be between 1 and 20 characters
  • Email
  • Must be a valid email address
  • Password
  • Length must be between 5 and 120 characters
  • Response Body

    Successful creation of a user will return a session token for that user.

    { 
      "User-Token": "i4dwXAUNfSUEaTP90K5RWOWLap5cvc9mtjfpvA+c0uufP5GYnpYZUO4k5pTEpwsJHVHNhY5lbLn0cDRpiwsOKA==",
      "login": "user_login"
    }

    The "User-Token" should be added to the header for requests that require a user session.

    Errors

    If a user session already exists, you will get an error:

    { 
      "error_code": 31,
      "message": "User session present."
    }

    If any of the fields contain validation errors, message will contain a list of validation errors separated by a semi-colon.

    {
      "error_code": 32,
      "message": "Email is not a valid email; Password is too short (minimum is 5 characters)"
    }

    To get a user:

    Request
    GET /api/users/:login
    Response

    A user session may query any user.

    {
      "login": "gose",
      "pic_url": "https://favqs.com/avatars/3b20421651.svg",
      "public_favorites_count": 520,
      "followers": 12,
      "following": 23,
      "pro": true
    }
    Response

    Note:  User session required

    If you request the user of the current user session, you will also get "account_details".

    {
      "login": "gose",
      "pic_url": "https://favqs.com/avatars/3b20421651.svg",
      "public_favorites_count": 520,
      "followers": 12,
      "following": 23,
      "pro": true,
      "account_details": {
        "email": "gose@favqs.com",
        "private_favorites_count": 22,
        "pro_until": "2027-03-13T12:19:06.133Z",
        "pro_source": "app_store",
        "account_uuid": "6f1c2a3e-8d4b-4e5f-9a7b-1c2d3e4f5a6b",
        "pro_expiration": "2027-03-13T12:19:06.133Z"
      }
    }

    pro_until andpro_source say when the user's FavQs Pro ends and where it's managed:stripe,app_store orgoogle_play. Both are null without Pro.account_uuid is the account's lasting ID, which an app gives the store with each purchase.pro_expiration repeatspro_until for older clients, and appears only with Pro.

    Note:  User session required

    To update a user:

    Request
    PUT /api/users/:login
    Request Body

    All fields are optional.

    { 
      "user": {
        "login": "user_login_here",
        "email": "user_email_here",
        "password": "user_password_here",
        "twitter_username": "twitter_username_here",
        "facebook_username": "facebook_username_here",
        "pic": "twitter",
        "profanity_filter": false
      }
    }
    Validations

    Additional validations are listed under 'Create User'.

    Pic
  • Either ["twitter", "facebook", "gravater", ""]
  • Profanity Filter
  • Must be either [true, false]. True means it's enabled (default).
  • Response Body
    { 
      "message": "User successfully updated."
    }

    Profile Pics

    Every user's "pic_url" is an SVG avatar FavQs draws: a small face whose colors and features come from the account. FavQs no longer shows Gravatar, Twitter or Facebook pictures, so "pic", "twitter_username" and "facebook_username" are accepted but have no effect.

    Errors

    If there is a validation error, one or more validation errors will be returned:

    {
      "error_code": 32,
      "message": {
        "login": [
          "has already been taken"
        ],
        "email": [
          "is not a valid email"
        ]
      }
    }

    To request a password reset.

    Request
    POST /api/users/forgot_password
    Request Body
    { 
      "user": {
        "email": "user_email_here"
      }
    }
    Response Body
    { 
      "message": "A reset link has been emailed."
    }
    Errors

    If the user login or email is not found, a 404 will be returned.

    { 
      "error_code": 30,
      "message": "User not found."
    }

    To reset a password:

    Request
    POST /api/users/reset_password
    Request Body
    { 
      "user": {
        "email": "user_email_here",
        "reset_password_token": "user_reset_password_token_here"
      }
    }
    Response Body
    { 
      "message": "Password successfully updated. Please login."
    }
    Errors

    If the password reset token is invalid:

    { 
      "error_code": 33,
      "message": "Invalid password reset token."
    }

    People buy FavQs Pro on favqs.com, or in the FavQs apps through the App Store or Google Play. It's one Pro on the account, wherever it was bought; Get User'saccount_details says when it ends and where it's managed.

    To describe FavQs Pro, with its features and the store products that sell it (prices come from each store, or from favqs.com):

    GET /api/v3/plans

    The pricing page sells it on the web. The old per-user URL, /users/:login/pro, redirects there.

    GET /pricing

    For the FavQs apps: send each StoreKit 2 transaction for FavQs Pro, signed as the App Store gave it, after a purchase, a renewal or a restore, and at launch for any not yet finished. Set the purchase'sappAccountToken to the user'saccount_uuid. Sending the same transaction twice is harmless.

    Request
    POST /api/purchases/app_store
    Request Body
    {
      "signed_transaction": "eyJhbGciOiJFUzI1NiIsIng1YyI6Wy..."
    }
    Response Body

    The user, as Get User gives it, with their Pro in account_details; or error 25, 26 or 27, whose message is written to show the person.

    For the FavQs apps: send each Google Play purchase of FavQs Pro after it's made, and any still unacknowledged at launch or sign-in. Set the purchase'sobfuscatedAccountId to the user'saccount_uuid. FavQs confirms the purchase with Google and acknowledges it; the app never does. A purchase awaiting payment answers with the user, without Pro, to be sent again later.

    Request
    POST /api/purchases/google_play
    Request Body
    {
      "purchase_token": "opaque-token-from-play-billing",
      "product_id": "com.favqs.app.pro"
    }
    Response Body

    The user, as Get User gives it, with their Pro in account_details; error 25, 26 or 27, final, whose message is written to show the person; or error 28 with HTTP 503, to send it again later.


    Typeahead

    This resource provides a list of the public Authors, Tags, and Users in FavQs.

    With this data, typeahead can be performed locally giving the user a fast response.

    Request
    GET /api/typeahead
    Response
    {
      "authors": [
        {
          "count": 118,
          "permalink": "mark-twain",
          "name": "Mark Twain"
        },
        ...
      ],
      "tags": [
        {
          "count": 44,
          "permalink": "funny",
          "name": "funny"
        },
        ...
      ],
      "users": [
        {
          "count": 432,
          "permalink": "gose",
          "name": "gose"
        },
        ...
      ]
    }

    Quotes

    Get the Quote of the Day. Each date has one quote, the same for everyone. Passdate (YYYY-MM-DD) to follow a reader's local day; without it, the date is today in UTC. Dates from yesterday through 31 days ahead always have a quote; earlier dates return the quote they had, if any. A date without a quote returns error code 80 with a 404, and a malformed date returns error code 10 with a 400.

    Request
    GET /api/qotd?date=2026-11-01
    Example
    $ curl https://favqs.com/api/qotd
    Response
    {
      "qotd_date": "2026-11-01T00:00:00.000+00:00",
      "quote": {
        "id": 17025,
        "favorites_count": 0,
        "dialogue": false,
        "favorite": false,
        "tags": [
          "equality",
          "men"
        ],
        "url": "http://localhost:3000/quotes/abraham-lincoln/17025-fourscore-and-",
        "upvotes_count": 1,
        "downvotes_count": 0,
        "author": "Abraham Lincoln",
        "author_permalink": "abraham-lincoln",
        "body": "Fourscore and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal."
      }
    }

    A list of quotes, paged 25 at a time.

    Request
    GET /api/quotes
    Response
    {
      "page": 1,
      "last_page": false,
      "quotes": [
        {
          "tags": [
            "linux",
            "programming",
            "code",
            "finnish-american"
          ],
          "favorite": false,
          "author_permalink": "linus-torvalds",
          "body": "Talk is cheap. Show me the code.",
          "id": 253,
          "favorites_count": 1,
          "upvotes_count": 0,
          "downvotes_count": 0,
          "dialogue": false,
          "author": "Linus Torvalds",
          "url": "https://favqs.com/quotes/linus-torvalds/253-talk-is-cheap-s-"
        },
        ...
      ]
    }

    Optional URL Parameters

    The list of quotes can be refined via these filters.

    ParameterDescription
    filterType lookup or keyword search
    type['author', 'tag', 'user']
    privateGet private quotes for the pro user session (e.g., private=true)
    hiddenGet hidden quotes for the user session (e.g., hidden=true)
    pagePage number (25 quotes per page)

    Examples

    Get a random list of quotes:

    GET https://favqs.com/api/quotes/

    Search for quotes containing the word "funny":

    GET https://favqs.com/api/quotes/?filter=funny

    Get quotes that are tagged with "funny":

    GET https://favqs.com/api/quotes/?filter=funny&type=tag

    Get quotes by Mark Twain:

    GET https://favqs.com/api/quotes/?filter=Mark+Twain&type=author

    Get the public quotes favorited by user 'gose':

    GET https://favqs.com/api/quotes/?filter=gose&type=user

    Get the private quotes of the current user (pro session required):

    GET https://favqs.com/api/quotes/?private=1

    Search for private quotes of the current user session that contain the words "little book":

    GET https://favqs.com/api/quotes/?filter=little+book&private=1

    Get quotes hidden by the user:

    GET https://favqs.com/api/quotes/?hidden=1

    Request
    GET /api/quotes/:quote_id
    Response Body
    {
      "id": 4,
      "author": "Albert Einstein",
      "body": "Make everything as simple as possible, but not simpler.",
      ...
    }

    To mark a quote as a user's favorite:

    Request
    PUT /api/quotes/:quote_id/fav
    Response Body
    {
      "id": 4,
      "author": "Albert Einstein",
      "body": "Make everything as simple as possible, but not simpler.",
      ...
      "user_details": {
        "favorite": true,
        ...
      }
    }
    Errors
    { 
      "error_code": 40,
      "message": "Quote not found."
    }
    Request

    To unmark a quote as a user's favorite:

    PUT /api/quotes/:quote_id/unfav
    Response Body
    {
      "id": 4,
      "author": "Albert Einstein",
      "body": "Make everything as simple as possible, but not simpler.",
      ...
      "user_details": {
        "favorite": false,
        ...
      }
    }
    Errors
    { 
      "error_code": 41,
      "message": "Private quotes cannot be unfav'd."
    }

    Users can vote a quote up or down to influence that quotes popularity.

    Vote a quote up:

    Request
    PUT /api/quotes/:quote_id/upvote
    Response Body
    {
      "id": 4,
      "author": "Albert Einstein",
      "body": "Make everything as simple as possible, but not simpler.",
      ...
      "user_details": {
        "upvote": true,
        "downvote": false,
        ...
      }
    }

    Vote a quote down:

    Request
    PUT /api/quotes/:quote_id/downvote
    Response Body
    {
      "id": 4,
      "author": "Albert Einstein",
      "body": "Make everything as simple as possible, but not simpler.",
      ...
      "user_details": {
        "upvote": false,
        "downvote": true,
        ...
      }
    }

    To clear the vote on a quote:

    Request
    PUT /api/quotes/:quote_id/clearvote
    Response Body
    {
      "id": 4,
      "author": "Albert Einstein",
      "body": "Make everything as simple as possible, but not simpler.",
      ...
      "user_details": {
        "upvote": false,
        "downvote": false,
        ...
      }
    }

    To add Personal Tags to a quote:

    Request
    PUT /api/quotes/:quote_id/tag

    The list of tags sent must include all of the user's personal tags for that quote.

    Request Body
    {
      "personal_tags": [
        "simplicity",
        "minimalism"
      ]
    }

    If a tag is missing from the list, that personal tag will be removed from the quote.

    Response Body
    {
      "id": 4,
      "author": "Albert Einstein",
      "body": "Make everything as simple as possible, but not simpler.",
      ...
      "user_details": {
        "personal_tags": [
          "simplicity",
          "minimalism"
        ]
        ...
      }
    }

    To hide a quote:

    Request
    PUT /api/quotes/:quote_id/hide
    Response Body
    {
      "id": 4,
      "author": "Albert Einstein",
      "body": "Make everything as simple as possible, but not simpler.",
      ...
      "user_details": {
        "hidden": true,
        ...
      }
    }

    To unhide a quote:

    Request
    PUT /api/quotes/:quote_id/unhide
    Response Body
    {
      "id": 4,
      "author": "Albert Einstein",
      "body": "Make everything as simple as possible, but not simpler.",
      ...
      "user_details": {
        "hidden": false,
        ...
      }
    }

    Quotes added by Pro users are private initially and can be edited.

    Quotes added by non-Pro users are public and cannot be edited.

    To add a quote:

    Request
    POST /api/quotes
    Request Body
    {
      "quote": {
        "author": "Mark Twain",
        "body": "Never let your schooling interfere with your education."
      }
    }

    Add"private": true to keep the quote to the user, which takes FavQs Pro (error 24 otherwise), or"private": false to share it. Withoutprivate, a Pro user's quote is private and anyone else's public.

    To add a dialogue:

    Request
    POST /api/quotes
    Request Body
    {
      "quote": {
        "lines": [
          {
            "author": "State Trooper",
            "body": "Pullover!"
          },
          {
            "author": "Harry Dunne",
            "body": "No, it's a cardigan but thanks for noticing."
          },
          {
            "author": "Lloyd Christmas",
            "body": "Yeah, killer boots man!"
          }
        ],
        "source": "Dumb & Dumber, 1994. Film",
        "context": "While being pulled over by a State Trooper on a motorcycle.",
        "tags": "funny, movie, dumb and dumber, police"
      }
    }
    Response Body

    The response is the same as Get Quote.

    {
      "id": 123,
      "author": "Mark Twain",
      "body": "Never let your schooling interfere with your education."
      ...
    }

    Updating a quote or dialogue requires the same request format as adding a quote.

    Request
    PUT /api/quotes/:quote_id
    Response

    The response is the same as Get Quote.

    To delete a quote:

    Request
    DELETE /api/quotes/:quote_id
    Response Header
    HTTP/1.1 200 OK 

    To make a quote public:

    Request
    PUT /api/quotes/:quote_id/publicize

    Once a quote is public, it cannot be edited and others will be able to see, fav it, etc.

    Response Body
    {
      "id": 4,
      "author": "Albert Einstein",
      "body": "Make everything as simple as possible, but not simpler.",
      "private": false
      ...

    Activity

    Get the activity of a user, tag, or author, sorted by recency.

    Request
    GET /api/activities/

    If a user session is present and no parameters are given, the activites for that user will be returned.

    URL Parameters

    ParameterDescription
    filterType lookup
    type['author', 'tag', 'user']
    pagePage number (25 activities per page)
    Response Body
    {
      "activities": [
        {
          "activity_id": 427,
          "owner_type": "User",
          "owner_id": "gose",
          "owner_value": "gose",
          "action": "favorited",
          "trackable_id": 61003,
          "trackable_type": "Quote",
          "trackable_value": "Pleasure in the job puts perfection in the work. - Aristotle",
          "message": "User gose favorited Quote \"Pleasure in the job puts perfection in the work.\" - Aristotle" 
        },
        {
          "activity_id": 426,
          "owner_type": "User",
          "owner_id": "gose",
          "owner_value": "gose",
          "action": "followed",
          "trackable_id": "chicago",
          "trackable_type": "Tag",
          "trackable_value": "chicago",
          "message": "User gose followed Tag chicago"
        },
        ...
      ]
    }

    Examples

    Get the activities of user 'gose':

    GET https://favqs.com/api/activities/?type=user&filter=gose

    Get the activities of author Mark Twain:

    GET https://favqs.com/api/activities/?type=author&filter=Mark+Twain

    Get the activities of tag "funny":

    GET https://favqs.com/api/activities/?type=tag&filter=funny

    To delete an activity entry:

    Request
    DELETE /api/activities/:activity_id

    Successful requests return a 200 OK and empty body.

    To follow a user, tag, or author:

    Request
    PUT /api/activities/follow/

    To unfollow a user, tag, or author:

    Request
    PUT /api/activities/unfollow/

    Required URL Parameters

    ParameterDescription
    filterType lookup
    type['author', 'tag', 'user']

    Successful requests return a 200 OK.

    To get the followers for a user, tag, or author:

    Request
    GET /api/activities/followers/

    Required URL Parameters

    ParameterDescription
    filterType lookup
    type['author', 'tag', 'user']

    For example, get users who follow user 'gose':

    GET https://favqs.com/api/activities/followers?type=user&filter=gose
    Response Body
    {
      "page": 1,
      "last_page": true,
      "users": [
        "david",
        "michael",
        "john"
      ]
    }

    Get users who follow tag 'funny':

    GET https://favqs.com/api/activities/followers?type=tag&filter=funny

    Get users who follow author 'Mark Twain':

    GET https://favqs.com/api/activities/followers?type=author&filter=mark-twain

    To get a list of users, tags, and authors a user is following:

    Request
    GET /api/activities/following/

    Only users can follow authors, tags, and other users.

    Response Body
    {
      "page": 1,
      "last_page": true,
      "following": [
        {
          "following_type": "Author",
          "following_id": "mark-twain",
          "following_value": "Mark Twain"
        },
        {
          "following_type": "Tag",
          "following_id": "society",
          "following_value": "society"
        },
        {
          "following_type": "User",
          "following_id": "david",
          "following_value": "david"
        }
      ]
    }

    Optional URL Parameters

    ParameterDescription
    userUsername

    To see who is following the current user:

    GET https://favqs.com/api/activities/following

    To see who is following user 'gose':

    GET https://favqs.com/api/activities/following/?user=gose

    Errors

    Successful requests return a 200 OK response, and no error_code.

    If your request returns a 200 OK and an error_code, the request could not be completed.

    Response Body
    { 
      "error_code": 21,
      "message": "Invalid login or password."
    }

    An additional message will indicate the reason, but you can present your own message based off the error_code.

    Error Codes
    10Invalid request.
    11Permission denied.
    20User session not found.
    21Invalid login or password.
    22Login is not active. Contact support@favqs.com.
    23User login or password is missing.
    24Pro user required
    25The App Store purchase couldn't be verified.
    26The App Store subscription belongs to another FavQs account.
    27The purchase was made for another FavQs account.
    28Google Play can't be asked right now; send the purchase again later. (HTTP 503)
    30User not found.
    31User session already present.
    32A list of 'user' validation errors.
    33Invalid password reset token.
    40Quote not found.
    41Private quotes cannot be unfav'd.
    42Could not create quote.
    50Author not found.
    60Tag not found.
    70Activity not found.
    80No quote of the day for that date.

    Additional error scenarios include non-200 codes in the response header.

    404HTTP/1.1 404 Not Found
    500HTTP/1.1 500 Internal Server Error

    Request API Key

    By using the FavQs API, you agree to our:

    Follow these steps to request access:

    1. Sign up for an account
    2. Visit your API Keys page