{
  "info": {
    "name": "Ranklify API",
    "description": "Generate platform-optimized product listings for Amazon, Shopify, and WooCommerce.\n\nSet the collection variables `baseUrl` and `apiKey`, then send. `apiKey` accepts either an API key from /api-keys (Agency plan required) or a store connection token from the connect flow (valid on every plan, including Free).\n\nThe async requests share a `jobId` variable: \"Queue listing job\" saves the returned job_id automatically, so \"Poll job\" works straight after it.\n\nDocs: https://www.getranklify.com/developers",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    { "key": "baseUrl", "value": "https://www.getranklify.com", "type": "string" },
    { "key": "apiKey", "value": "lfy_YOUR_KEY", "type": "string" },
    { "key": "jobId", "value": "", "type": "string" }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [{ "key": "token", "value": "{{apiKey}}", "type": "string" }]
  },
  "item": [
    {
      "name": "Synchronous",
      "item": [
        {
          "name": "Generate listing",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/v1/generate", "host": ["{{baseUrl}}"], "path": ["api", "v1", "generate"] },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"product_name\": \"Stainless Steel Pour-Over Kettle\",\n  \"features\": \"Gooseneck spout, 1L, food-grade steel, keeps heat\",\n  \"platform\": \"amazon\",\n  \"tone\": \"Professional\"\n}"
            },
            "description": "Stays open for the whole generation (15-35s), so set a timeout of at least 60s. Optional body fields: category, price, customer, competitors, brand_id."
          }
        },
        {
          "name": "Generate listing (Shopify example)",
          "request": {
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/v1/generate", "host": ["{{baseUrl}}"], "path": ["api", "v1", "generate"] },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"product_name\": \"Organic Cotton Baby Blanket\",\n  \"features\": \"GOTS certified organic cotton, breathable, machine washable\",\n  \"category\": \"Baby\",\n  \"tone\": \"Friendly\",\n  \"platform\": \"shopify\"\n}"
            }
          }
        }
      ]
    },
    {
      "name": "Asynchronous (jobs)",
      "item": [
        {
          "name": "Queue listing job",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Save job_id so \"Poll job\" can run without copy-pasting.",
                  "if (pm.response.code === 202) {",
                  "    pm.collectionVariables.set('jobId', pm.response.json().job_id);",
                  "}"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              { "key": "Content-Type", "value": "application/json" },
              { "key": "Idempotency-Key", "value": "sku-4471-run1", "description": "A retry with the same key returns the original job instead of queueing a second generation. Change it for a genuinely new request." }
            ],
            "url": { "raw": "{{baseUrl}}/api/v1/jobs", "host": ["{{baseUrl}}"], "path": ["api", "v1", "jobs"] },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"product_name\": \"Stainless Steel Pour-Over Kettle\",\n  \"features\": \"Gooseneck spout, 1L, food-grade steel, keeps heat\",\n  \"platform\": \"woocommerce\",\n  \"external_ref\": \"4471\"\n}"
            },
            "description": "Returns 202 immediately with a job_id. Use this instead of /generate anywhere there is an execution cap you do not control (PHP, WordPress, serverless). A credit is reserved on creation and refunded exactly once if the job ends up failed."
          }
        },
        {
          "name": "Poll job",
          "request": {
            "method": "GET",
            "header": [],
            "url": { "raw": "{{baseUrl}}/api/v1/jobs/{{jobId}}", "host": ["{{baseUrl}}"], "path": ["api", "v1", "jobs", "{{jobId}}"] },
            "description": "Poll every 3s until status is 'complete' or 'failed'. Exempt from the rate limit. A failed job returns HTTP 200 with status: 'failed' — check the status field, not just the HTTP code."
          }
        },
        {
          "name": "List recent jobs",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/jobs?limit=20",
              "host": ["{{baseUrl}}"],
              "path": ["api", "v1", "jobs"],
              "query": [{ "key": "limit", "value": "20", "description": "1-50, default 20" }]
            },
            "description": "Most recent jobs, newest first. Exempt from the rate limit."
          }
        }
      ]
    },
    {
      "name": "Account",
      "item": [
        {
          "name": "Me (plan, usage, brands)",
          "request": {
            "method": "GET",
            "header": [],
            "url": { "raw": "{{baseUrl}}/api/v1/me", "host": ["{{baseUrl}}"], "path": ["api", "v1", "me"] },
            "description": "Plan, remaining credits, what this token is, and which brands it can file listings under. Exempt from the rate limit."
          }
        }
      ]
    },
    {
      "name": "Connect flow",
      "item": [
        {
          "name": "Exchange connect code for a store token",
          "auth": { "type": "noauth" },
          "request": {
            "auth": { "type": "noauth" },
            "method": "POST",
            "header": [{ "key": "Content-Type", "value": "application/json" }],
            "url": { "raw": "{{baseUrl}}/api/v1/connect/exchange", "host": ["{{baseUrl}}"], "path": ["api", "v1", "connect", "exchange"] },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"code\": \"ONE_TIME_CODE\",\n  \"site\": \"https://shop.example.com\"\n}"
            },
            "description": "Server-to-server only, no Bearer auth — possession of a valid code IS the credential.\n\nGet the code by sending the store owner's browser to {{baseUrl}}/connect?site=...&platform=woocommerce&return_url=...&state=... — we redirect back to return_url with ?ranklify_code=...&state=...\n\nCodes expire in 10 minutes and are single-use. The token comes back once and is stored hashed on our side. `site` must match the origin the code was issued for."
          }
        }
      ]
    }
  ]
}
