Search

Search images — unified semantic + keyword

Unified search combining semantic similarity (vector embeddings) with keyword matching. No mode parameter — every query runs both. Use tags for multi-tag AND filtering; tag is still accepted for single-tag backward compatibility. Queries may be in any language: a non-English query is also searched in English, and the response names the English text (translated_query) and the detected language (query_language). When results carry match (strong or closest — query searches while the server has honest search on), strong matches come first, total counts them and has_more says whether to page on; without has_more, a page shorter than limit is the last.

get/v1/images/search

Request

  • Base URL: https://api.memestack.ai
  • URL: https://api.memestack.ai/v1/images/search
  • Auth: none declared

Query parameters

qstring

Search query (optional — omit to browse without a query)

limitinteger
offsetinteger
tagsstring

Comma-separated tag slugs for AND filtering (e.g. 'bitcoin,charts')

tagstring

Single tag slug filter — superseded by tags but still accepted for backward compatibility

uploader_idstring
sort_by'created_at' | 'zap_total_sats' | 'save_count' | 'trending'

Field to sort by

sort_order'asc' | 'desc'

Sort direction

in_text_onlyboolean

Search ONLY the OCR-extracted text inside images, ignoring captions, alt text, and tags. Requires q. A result whose text holds q as a phrase (case and punctuation ignored, starting on a word boundary; the last word may continue, so meme also finds memes) is labelled match: strong and comes first, and total counts exactly those; results holding the words apart, or close to them, follow as match: closest (closest=none omits them).

has_chart_databoolean

Restrict to images that have a stored chart-metadata row. Means 'a metadata row exists', NOT 'is a chart': charts with no stored metadata are excluded, so this under-returns against the true chart population.

chart_sourcestring

Restrict to one upstream chart source key: 'owid' (Our World in Data), 'usda_ers' (USDA Economic Research Service), 'eurostat' or 'eea' (European Environment Agency), or 'extracted' (community-uploaded charts whose title, source line and period were read from the image text, not checked against the original data). Implies has_chart_data.

data_frominteger

Earliest year of interest. Matches charts whose DISPLAYED period overlaps [data_from, data_to] - never the underlying dataset's wider history. A chart whose displayed period could not be proven from the image itself is excluded rather than guessed at. Implies has_chart_data. A malformed value is a 400.

data_tointeger

Latest year of interest. See data_from.

regionstring

Restrict to charts that plot this entity exactly as the chart names it, e.g. 'World', 'Germany'. Implies has_chart_data.

content'safe' | 'all'

Safe by default: 'safe' (the default) excludes images classified controversial, except the caller's own uploads; 'all' includes them, each carrying controversial: true. Case-insensitive; any other value is 400 INVALID_CONTENT. Send the same value on every page of one search.

closest'some' | 'none'

Honest search: some serves up to 24 closest matches after the strong ones (admin callers get every closest result); none serves strong matches only. Ignored when the server has honest search off.

autocorrectboolean

false skips the automatic spelling correction (the response then never carries corrected_query). Honoured whether or not honest search is on.

publisher_onlyboolean

true restricts the results to charts imported from a licence-clean publisher: Our World in Data (CC BY 4.0), the USDA Economic Research Service (U.S. public domain), Eurostat and the European Environment Agency (both CC BY 4.0). Community uploads, including copies of publisher charts, are left out. Every result's rights then has source: publisher. Applies to the semantic, keyword and text-in-image matching alike, and combines with the chart filters (AND). Case-insensitive; any value other than true or false is 400 INVALID_PUBLISHER_ONLY.

Response

Search results

countinteger
limitinteger

The page size used.

offsetinteger

The offset used.

filtersobject

The filters the search applied, echoed back (q, content, tags, sort_by, chart filters…); an unset filter is absent.

totalinteger

When results carry match: the number of STRONG matches (images with evidence of matching the query) — exact once has_more is false, otherwise a lower bound, never counting closest matches. Without labels: an approximate display count of every match; it does not end pagination (a page shorter than limit does).

has_moreboolean

Present when results carry match: true while more results follow this page. When absent, a page shorter than limit is the last.

match_quality'strong' | 'closest_only' | 'none'

Present with has_more (a query search with honest search on): whether the SEARCH found anything it has evidence for. strong = at least one strong match (they lead page 1; a later page can hold only closest ones, so read each result's match); closest_only = no strong match anywhere, every result is the nearest guess; none = no strong match and nothing on this page. An agent should not present a closest_only result as the answer.

corrected_querystring

Present when the query was automatically spelling-corrected. When results carry match, the correction runs whenever the searched window has zero strong results, at any offset, so paging stays on the correction; without labels, only when the page came back empty. Suppressed by autocorrect=false.

translated_querystring

Present only when the query was not English: the English text it was also searched as; those results are merged into this page.

query_languagestring

Present with translated_query: the ISO 639-1 code of the query language, e.g. "fr".

Example response

{
  "images": [
    {
      "id": "1b856382-7fdf-4afd-8f66-ae5972989d6d",
      "status": "approved",
      "mime_type": "image/jpeg",
      "width": 419,
      "height": 235,
      "thumb_width": 419,
      "thumb_height": 235,
      "caption": "The iconic 'This is Fine' meme featuring a dog sitting calmly in a room engulfed by flames.",
      "alt_text": "A two-panel comic strip showing a dog wearing a hat sitting at a table with a mug. The entire room is on fire with thick smoke at the ceiling. In the second panel, the dog smiles and a speech bubble says, 'THIS IS FINE.'",
      "tags": [
        {
          "tag": "meme",
          "name": "Meme",
          "score": 10
        },
        {
          "tag": "cartoon",
          "name": "Cartoon",
          "score": 10
        },
        {
          "tag": "artwork",
          "name": "Artwork",
          "score": 8
        }
      ],
      "free_tags": [
        {
          "tag": "this is fine",
          "name": "This Is Fine",
          "score": 10
        },
        {
          "tag": "kc green",
          "name": "Kc Green",
          "score": 9
        },
        {
          "tag": "dog",
          "name": "Dog",
          "score": 8
        }
      ],
      "text_in_image": "THIS IS FINE.",
      "meme_template_name": "This is Fine",
      "source_url": null,
      "zap_count": 0,
      "zap_total_sats": "0",
      "save_count": 0,
      "like_count": 0,
      "controversial": false,
      "is_ai_generated": false,
      "has_thumbnail": true,
      "has_canonical": false,
      "uploader_display_name": "BTC_Boi",
      "uploaded_as_creator": false,
      "rights": {
        "source": "community",
        "publisher": null,
        "license": null,
        "license_name": null,
        "license_url": null,
        "attribution": "Uploaded by BTC_Boi via MemeStack",
        "attribution_required": false,
        "commercial_use": "unknown",
        "note": "MemeStack grants no licence to this image: its rights belong to its owner, who is usually not MemeStack and often not the uploader. The attribution records where it was found, not who owns it."
      },
      "created_at": "2026-05-07T23:53:23.224Z",
      "updated_at": "2026-07-17T22:33:04.207Z"
    }
  ]
}

Changes

No recorded changes to this operation across all 1 revision of this API.