Reseller API is an API, where the Resellers can list, search and buy videos from Glymt.
The Reseller API lets your platform browse and search Glymt's catalogue, read every video's metadata, show its cover and its unbranded previews in two resolutions, and license a video for 20 credits to download the unwatermarked file. API version 1.0; https only — http is refused.
API clients are issued by Glymt on request. Glymt reviews the request and issues a client ID and secret.
Every request of the Reseller API goes to this base URL. Only https is accepted: a request over http is refused.
Every answer is JSON with its own HTTP status. An unknown path under the base answers 404 with
{"error": "not_found", "documentation": …}.
https://api.glymt.com/reseller/v1The Reseller API uses OAuth 2.0 client credentials (RFC 6749 §4.4). Glymt issues your platform a client ID and a client secret. The secret is shown once, when it is issued: keep it on your server, never in a browser or an app. If it is lost or exposed, ask us for a new one — the old one stops working at once and every token issued with it is revoked. Glymt can also revoke a token or a client on request.
Request a token from POST /oauth/token with grant_type=client_credentials, authenticating the client with
HTTP Basic (client_id:client_secret) — or with client_id and client_secret in the form body,
never both. A user's username or password is never accepted.
Send the token on every other call in the header Authorization: Bearer {access_token}. A token lasts
7200 seconds (expires_in); when it expires, request a new one the same way. A token of the Reseller
API is refused by the Submitter API, and a Submitter API token is refused here (401 invalid_token).
Errors of the token request (RFC 6749 §5.2): 400 invalid_request (no grant_type, user credentials sent, the client
sent twice), 400 unsupported_grant_type, 401 invalid_client (unknown client, wrong secret, a client or
owner that is not active), with WWW-Authenticate. Errors of every other call: 401 invalid_token (no token,
unknown, expired, revoked, or issued for the other API) and 403 insufficient_scope, with
WWW-Authenticate: Bearer.
curl -s -X POST https://api.glymt.com/reseller/v1/oauth/token \
-u '{client_id}:{client_secret}' \
-d grant_type=client_credentials
curl -s -X POST https://api.glymt.com/reseller/v1/oauth/token \
-d grant_type=client_credentials \
-d client_id={client_id} \
--data-urlencode client_secret={client_secret}
{
"access_token": "{access_token}",
"token_type": "Bearer",
"expires_in": 7200,
"scope": "reseller"
}
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Glymt Reseller API"
{ "error": "invalid_client", "error_description": "Client authentication failed." }
curl -s https://api.glymt.com/reseller/v1/account/summary \
-H 'Authorization: Bearer {access_token}'
Every endpoint has its own path. Base URL https://api.glymt.com/reseller/v1.
| Method | Path | Endpoint |
|---|---|---|
| GET | / |
welcome (name, version, documentation URL; no token) |
| POST | /oauth/token |
token (OAuth 2.0 client credentials; no Bearer) |
| GET | /videos/browse |
browse the client's catalogue |
| GET | /videos/search |
full-text search (OpenSearch) |
| GET | /videos/details/:video_id |
all metadata of one video |
| POST | /ai_search/start |
start an AI search (text and/or up to 2 images) |
| GET | /ai_search/results/:search_id |
poll / read an AI search |
| POST | /licenses/purchase |
license a video (credits debited) |
| GET | /licenses/list |
this client's licences |
| GET | /licenses/download_link/:licence_id |
120 s download link of a held licence |
| GET | /licenses/model_releases/:licence_id |
the licensed video's model releases |
| GET | /account/summary |
credits and statistics, read only |
The catalogue lists videos whose unbranded previews are ready; it grows as previews are generated. Your catalogue
is the published videos whose creators allow your client's type (stock, training or other). Every URL is absolute (https on
glymt.com); an asset that does not exist yet is null, never a broken URL. Watermarked previews and the original file
are never in an object: the unwatermarked file is reached only through a licence's download link.
| Field | Type | Meaning |
|---|---|---|
id | integer | the video's id (the video_id of every other endpoint) |
token | string | the video's public token |
title | string | its title |
duration | number | seconds |
fps | integer | frames per second |
resolution_width, resolution_height | integer | the original's pixels |
orientation | string | landscape | portrait | square |
has_audio | boolean | the video has a sound track |
is_ai | boolean | the video is AI-generated |
price_credits | integer | always 20 — every licence costs 20 credits |
licensed | boolean | your account already holds a licence for it |
assets.cover.small, .medium, .large | URL or null | the cover image in three sizes |
assets.preview_sd | URL or null | the unbranded preview, 570×320 |
assets.preview_hd | URL or null | the unbranded preview, 1920×1080 |
{
"id": {video_id},
"token": "{video_token}",
"title": "{video_title}",
"duration": 12.0,
"fps": 25,
"resolution_width": 1920,
"resolution_height": 1080,
"orientation": "landscape",
"has_audio": true,
"is_ai": false,
"price_credits": 20,
"licensed": false,
"assets": {
"cover": {
"small": "https://glymt.com/{cover_small_path}",
"medium": "https://glymt.com/{cover_medium_path}",
"large": "https://glymt.com/{cover_large_path}"
},
"preview_sd": "https://glymt.com/uploads/video/{video_id}/unbranded_sd.mp4",
"preview_hd": "https://glymt.com/uploads/video/{video_id}/unbranded_hd.mp4"
}
}
Every VideoCard field, and:
| Field | Type | Meaning |
|---|---|---|
description | string | its description |
keywords | array of strings | the published keywords |
categories | array of strings | the category names |
location | array of strings or null | place names (city, country) when known — never coordinates |
model_release_count | integer | the model releases attached to the video |
created_at, published_at | ISO 8601 UTC | when it was uploaded and published |
licence_id | integer or null | your licence for it, when you hold one |
| Field | Type | Meaning |
|---|---|---|
id | integer | the licence id (licence_id) |
video_id | integer | the licensed video |
price_credits | integer | the credits it debited (20) |
created_at | ISO 8601 UTC | when it was purchased |
/videos/browse, /videos/search and /ai_search/results/:search_id take the same query
parameters. An unknown parameter or a malformed value is 400 invalid_request — never ignored.
| Parameter | Values |
|---|---|
page | whole number from 1 (default 1) |
per_page | 1 – 100 (default 50); page × per_page reaches at most 10,000 results on search |
sort | newest | popular | rating | relevance (browse: default newest; search: default relevance; AI-search results are always in relevance order and take no sort) |
resolution | 720 | 1080 | 2160 (the original's height) |
orientation | landscape | portrait | square |
fps | whole number |
duration_min, duration_max | seconds (up to 3 decimals) |
has_audio, model_releases, geolocation | true | false |
categories | category names, comma-separated (up to 50) |
only_ai, exclude_ai | true | false (not both true) |
created_after, created_before | YYYY-MM-DD |
The API's name, version and documentation. No token. No parameters.
curl -s https://api.glymt.com/reseller/v1
{
"name": "Glymt Reseller API",
"version": "1.0",
"documentation": "https://glymt.com/reseller_api_documentation",
"description": "{summary}"
}
A Bearer token for 7200 seconds — see Authentication. Form body: grant_type
(client_credentials), and the client by HTTP Basic or client_id + client_secret.
Errors: 400 invalid_request, 400 unsupported_grant_type, 401 invalid_client, 429 (too many token requests).
curl -s -X POST https://api.glymt.com/reseller/v1/oauth/token \
-u '{client_id}:{client_secret}' \
-d grant_type=client_credentials
{
"access_token": "{access_token}",
"token_type": "Bearer",
"expires_in": 7200,
"scope": "reseller"
}
Your catalogue, a page at a time: page, per_page, sort and the
filters. sort=relevance ranks the catalogue through the search index without a query.
Returns {count, page, per_page, videos: [VideoCard]} — count is the number of catalogue videos matching
the filters.
Errors: 400 invalid_request, 401 invalid_token, 429.
curl -s 'https://api.glymt.com/reseller/v1/videos/browse?page=1&per_page=50&sort=newest&resolution=1080&has_audio=true' \
-H 'Authorization: Bearer {access_token}'
{
"count": {matching_videos},
"page": 1,
"per_page": 50,
"videos": [ {VideoCard}, … ]
}
Full-text search (OpenSearch) over your catalogue: q (required, at most 200 characters), with the same paging,
sort and filters as browse. Your client's allowance is part of the query, so count is your real
match count and every page is full.
Errors: 400 invalid_request (no q, an unknown parameter, past 10,000 results), 401 invalid_token, 429.
curl -s 'https://api.glymt.com/reseller/v1/videos/search?q=city%20night&orientation=portrait&per_page=20' \
-H 'Authorization: Bearer {access_token}'
{
"count": {matching_videos},
"page": 1,
"per_page": 50,
"videos": [ {VideoCard}, … ]
}
All the metadata of one catalogue video: {video: VideoDetail}. No query parameters.
Errors: 400 invalid_request, 401 invalid_token, 404 not_found (a video outside your catalogue).
curl -s https://api.glymt.com/reseller/v1/videos/details/{video_id} \
-H 'Authorization: Bearer {access_token}'
{
"video": {
… every VideoCard field …,
"description": "{video_description}",
"keywords": ["{keyword}", "{keyword}"],
"categories": ["{category}"],
"location": ["{city}", "{country}"],
"model_release_count": 1,
"created_at": "2026-10-01T09:30:00Z",
"published_at": "2026-10-02T10:00:00Z",
"licence_id": null
}
}
Starts an AI search by text, by up to 2 reference images, or both. JSON body: q (text, at most
750 characters), images (each {"data": base64, "content_type": "image/jpeg" | "image/png" | …},
a data: URL string, or {"url": "https://…"} on a public host; each at most 2 MB),
auto_filter (true | false). The search runs in the background: the answer is 202 with the
search_id to poll.
Limits per account: 60 AI searches an hour, 3 in
flight, 6 seconds between two starts — 429 with Retry-After.
Errors: 400 invalid_request (an unknown parameter), 401 invalid_token, 422 invalid_request (no q and no images, q too long, too many images), 422 invalid_image (unreadable, too large, not an image, a URL that is not public), 429 too_many_requests.
curl -s -X POST https://api.glymt.com/reseller/v1/ai_search/start \
-H 'Authorization: Bearer {access_token}' \
-H 'Content-Type: application/json' \
-d '{
"q": "{search_text}",
"auto_filter": false,
"images": [
{ "data": "{base64_image}", "content_type": "image/jpeg" },
{ "url": "https://{your_host}/{image}.jpg" }
]
}'
HTTP/1.1 202 Accepted
{
"search_id": {search_id},
"state": "processing",
"auto_filter": false,
"images_accepted": 2,
"results": "/reseller/v1/ai_search/results/{search_id}"
}
Poll an AI search: state is processing, failed (with error) or
completed — then the results of your catalogue in relevance order, with page, per_page and
the filters (no sort). Poll every few seconds.
Errors: 400 invalid_request, 401 invalid_token, 404 not_found (an unknown search or another account's).
curl -s 'https://api.glymt.com/reseller/v1/ai_search/results/{search_id}?page=1&per_page=50' \
-H 'Authorization: Bearer {access_token}'
{ "search_id": {search_id}, "state": "processing" }
{ "search_id": {search_id}, "state": "failed", "error": "{reason}" }
{
"search_id": {search_id},
"state": "completed",
"count": {matching_videos},
"page": 1,
"per_page": 50,
"videos": [ {VideoCard}, … ]
}
Licenses one catalogue video for 20 credits, debited from your account's credits in the same step: body
{"video_id": …} and nothing else (a price, a credit amount or any other parameter is 400 — the price is
Glymt's). 201 with the licence and your credits left. A video your account already holds is 200 with
that licence and "held": true — nothing is debited twice, so a repeated request is safe.
Errors: 400 invalid_request, 401 invalid_token, 402 insufficient_credits (with your credits and the price; nothing is written), 403 insufficient_scope (a test client licenses test videos only), 404 not_found (outside your catalogue), 409 own_video.
curl -s -X POST https://api.glymt.com/reseller/v1/licenses/purchase \
-H 'Authorization: Bearer {access_token}' \
-H 'Content-Type: application/json' \
-d '{ "video_id": {video_id} }'
HTTP/1.1 201 Created
{
"licence": { "id": {licence_id}, "video_id": {video_id}, "price_credits": 20, "created_at": "2026-10-30T12:00:00Z" },
"credits_left": 80
}
HTTP/1.1 200 OK
{
"licence": { "id": {licence_id}, "video_id": {video_id}, "price_credits": 20, "created_at": "2026-10-30T12:00:00Z" },
"credits_left": 80,
"held": true
}
HTTP/1.1 402 Payment Required
{ "error": "insufficient_credits", "credits": 19, "price": 20 }
Your account's licences, newest first: page, per_page (1 – 100, default 50).
Errors: 400 invalid_request, 401 invalid_token.
curl -s 'https://api.glymt.com/reseller/v1/licenses/list?page=1&per_page=50' \
-H 'Authorization: Bearer {access_token}'
{
"count": {licences},
"page": 1,
"per_page": 50,
"licences": [
{ "id": {licence_id}, "video_id": {video_id}, "price_credits": 20, "created_at": "2026-10-30T12:00:00Z" }
]
}
A signed link to the licensed, unwatermarked file. The link lasts 120 seconds: start the download at once, and request a new link at any time for a licence you hold.
Errors: 400 invalid_request, 401 invalid_token, 404 not_found (an unknown licence or another account's), 409 download_unavailable (the file is not available right now; Glymt is alerted).
curl -s https://api.glymt.com/reseller/v1/licenses/download_link/{licence_id} \
-H 'Authorization: Bearer {access_token}'
{
"licence_id": {licence_id},
"url": "{signed_download_url}",
"expires_in": 120
}
The model releases of a licensed video, each with a signed link that lasts 120 seconds.
Errors: 400 invalid_request, 401 invalid_token, 404 not_found.
curl -s https://api.glymt.com/reseller/v1/licenses/model_releases/{licence_id} \
-H 'Authorization: Bearer {access_token}'
{
"licence_id": {licence_id},
"count": 1,
"model_releases": [
{ "name": "{release_name}", "url": "{signed_release_url}", "expires_in": 120 }
]
}
Read only: your client, the licence price, your credits available and spent, your licences, your searches against their limits and your token's issue and expiry. No parameters.
Errors: 400 invalid_request, 401 invalid_token.
curl -s https://api.glymt.com/reseller/v1/account/summary \
-H 'Authorization: Bearer {access_token}'
{
"client": { "name": "{client_name}", "type": "training", "client_id": "{client_id}" },
"price_credits": 20,
"credits_available": 80,
"credits_spent": 20,
"licences_count": 1,
"licences_via_api": 1,
"last_licence_at": "2026-10-30T12:00:00Z",
"licences_per_month": { "2026-10": 1 },
"searches": { "this_hour": 12, "today": 40, "limit_per_minute": 600 },
"ai_searches": { "this_hour": 2, "today": 5, "limit_per_hour": 60 },
"token": { "issued_at": "2026-10-30T11:00:00Z", "expires_at": "2026-10-30T13:00:00Z" }
}
Every licence costs 20 credits; Glymt adds credits to your account; nothing in the API buys or adds credits.
/account/summary shows them.402 insufficient_credits and
nothing is written./licenses/model_releases/:licence_id.Every error is JSON with its HTTP status — {"error": code, "message": text}, or the OAuth form
{"error": code, "error_description": text} for 400/401/403 of the token and the Bearer checks.
{ "error": "invalid_request", "message": "unknown parameter(s): price" }
| Status | error | When |
|---|---|---|
| 400 | invalid_request, unsupported_grant_type | a missing, unknown or malformed parameter; a malformed JSON body |
| 401 | invalid_client | the token request: unknown client, wrong secret, inactive client or owner |
| 401 | invalid_token | no token, or one unknown, expired, revoked or issued for the Submitter API |
| 402 | insufficient_credits | a purchase with fewer credits than the price |
| 403 | insufficient_scope | a valid token asking for something its client may not do |
| 404 | not_found | an unknown path, or a video, search or licence outside your account |
| 409 | own_video, download_unavailable | licensing your own video; the licensed file is not available right now |
| 413 | — | a request body above the size limit, refused before it reaches the API |
| 415 | — | not answered by v1: a body that is neither JSON nor form-encoded is not read, and the request answers 400 |
| 422 | invalid_request, invalid_image | an AI search without text or images, or with an image that cannot be used |
| 423 | — | not answered by the Reseller API |
| 429 | too_many_requests | a limit reached — wait the Retry-After seconds |
| 500 | server_error | an error on Glymt's side; retry later |
{ "error": "not_found", "documentation": "https://glymt.com/reseller_api_documentation" }
429 with Retry-After (seconds).API version 1.0.
/videos… endpoints and the
account balance endpoint are removed.