Tes API endpoint
Searches Tes's (tes.com) teaching-resources marketplace. Returns listing facts (title, author, price, rating, downloads) -- not full listing descriptions. query is optional: omit it (alone, or combined with key_stage/subject/on_sale) for pure filter-driven or fully unfiltered browsing. sort mirrors the real search page's own Sort by dropdown; key_stage and subject mirror its left-hand Refine by filters (both closed, validated enums taken from Tes's own facet taxonomy, and always resolved against Tes's own single GB-taxonomy regardless of country). country controls result currency/localisation only (confirmed live for all seven values); it does not change which key_stage/subject values are valid.
/tes/resources/searchQuery parameters:
query (optional): search keywords, e.g. phonics. Omit for filter-driven or fully unfiltered browsing.country (optional, default GB): storefront market. One of GB, US, AU, IE, CA, NZ, UN.page (optional, default 1, 1-500): one-based page.page_size (optional, default 20, 1-50): results per page.sort (optional, default relevance): one of relevance, newest, highest_rated, lowest_price.key_stage (optional): filter by age range. One of 3-5, 5-7, 7-11, 11-14, 14-16, 16+, age_not_applicable.subject (optional): filter by subject. One of English, Mathematics, Science, Modern foreign languages, Geography, History, Religious education, Art, business and technology, Physical education, All languages, Anthropology, Citizenship, Classics, Computing, Cross-curricular topics, Government and politics, Law and legal studies, Media studies, New teachers, Pedagogy and professional development, Personal, social and health education, Philosophy and ethics, Physical development, Psychology, Sociology, Special educational needs, Understanding the world, Vocational studies, Whole school.on_sale (optional, default false): filter to discounted resources only.Notable response behavior:
total is the upstream's true result count across all pages, not just the current page's length.price is 0 and free is true for free resources.resource_types and file_types reflect Tes's own resource-type/file-type taxonomy and may be empty.is_bundle marks a listing that packages multiple resources under one price (Tes's own "Bundle" badge); bundle_resource_count and bundle_original_price are only meaningful when is_bundle is true.license is Tes's own short licence code: one of Paid, CC-BY-SA, CC-BY-ND, CC-BY.| Field | Filled in, of 40 checked | Values in the sample |
|---|---|---|
| id | 40 | |
| title | 40 | “Phonics roll and write” and 38 other values |
| url | 40 | tes.com |
| author | 40 | |
| price | 40 | 0 to 2, median 0 |
| currency | 40 | GBP in all 40 |
| free | 40 | true in 23 of 40 |
| on_sale | 40 | true in 0 of 40 |
| rating | 40 | 0 to 5, median 4.4 |
| rating_count | 40 | 0 to 47, median 1 |
| downloads | 40 | 2 to 20,102, median 848 |
| resource_types | 40 | median 1 entry |
| file_types | 40 | median 1 entry |
| thumbnail_url | 40 | d1e4pidl3fu268.cloudfront.net and 1 other host |
| first_published | 40 | 2010-10-09 to 2026-10-08 |
| last_published | 40 | 2010-10-09 to 2026-10-08 |
| is_bundle | 40 | true in 0 of 40 |
| license | 35 | Paid (17), CC-BY-SA (12), CC-BY-ND (6) |
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| query | string | No | Search keywords -- omit for filter-driven or unfiltered browsing | phonics | |
| country | string | No | Storefront market Allowed values: GB, US, AU, IE, CA, NZ, UN. | ||
| page | integer | No | One-based page Minimum: 1. Maximum: 500. | ||
| page_size | integer | No | Results per page Minimum: 1. Maximum: 50. | ||
| sort | string | No | Sort order Allowed values: relevance, newest, highest_rated, lowest_price. | ||
| key_stage | string | No | Filter by age range Allowed values: 3-5, 5-7, 7-11, 11-14, 14-16, 16+, age_not_applicable. | ||
| subject | string | No | Filter by subject -- one of Tes's own top-level subject facet labels; see the endpoint markdown for the full list (two of the 29 values contain a comma, which is why this parameter is not expressed as a Swagger Enums() list) Allowed values: . | English | |
| on_sale | boolean | No | Filter to discounted resources only | ||
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/tes/resources/search?query=coffee&country=us&page=1&sort=relevance&key_stage=3-5&subject=&on_sale=true" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"msg": "OK",
"data": {
"query": "phonics",
"country": "GB",
"page": 1,
"page_size": 20,
"total": 38150,
"resources": [
{
"id": "13463100",
"title": "Phonics Bunting",
"url": "https://www.tes.com/teaching-resource/phonics-bunting-13463100",
"author": "joannecrozierharbottle",
"price": 1,
"currency": "GBP",
"free": false,
"on_sale": false,
"rating": 0,
"rating_count": 0,
"downloads": 143,
"resource_types": [
"Visual aid/Display"
],
"file_types": [
"Image"
],
"thumbnail_url": "https://d1e4pidl3fu268.cloudfront.net/example/preview.png",
"first_published": "2026-05-03T21:00:33.987Z",
"last_published": "2026-05-03T21:00:33.987Z",
"is_bundle": false,
"license": "Paid"
}
]
}
}Request schema
No body schema
Response schema
#/definitions/tes.resourceSearchResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| code | integer | No | 200 | |||
| data | tes.ResourceSearchResponse | No | ||||
| data.country | string | No | ||||
| data.page | integer | No | ||||
| data.page_size | integer | No | ||||
| data.query | string | No | ||||
| data.resources | array | No | ||||
| data.resources[].author | string | No | ||||
| data.resources[].bundle_original_price | number | No | ||||
| data.resources[].bundle_resource_count | integer | No | ||||
| data.resources[].currency | string | No | ||||
| data.resources[].downloads | integer | No | ||||
| data.resources[].file_types | array | No | ||||
| data.resources[].first_published | string | No | ||||
| data.resources[].free | boolean | No | ||||
| data.resources[].id | string | No | ||||
| data.resources[].is_bundle | boolean | No | IsBundle marks a listing that packages multiple resources under one price, tes.com's own "Bundle" badge. BundleResourceCount and BundleOriginalPrice are only meaningful when IsBundle is true. | |||
| data.resources[].last_published | string | No | ||||
| data.resources[].license | string | No | License is Tes's own short licence code -- one of "Paid", "CC-BY-SA", "CC-BY-ND", "CC-BY" (its licence facet's own values, confirmed live 2026-09-04). | |||
| data.resources[].on_sale | boolean | No | ||||
| data.resources[].price | number | No | ||||
| data.resources[].rating | number | No | ||||
| data.resources[].rating_count | integer | No | ||||
| data.resources[].resource_types | array | No | ||||
| data.resources[].thumbnail_url | string | No | ||||
| data.resources[].title | string | No | ||||
| data.resources[].url | string | No | ||||
| data.total | integer | No | ||||
| msg | string | No | OK |
| Status | Description | Schema |
|---|---|---|
| 400 | Bad Request | #/definitions/app.Response |
| 429 | Too Many Requests | #/definitions/app.Response |
| 503 | Service Unavailable | #/definitions/app.Response |
Use environment variables for secrets and keep Crawlora API keys server-side.
curl -X GET "https://api.crawlora.net/api/v1/tes/resources/search?query=coffee&country=us&page=1&sort=relevance&key_stage=3-5&subject=&on_sale=true" \
-H "x-api-key: $CRAWLORA_API_KEY"