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.

From the Dashboard.
Equivalent cURL
curl -X POST https://openpagerank.keywordseverywhere.com/v1/domains/bulk …
Response
Run a request to see the response.

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.

FieldTypeNotes
domainsstring[]Required. Up to 100 unique domains per request (duplicates and equivalent forms, e.g. URLs of the same site, are merged first).
include_historybooleanOptional, 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": []
}
FieldMeaning
open_page_rankThe 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.
rankGlobal position by PageRank (1 = highest).
referring_domainsAuthority-weighted count of linking domains.
historyMonthly series, oldest first. Present only when include_history is not false; omitted entirely otherwise.
history[].estimatedfalse 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.
invalidInputs 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/health

Domain 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>" } }
StatustypeWhen
400invalid_request_errorMissing domains, more than 100 unique domains per request, or include_history is not a boolean.
401authentication_errorMissing or invalid OPR API key.
404not_found_errorUnknown endpoint (path not part of the API).
405invalid_request_errorWrong HTTP method for a known endpoint. The Allow header lists the accepted methods.
429quota_error / rate_limit_errorMonthly 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.