Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🐘 airanks-net/api-client

The PHP client for the AIR API.

AIR (Artificial Intelligence Ranking) by airanks makes AI optimization visible: a 0–10 score for how often, and how well, AI assistants like ChatGPT cite a domain when answering real questions. Check any site's AIR score at airanks.net, or install the airanks toolbar to see it while you browse. This package is the PHP door into that same data — no CLI, no scaffolding, one class, three methods.

Packagist PHP License Dependencies Tests


📚 Table of contents


🤖 What is AIR?

AIR (Artificial Intelligence Ranking) by airanks is AI optimization made visible — the AI-era answer to "where do I rank." Instead of guessing whether ChatGPT knows and trusts your site, AIR gives you a number: a 0–10 score backed by real observed citations, plus your AI-file posture (llms.txt, ai.txt, robots.txt AI-agent rules). Look up any domain free at airanks.net, or install the browser toolbar to see the score on every page you visit. This package puts the same numbers behind a PHP Client class.

📦 Install

composer require airanks-net/api-client

Requires: PHP >=8.2, ext-curl, ext-json.

🚀 Quickstart

use Airanks\ApiClient\Client;

$client = new Client();

$domain = $client->domain('stripe.com');
echo $domain['data']['air_score']; // 0-10

$results = $client->search('payment processing');
$who = $client->user(); // throws ApiException(401) if unauthenticated

A never-before-seen domain still 200s and triggers server-side hydration in the background — $domain['data']['ai_files']['status'] === 'pending' means "check again shortly," not an error.

📄 Fuller example, with error handling (examples/lookup.php)
<?php

declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

use Airanks\ApiClient\ApiException;
use Airanks\ApiClient\Client;

// Auth resolves itself: AIR_API_KEY env, then ~/.config/air/auth.json (written by `air login`
// in any AIR client), then anonymous. Pass a token explicitly if you'd rather not rely on either.
$client = new Client();

try {
    $result = $client->domain('stripe.com');
    $domain = $result['data'];

    printf("%s — AIR %d/10\n", $domain['hostname'], $domain['air_score']);

    if (($domain['ai_files']['status'] ?? null) === 'pending') {
        echo "still gathering — check back in a minute\n";
    }

    $search = $client->search('payment processing');
    printf("%d domains matched \"payment processing\"\n", count($search['data']['domains'] ?? []));

    $who = $client->user();
    echo "logged in as: " . ($who['data']['name'] ?? $who['name'] ?? 'anonymous') . "\n";
} catch (ApiException $e) {
    fwrite(STDERR, "AIR request failed ({$e->getStatusCode()}): {$e->getMessage()}\n");
    exit(1);
}

Run it with php examples/lookup.php (after composer install).

🔀 How a request resolves

flowchart TD
    A["new Client($token = null)"] --> B{Explicit token\npassed to constructor?}
    B -- yes --> C["source: explicit\nalways attaches"]
    B -- no --> D["Auth::resolveToken()"]
    D --> E{AIR_API_KEY\nenv set?}
    E -- yes --> F["source: env\nalways attaches"]
    E -- no --> G{"~/.config/air/auth.json\nreadable + has token?"}
    G -- yes --> H["source: file\nattaches only if request\nhost === saved host"]
    G -- no --> I["source: anonymous\nno Authorization header"]
    C --> J["Client::get($url)\ncurl + User-Agent + Bearer (if attached)"]
    F --> J
    H --> J
    I --> J
    J --> K{HTTP status}
    K -- "< 400" --> L["decode JSON → array"]
    K -- ">= 400" --> M["throw ApiException\n(message, status, retryAfter for 429)"]
Loading

🧩 API reference

Airanks\ApiClient\Client — one constructor, three request methods:

Method Returns Notes
new Client(?string $token = null, ?string $apiBase = null) $token skips shared auth resolution entirely and always attaches. $apiBase overrides AIR_API_BASE / the default https://airanks.net/api/v1.
domain(string $host): array {"data": {...domain}, "meta": {"dataset_version": ...}} AIR score, percentile, and AI-file posture (llms.txt, ai.txt, robots.txt AI-agent rules, JSON-LD) for a hostname. Always 200s for a valid host; a never-before-seen domain triggers server-side hydration, so data.ai_files.status === "pending" means check again shortly, not an error.
search(string $q): array {"data": {"domains": [], "brands": [], "phrases": []}, "meta": {...}} Matches across every domain, brand, and phrase AIR tracks.
user(): array The authenticated user (name, email) for whichever token was resolved. Throws ApiException with status 401 if the token is missing, invalid, or revoked.

🔑 Shared authentication — one login, every AIR client

This package resolves auth exactly the way every other AIR client does, in this order — first hit wins:

# Source Behaviour
1 AIR_API_KEY env var Explicit intent — always attaches, to any host.
2 ~/.config/air/auth.json The file air login writes. Only attaches to requests whose host matches the host it was saved for, so a repointed AIR_API_BASE can't leak a stale token elsewhere.
3 Anonymous No token sent; subject to the anonymous rate limit.

Because the path, env var, and file shape are identical across clients, air login run once — from the CLI or the toolbar — authenticates this library too. Nothing to configure beyond an optional explicit token:

$client = new Client(token: getenv('MY_OWN_AIR_TOKEN'));

Point at a different API base (staging, a mirror, etc.) with the AIR_API_BASE env var, or the constructor's second argument.

🚨 Errors

Non-2xx responses throw Airanks\ApiClient\ApiException, which carries the HTTP status (getStatusCode()) and, for a 429, the server's Retry-After seconds (getRetryAfter()) when present:

use Airanks\ApiClient\ApiException;

try {
    $domain = $client->domain('example.com');
} catch (ApiException $e) {
    if ($e->getStatusCode() === 429) {
        sleep($e->getRetryAfter() ?? 30);
    }
}

🧪 Testing

tests/AuthTest.php covers token-resolution order and the host-scoped attach rule — no network calls involved.

composer install
composer test

🌐 Sibling AIR clients

Every client below shares the same auth file, so logging in with any one of them logs you into all the others:

Client Language Repo
air Go CLI github.com/airanks-net/go-cli
air-cli Node CLI github.com/airanks-net/node-cli
air-cli Rust CLI github.com/airanks-net/rust-cli
@airanks-net/sdk JS/TS SDK github.com/airanks-net/js-sdk
airanks Python SDK github.com/airanks-net/python-sdk
airanks-mcp-server MCP server github.com/airanks-net/mcp-server
air-toolbar Chrome extension github.com/airanks-net/chrome-extension

📜 License

MIT — see LICENSE.


Built for the AIR ecosystem at airanks.net — because knowing your AI optimization score beats guessing it. 🎯

About

airanks-net/api-client — PHP client for the AIR (airanks) AI optimization API. airanks.net

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages