Ranklify API
Version v1 · Base URL https://www.getranklify.com
The Ranklify API generates platform-optimized product listings for Amazon, Shopify, and WooCommerce. Send product details, get back a titled, keyword-rich, scored listing in one request. API access is available on the Agency plan.
- Base URL
- Authentication
- Quickstart
- Generate a listing
- Response shape
- Errors
- Rate limits & usage
- Versioning & breaking changes
- Code samples
- OpenAPI & Postman
- Changelog
Base URL
All requests go to:
https://www.getranklify.com/api/v1Always use the www host. The apex domain (https://getranklify.com) issues a 308 redirect, and many HTTP clients drop the Authorization header when following a redirect, which would fail your request. Requests must be https.
Authentication
Authenticate with a secret API key in the Authorization header as a Bearer token:
Authorization: Bearer lfy_your_key_hereQuickstart
Replace lfy_YOUR_KEY with a real key and run:
curl -X POST https://www.getranklify.com/api/v1/generate \
-H "Authorization: Bearer lfy_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_name": "Stainless Steel Pour-Over Kettle",
"features": "Gooseneck spout, 1L, food-grade steel, keeps heat",
"platform": "amazon",
"tone": "Professional"
}'A 200 response returns a listing object plus metadata (see below).
POST /api/v1/generate
Generates a single optimized listing and saves it to your account history.
Headers
| Header | Value |
|---|---|
| Authorization | Bearer lfy_... (required) |
| Content-Type | application/json (required) |
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
| product_name | string | Yes | Max 200 chars. |
| features | string | Yes | Key features / selling points. Max 600 chars. |
| platform | string | No | One of amazon, shopify, woocommerce. Default amazon. Unknown values fall back to amazon. |
| tone | string | No | One of Professional, Energetic, Friendly, Luxury, Technical, Playful, Bold, Minimalist. Default Professional. |
| category | string | No | Max 100 chars. |
| price | string | No | Free-text price context (e.g. "$24.99 mid-range"), not a number. Max 100 chars. |
| customer | string | No | Target customer & use cases. Max 500 chars. |
| competitors | string | No | Competitor URLs or market context. Max 300 chars. |
| brand_id | string | No | Target workspace/brand the listing is filed under. Defaults to your active brand. Must be one you own or you get brand_forbidden. |
Unknown fields are ignored, so new optional fields can be added without breaking your integration.
Response shape
A successful call returns 200 with the envelope below. The listing object is a stable superset: every key is always present. Fields that don't apply to the chosen platform come back empty ("" or []), so you can write one parser for all platforms.
{
"api_version": "v1",
"listing": {
"title": "HYDROSTEEL Stainless Steel Pour-Over Kettle ...",
"bullets": ["PRECISE POUR — ...", "BUILT TO LAST — ...", "..."],
"description": "<p>...</p>",
"keywords": ["pour over kettle", "gooseneck kettle", "..."],
"backend_terms": "coffee kettle, drip kettle, ...",
"focus_keyphrase": "",
"meta_description": "",
"product_tags": [],
"seo_scores": {
"keyword_density": 89,
"readability": 92,
"conversion_potential": 91,
"platform_compliance": 95
},
"pro_tip": "Add a lifestyle image showing the spout mid-pour."
},
"listing_id": "b1c2...",
"platform": "amazon",
"tone": "Professional",
"brand_id": "a9d4...",
"usage": { "used": 12, "limit": 1000, "plan": "agency" }
}Which listing fields are populated per platform
| Field | Amazon | Shopify | WooCommerce |
|---|---|---|---|
| title, description, keywords, seo_scores, pro_tip | ✓ | ✓ | ✓ |
| bullets (up to 5) | ✓ | — | ✓ |
| backend_terms (string) | ✓ | — | — |
| meta_description | — | ✓ | ✓ |
| focus_keyphrase | — | — | ✓ |
| product_tags (up to 8) | — | — | ✓ |
seo_scores holds four integers 0–100: keyword_density, readability, conversion_potential, platform_compliance.
Errors
Errors return a non-2xx status with a stable envelope. Branch on error.code, never on the human message (messages may change, codes will not).
{ "error": { "code": "invalid_api_key", "message": "Invalid or revoked API key." } }| Status | code | Meaning |
|---|---|---|
| 401 | missing_authorization | No / malformed Authorization header. |
| 401 | invalid_api_key | Wrong format, unknown, or revoked key. |
| 403 | plan_required | Key owner is not on the Agency plan. |
| 403 | brand_forbidden | brand_id is not on this account. |
| 410 | brand_archived | brand_id refers to an archived brand. |
| 400 | invalid_json | Body is not valid JSON. |
| 400 | validation_error | Missing required field or a field exceeds its limit. |
| 403 | usage_limit_reached | Monthly generation limit hit. |
| 429 | rate_limited | Over 10 requests/min for this key. Retry after the Retry-After header. |
| 500 | internal_error | Unexpected server error. Safe to retry. |
Rate limits & usage
- Rate limit: 10 requests per minute per key. Exceeding returns
429with aRetry-After: 60header. - Usage: every successful generation counts against your plan's monthly quota, shared with the dashboard. The response's
usageobject reportsused,limit, andplan. - Latency: generation is AI-backed and typically takes a few seconds up to ~30s. Set a client timeout of at least 60 seconds.
Versioning & breaking changes
The API is versioned in the URL path (/api/v1/...). Our commitments:
- Additive changes ship without a version bump. We may add new optional request fields, new response fields, new endpoints, and new accepted enum values within
v1. Build clients to tolerate unknown fields. - Breaking changes ship as a new major version (
/v2). Breaking means removing or renaming a field, changing a field's type or meaning, making an optional field required, tightening validation, or changing the error shape. - Deprecation window: when a new major version ships, the previous version keeps working for at least 6 months.
- Notice: we announce breaking changes in advance by email to API key owners, in the changelog below, and via
DeprecationandSunsetresponse headers on the retiring version.
Code samples
curl -X POST https://www.getranklify.com/api/v1/generate \
-H "Authorization: Bearer lfy_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_name": "Stainless Steel Pour-Over Kettle",
"features": "Gooseneck spout, 1L, food-grade steel, keeps heat",
"platform": "amazon",
"tone": "Professional"
}'const res = await fetch("https://www.getranklify.com/api/v1/generate", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.RANKLIFY_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
product_name: "Stainless Steel Pour-Over Kettle",
features: "Gooseneck spout, 1L, food-grade steel, keeps heat",
platform: "amazon",
tone: "Professional",
}),
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(error.code + ": " + error.message);
}
const data = await res.json();
console.log(data.listing.title);import os, requests
resp = requests.post(
"https://www.getranklify.com/api/v1/generate",
headers={
"Authorization": f"Bearer {os.environ['RANKLIFY_API_KEY']}",
"Content-Type": "application/json",
},
json={
"product_name": "Stainless Steel Pour-Over Kettle",
"features": "Gooseneck spout, 1L, food-grade steel, keeps heat",
"platform": "amazon",
"tone": "Professional",
},
timeout=60,
)
if resp.status_code != 200:
err = resp.json()["error"]
raise RuntimeError(f"{err['code']}: {err['message']}")
print(resp.json()["listing"]["title"])<?php
$ch = curl_init("https://www.getranklify.com/api/v1/generate");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("RANKLIFY_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"product_name" => "Stainless Steel Pour-Over Kettle",
"features" => "Gooseneck spout, 1L, food-grade steel, keeps heat",
"platform" => "amazon",
"tone" => "Professional",
]),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($response, true);
if ($status !== 200) {
throw new Exception($data["error"]["code"] . ": " . $data["error"]["message"]);
}
echo $data["listing"]["title"];import java.net.URI;
import java.net.http.*;
HttpClient client = HttpClient.newHttpClient();
String body = """
{
"product_name": "Stainless Steel Pour-Over Kettle",
"features": "Gooseneck spout, 1L, food-grade steel, keeps heat",
"platform": "amazon",
"tone": "Professional"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://www.getranklify.com/api/v1/generate"))
.header("Authorization", "Bearer " + System.getenv("RANKLIFY_API_KEY"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("Request failed: " + response.body());
}
System.out.println(response.body());OpenAPI & Postman
Import the API into your tooling:
- OpenAPI 3.1 spec: /openapi.json — import into Swagger, Stoplight, or code generators.
- Postman collection: ranklify.postman_collection.json — set the
baseUrlandapiKeyvariables and send.
Changelog
- Errors now return a machine-readable
error.code. listingis a stable superset — every field is always present (empty when not applicable to the platform).- Responses include
api_version, and echo the resolvedtoneandbrand_id. - Added optional
brand_idto file a listing under a specific workspace.
POST /api/v1/generate— Bearer auth, Agency plan, 10 req/min per key.
Questions or need a higher rate limit? Get in touch.