API reference
One endpoint returns the current OpenPageRank and full monthly history for up to 100 domains. Base URL: https://openpagerank.keywordseverywhere.com
Authentication
Send your OPR API key as a bearer token on every request. Create one on the Dashboard after signing in with your Keywords Everywhere key.
Authorization: Bearer opr_live_xxxxxxxxxxxxxxxx
Try it
Run a real request against your account. Your key is used only for this call and never leaves your browser except to this API.
curl -X POST https://openpagerank.keywordseverywhere.com/v1/domains/bulk …
Look up domains
POST /v1/domains/bulk
Returns the current score and, by default, the full monthly history for each domain. Input can be a bare domain, a hostname, or a full URL. It is reduced to the registered domain. Each unique domain counts once toward your monthly limit.
| Field | Type | Notes |
|---|---|---|
domains | string[] | Required. Up to 100 unique domains per request (duplicates and equivalent forms, e.g. URLs of the same site, are merged first). |
include_history | boolean | Optional, default true. Set false for a smaller, current-only response. |
curl -X POST https://openpagerank.keywordseverywhere.com/v1/domains/bulk \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"domains": ["github.com", "google.com"], "include_history": true}'import requests
resp = requests.post(
"https://openpagerank.keywordseverywhere.com/v1/domains/bulk",
headers={"Authorization": "Bearer YOUR_KEY"},
json={"domains": ["github.com", "google.com"], "include_history": True},
)
data = resp.json()
for row in data["results"]:
print(row["domain"], row["open_page_rank"])const resp = await fetch("https://openpagerank.keywordseverywhere.com/v1/domains/bulk", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
domains: ["github.com", "google.com"],
include_history: true,
}),
});
const data = await resp.json();
data.results.forEach((r) => console.log(r.domain, r.open_page_rank));<?php
$ch = curl_init("https://openpagerank.keywordseverywhere.com/v1/domains/bulk");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_KEY", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode([
"domains" => ["github.com", "google.com"],
"include_history" => true,
]),
]);
$data = json_decode(curl_exec($ch), true);
foreach ($data["results"] as $row) {
echo $row["domain"], " ", $row["open_page_rank"], "\n";
}require "net/http"
require "json"
uri = URI("https://openpagerank.keywordseverywhere.com/v1/domains/bulk")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_KEY"
req["Content-Type"] = "application/json"
req.body = { domains: ["github.com", "google.com"], include_history: true }.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
JSON.parse(res.body)["results"].each { |r| puts "#{r["domain"]} #{r["open_page_rank"]}" }import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://openpagerank.keywordseverywhere.com/v1/domains/bulk"))
.header("Authorization", "Bearer YOUR_KEY")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(
"{\"domains\": [\"github.com\", \"google.com\"], \"include_history\": true}"))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]any{
"domains": []string{"github.com", "google.com"},
"include_history": true,
})
req, _ := http.NewRequest("POST", "https://openpagerank.keywordseverywhere.com/v1/domains/bulk", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer YOUR_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var data map[string]any
json.NewDecoder(resp.Body).Decode(&data)
fmt.Println(data["count"], "domains returned")
}using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "YOUR_KEY");
var json = "{\"domains\": [\"github.com\", \"google.com\"], \"include_history\": true}";
var content = new StringContent(json, Encoding.UTF8, "application/json");
var resp = await client.PostAsync("https://openpagerank.keywordseverywhere.com/v1/domains/bulk", content);
Console.WriteLine(await resp.Content.ReadAsStringAsync());Response
{
"as_of": "2026-06-01",
"count": 2,
"results": [
{
"domain": "github.com",
"found": true,
"open_page_rank": 9.67,
"rank": 30,
"referring_domains": 282833,
"history": [
{ "date": "2018-01-01", "open_page_rank": 9.41, "estimated": false },
{ "date": "2026-06-01", "open_page_rank": 9.67, "estimated": false }
]
},
{ "domain": "google.com", "found": true, "open_page_rank": 10, "rank": 2, "referring_domains": 2308810, "history": [ ] }
],
"invalid": []
}
| Field | Meaning |
|---|---|
open_page_rank | The authority score: a number from 0 to 10 with up to 2 decimal places (e.g. 10, 9.7, 4.92). null if the domain is not found. |
rank | Global position by PageRank (1 = highest). |
referring_domains | Authority-weighted count of linking domains. |
history | Monthly series, oldest first. Present only when include_history is not false; omitted entirely otherwise. |
history[].estimated | false for a month with a Common Crawl release (measured); true for a month with no release, linearly interpolated from the surrounding measured months. Interpolated months are most common before 2024, when releases were quarterly. |
invalid | Inputs that could not be parsed to a domain (echoed back verbatim — escape before rendering in a UI). Invalid inputs are not counted against your limit. |
Usage
GET /v1/usage. Returns your plan tier and how many domains you have left this month. Reading it does not count against your limit.
curl https://openpagerank.keywordseverywhere.com/v1/usage -H "Authorization: Bearer YOUR_KEY"import requests
u = requests.get("https://openpagerank.keywordseverywhere.com/v1/usage", headers={"Authorization": "Bearer YOUR_KEY"}).json()
print(u["domains_remaining"], "of", u["monthly_domain_limit"], "left this month"){ "tier": "free", "monthly_domain_limit": 30000, "domains_used": 1234, "domains_remaining": 28766, "resets_at": "2026-07-01T00:00:00+00:00", "requests_per_minute": 60 }
Health
GET /v1/health. Returns service status and the current data release. No authentication.
curl https://openpagerank.keywordseverywhere.com/v1/healthDomain limits
Each response includes your current balances in headers:
X-Domains-Limit: 30000 # your plan's monthly domain allowance
X-Domains-Remaining: 28766 # domains left this month
X-Domains-Reset: 1782864000 # unix time the monthly allowance resets (1st of next month)
X-RateLimit-Limit: 60 # requests/minute allowed on your plan
X-RateLimit-Remaining: 59 # requests left in the current minute
X-RateLimit-Reset: 1782777600 # unix time the per-minute window resets
Each unique, valid domain counts once per request (history or not); an empty request or one with only invalid inputs counts zero. A request that would exceed your monthly limit is declined with 429 (quota_error) and those domains are not counted. There is also a per-minute request limit (429 rate_limit_error) to guard against bursts. Domain limits reset on the 1st of each month. See plans for the limit on each tier.
Errors
Errors return a consistent shape:
{ "error": { "type": "authentication_error", "message": "Missing OPR API key. Provide it as: Authorization: Bearer <api_key>" } }
| Status | type | When |
|---|---|---|
| 400 | invalid_request_error | Missing domains, more than 100 unique domains per request, or include_history is not a boolean. |
| 401 | authentication_error | Missing or invalid OPR API key. |
| 404 | not_found_error | Unknown endpoint (path not part of the API). |
| 405 | invalid_request_error | Wrong HTTP method for a known endpoint. The Allow header lists the accepted methods. |
| 429 | quota_error / rate_limit_error | Monthly domain limit reached, or too many requests per minute. |
Prefer a machine-readable contract? The full OpenAPI 3 spec imports into Postman and generates client SDKs.