iajson / client
PHP reference library for consuming ia.json files — the universal standard for AI interaction with websites
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.5
- psr/http-message: ^2.0
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0|^11.0
README
PHP reference library for consuming ia.json files -- the universal standard for AI interaction with websites.
Requirements
- PHP 8.1 or higher
- ext-json
- ext-hash
Installation
composer require iajson/client
Note: The package will be available on Packagist soon. In the meantime, install from GitHub:
git clone https://github.com/Dandte/ai.json.git # Add a path repository in your composer.json pointing to libraries/php/
Quick Start
use IaJson\Client\IaJsonClient; // Discover a site's ia.json and create a client $client = IaJsonClient::discover('techstore.example.com'); // Call a public endpoint (no authentication needed) $results = $client->call('search_products', ['q' => 'wireless headphones']); // Inspect the site $site = $client->getSite(); echo $site['name']; // "TechStore" echo $site['type']; // "ecommerce"
Discovery
The library follows the ia.json discovery algorithm:
- Tries
https://{domain}/ia.json - Falls back to
https://{domain}/.well-known/ia.json - Validates the spec structure and version compatibility
use IaJson\Client\Discovery; $discovery = new Discovery(); $spec = $discovery->fetch('example.com'); // $spec is the full parsed ia.json array echo $spec['version']; // "1.0.0" echo $spec['api']['base_url']; // "https://example.com/api/v1"
Browsing Endpoints
$client = IaJsonClient::discover('techstore.example.com'); // Get all endpoints $all = $client->getEndpoints(); // Get only public endpoints $public = $client->getEndpoints('public'); // Get protected endpoints (require agent auth) $protected = $client->getEndpoints('protected'); // Get user_required endpoints (require OAuth) $userRequired = $client->getEndpoints('user_required'); // Check capabilities if ($client->hasCapability('search')) { $results = $client->call('search_products', ['q' => 'laptop']); } // Get rate limit info $rateLimit = $client->getRateLimit(); // e.g., "1000/hour"
Authentication
Signed Key Registration
For protected endpoints, you must register your AI agent and receive credentials:
$client = IaJsonClient::discover('techstore.example.com'); // Step 1: Register your agent $response = $client->register([ 'name' => 'My AI Assistant', 'domain' => 'myai.example.com', 'webhook_url' => 'https://myai.example.com/ia/verify', 'contact' => 'admin@myai.example.com', 'description' => 'AI shopping assistant', ]); // Step 2: Your webhook receives a verification_code from the site. // Step 3: Submit the verification code: $credentials = $client->verify('vc_abc123def456'); // The client now has credentials set automatically. // You can also store and re-use them: echo $credentials['api_key']; // "ia_live_..." echo $credentials['secret']; // "sec_..."
Using Existing Credentials
If you already have credentials from a previous registration:
$client = IaJsonClient::discover('techstore.example.com'); $client->setCredentials('ia_live_abc123', 'sec_xyz789'); // Now you can call protected endpoints $inventory = $client->call('get_inventory');
OAuth2 (User Authorization)
For user_required endpoints, you need the user's OAuth2 token:
$client = IaJsonClient::discover('techstore.example.com'); $client->setCredentials('ia_live_abc123', 'sec_xyz789'); // Get the OAuth helper $oauth = $client->getOAuth( clientId: 'your_client_id', clientSecret: 'your_client_secret', ); // Step 1: Get the authorization URL for the user to visit $result = $oauth->getAuthorizationUrl( redirectUri: 'https://myai.example.com/callback', scopes: ['cart:read', 'cart:write', 'orders:write'], state: 'random_csrf_token', ); echo $result['url']; // Redirect user here // If PKCE is required, store $result['code_verifier'] in the session // Step 2: After the user authorizes, exchange the code $tokens = $oauth->exchangeCode( code: $_GET['code'], redirectUri: 'https://myai.example.com/callback', codeVerifier: $result['code_verifier'] ?? null, // If PKCE ); // The OAuth helper stores tokens internally. // Or set a token directly: $client->setOAuthToken($tokens['access_token']); // Now call user_required endpoints $cart = $client->call('get_cart'); $client->call('add_to_cart', [ 'product_id' => 'prod_abc123', 'quantity' => 2, ]);
Request Signing
The Signer class implements the ia.json HMAC signing algorithm:
use IaJson\Client\Auth\Signer; // Sign a request $signature = Signer::sign( secret: 'sec_xyz789', timestamp: time(), body: '{"product_id":"prod_123","quantity":2}', algorithm: 'sha256', ); // Generate all auth headers at once $headers = Signer::createSignedHeaders( apiKey: 'ia_live_abc123', secret: 'sec_xyz789', body: '{"product_id":"prod_123"}', algorithm: 'sha256', prefix: 'X-IA-', ); // Result: // [ // 'X-IA-Key' => 'ia_live_abc123', // 'X-IA-Signature' => 'a1b2c3d4...', // 'X-IA-Timestamp' => '1707753600', // ] // Verify an incoming signature (server-side) $valid = Signer::verify( secret: 'sec_xyz789', providedSignature: $incomingSignature, timestamp: (int) $incomingTimestamp, body: $rawRequestBody, algorithm: 'sha256', maxAgeSeconds: 60, );
Error Handling
The library throws typed exceptions for different error conditions:
use IaJson\Client\Exceptions\IaJsonException; use IaJson\Client\Exceptions\AuthenticationException; use IaJson\Client\Exceptions\RateLimitException; try { $result = $client->call('get_inventory'); } catch (RateLimitException $e) { // HTTP 429 - retry after the suggested delay $retryAfter = $e->getRetryAfter(); // seconds, or null sleep($retryAfter ?? 60); } catch (AuthenticationException $e) { // HTTP 401/403 - invalid key, expired signature, etc. echo $e->getErrorCode(); // e.g., "invalid_signature" } catch (IaJsonException $e) { // Any other ia.json error echo $e->getMessage(); echo $e->getErrorCode(); print_r($e->getErrorDetails()); }
Laravel Integration
This package includes first-class Laravel support with auto-discovery.
Setup
- Publish the configuration:
php artisan vendor:publish --tag=iajson-config
- Add your credentials to
.env:
IAJSON_DOMAIN=techstore.example.com IAJSON_API_KEY=ia_live_abc123 IAJSON_SECRET=sec_xyz789 # Optional: OAuth2 credentials IAJSON_OAUTH_CLIENT_ID=your_client_id IAJSON_OAUTH_CLIENT_SECRET=your_client_secret # Optional: Cache TTL in seconds (default: 3600) IAJSON_CACHE_TTL=3600
Using the Facade
use IaJson\Client\Laravel\Facades\IaJson; // Call endpoints $products = IaJson::call('search_products', ['q' => 'laptop']); $inventory = IaJson::call('get_inventory'); // Inspect the site $site = IaJson::getSite(); $endpoints = IaJson::getEndpoints('public'); $capabilities = IaJson::getCapabilities();
Dependency Injection
use IaJson\Client\IaJsonClient; class ProductController extends Controller { public function search(Request $request, IaJsonClient $iajson) { $results = $iajson->call('search_products', [ 'q' => $request->input('query'), ]); return response()->json($results); } }
Verifying Incoming AI Agent Requests
If your Laravel application serves as an ia.json-enabled site and receives requests from AI agents, use the VerifyIaSignature middleware:
- Register the middleware alias in your
bootstrap/app.php(Laravel 11+) or kernel:
// bootstrap/app.php (Laravel 11+) ->withMiddleware(function (Middleware $middleware) { $middleware->alias([ 'iajson.verify' => \IaJson\Client\Laravel\Middleware\VerifyIaSignature::class, ]); })
// app/Http/Kernel.php (Laravel 10) protected $middlewareAliases = [ // ... 'iajson.verify' => \IaJson\Client\Laravel\Middleware\VerifyIaSignature::class, ];
- Apply it to your routes:
Route::middleware('iajson.verify')->prefix('api/v1')->group(function () { Route::get('/inventory', [InventoryController::class, 'index']); Route::post('/orders', [OrderController::class, 'store']); });
- Configure the secret resolver in
config/iajson.php:
// Option A: Static key mapping 'verification' => [ 'keys' => [ 'ia_live_agent1_key' => 'sec_agent1_secret', 'ia_live_agent2_key' => 'sec_agent2_secret', ], ], // Option B: Custom resolver (e.g., from database) 'verification' => [ 'secret_resolver' => function (string $apiKey): ?string { $agent = \App\Models\AiAgent::where('api_key', $apiKey)->first(); return $agent?->secret; }, ],
The verified API key is available in the request:
public function index(Request $request) { $apiKey = $request->attributes->get('iajson_api_key'); // Use $apiKey to identify which agent is making the request }
Configuration Reference
The full config/iajson.php supports the following options:
| Key | Env Variable | Description |
|---|---|---|
domain |
IAJSON_DOMAIN |
Domain to discover ia.json from |
api_key |
IAJSON_API_KEY |
Agent API key |
secret |
IAJSON_SECRET |
Agent secret |
oauth.client_id |
IAJSON_OAUTH_CLIENT_ID |
OAuth2 client ID |
oauth.client_secret |
IAJSON_OAUTH_CLIENT_SECRET |
OAuth2 client secret |
cache_ttl |
IAJSON_CACHE_TTL |
Spec cache TTL in seconds |
verification.algorithm |
IAJSON_VERIFY_ALGORITHM |
HMAC algorithm for verification |
verification.header_prefix |
IAJSON_VERIFY_HEADER_PREFIX |
Auth header prefix |
verification.max_age_seconds |
IAJSON_VERIFY_MAX_AGE |
Max timestamp age |
Spec Compliance
This library implements the ia.json v1.0.0 specification:
- Discovery at
/ia.jsonand/.well-known/ia.json - Version validation (major version check)
- File size limit enforcement (1 MB)
- All three access levels:
public,protected,user_required - HMAC-SHA256 and HMAC-SHA512 request signing
- Timestamp-based replay attack prevention
- Agent registration and domain verification flow
- OAuth2 with PKCE support
- Structured error responses per the spec format
License
MIT License. See the ia.json project for the full specification.