Docs · SDKs
PHP SDK
Install the PHP SDK, build a client, see every method with a PHP sample, and verify records offline.
Install
PHP
invoance/invoance on Packagist.
PHP 8.1 or later with the curl, sodium, json and mbstring extensions. No Composer dependencies.
Terminal
composer require invoance/invoance
Client
api_key | The API key. Falls back to INVOANCE_API_KEY; InvalidArgumentException when neither is set. |
|---|---|
base_url | API host. Falls back to INVOANCE_BASE_URL, then https://api.invoance.com. Trailing slashes are removed. |
api_version | Path prefix put before every request path. Default v1. |
| timeout | Per-request timeout in seconds. Default 30; past it the call throws TimeoutException. |
idempotency_key | Default Idempotency-Key header for every mutating request; a per-call key wins. |
extra_headers | Headers merged into every request. |
| Retries | None. Each request is sent once; on TimeoutException or NetworkException, retry it yourself with the same idempotency_key. |
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY and INVOANCE_BASE_URL from the environment.
$client = new Client();
// Or pass options.
$configured = new Client([
'api_key' => 'invoance_live_...',
'base_url' => 'https://api.invoance.com',
'timeout' => 60,
]);
// GET /v1/me checks no scope, so any live key passes. Never throws.
$result = $client->validate();
echo $result['valid'] ? "ok\n" : "{$result['reason']}\n";
Methods
Every endpoint with a PHP sample, by resource. Open a row for the sample; the link opens the endpoint card with its fields, response and errors.
EventsReference
POST/v1/events
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$result = $client->events->ingest([
'eventType' => 'policy.approval',
'eventTime' => '2026-09-22T08:14:07Z',
'payload' => [
'policy_id' => 'pol_8472',
'approved_by' => 'risk_committee',
'decision' => 'approved',
],
'idempotencyKey' => 'policy-approval-pol_8472',
]);
echo $result['event_id'], ' ', $result['ingested_at'], "\n";
GET/v1/events
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$page = $client->events->list([
'page' => 1,
'limit' => 50,
'eventType' => 'policy.approval',
]);
echo $page['total'], ' ', $page['has_more'] ? 'true' : 'false', "\n";
foreach ($page['events'] as $event) {
echo $event['event_id'], ' ', $event['ingested_at'], ' ', $event['payload_hash'], "\n";
}
GET/v1/events/{event_id}
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$event = $client->events->get('7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4');
echo $event['event_type'], ' ', $event['ingested_at'], "\n";
echo $event['payload_hash'], ' ', $event['event_hash'], ' ', $event['request_hash'], "\n";
print_r($event['payload']);
POST/v1/events/{event_id}/verify
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$result = $client->events->verify('7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4', [
'payload' => [
'policy_id' => 'pol_8472',
'approved_by' => 'risk_committee',
'decision' => 'approved',
],
]);
echo $result['match_result'] ? 'true' : 'false', ' ', $result['matched_field'] ?? 'null', "\n";
echo $result['anchored_hash'], ' ', $result['submitted_hash'], ' ', $result['anchored_at'], "\n";
DocumentsReference
POST/v1/document/anchor
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
$documentHash = hash_file('sha256', './INV-2026-0917.pdf');
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$result = $client->documents->anchor([
'documentHash' => $documentHash,
'documentRef' => 'INV-2026-0917.pdf',
'eventType' => 'invoice.issued',
'metadata' => [
'invoice_number' => 'INV-2026-0917',
'amount' => 5230,
'currency' => 'USD',
],
'idempotencyKey' => 'anchor-' . $documentHash,
]);
echo $result['event_id'], ' ', $result['status'], "\n";
GET/v1/document
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$page = $client->documents->list([
'limit' => 25,
'dateFrom' => '2026-09-01T00:00:00Z',
]);
echo $page['total'], ' ', $page['has_more'] ? 'true' : 'false', "\n";
foreach ($page['documents'] as $d) {
echo $d['event_id'], ' ', $d['document_ref'], ' ', $d['has_original'] ? 'true' : 'false', "\n";
}
GET/v1/document/{event_id}
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$doc = $client->documents->get('7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4');
echo $doc['document_hash'], ' ', $doc['has_original'] ? 'true' : 'false', ' ', $doc['created_at'], "\n";
if (isset($doc['organization'])) {
echo $doc['organization']['issuer_name'], ' ', $doc['organization']['domain_verified'] ? 'true' : 'false', "\n";
}
GET/v1/document/{event_id}/original
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$data = $client->documents->getOriginal('7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4');
file_put_contents('./INV-2026-0917.pdf', $data);
echo strlen($data), "\n";
POST/v1/document/{event_id}/verify
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
$documentHash = hash_file('sha256', './INV-2026-0917.pdf');
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$result = $client->documents->verify('7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4', [
'documentHash' => $documentHash,
]);
echo $result['match_result'] ? 'true' : 'false', ' ', $result['anchored_hash'], ' ', $result['anchored_at'], "\n";
AI AttestationsReference
POST/v1/ai/attestations
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$result = $client->attestations->ingest([
'type' => 'output',
'input' => 'Summarize the termination clause in contract CT-8472.',
'output' => 'Either party may terminate with 30 days written notice. Early termination fees do not apply after month 12.',
'modelProvider' => 'openai',
'modelName' => 'gpt-4.1',
'modelVersion' => '2026-04-14',
'subject' => ['userId' => 'u_4821', 'sessionId' => 'sess_9f3a', 'department' => 'legal'],
'idempotencyKey' => 'ct-8472-summary-1',
]);
echo $result['attestation_id'], ' ', $result['payload_hash'], "\n";
GET/v1/ai/attestations
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$page = $client->attestations->list([
'limit' => 50,
'attestationType' => 'output',
'modelProvider' => 'openai',
]);
echo $page['total'], ' ', count($page['attestations']), "\n";
GET/v1/ai/attestations/{attestation_id}
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$att = $client->attestations->get('7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4');
echo $att['attestation_hash'], ' ', $att['signature_alg'], ' ', $att['public_key'], "\n";
GET/v1/ai/attestations/{attestation_id}/raw
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$raw = $client->attestations->getRaw('7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4');
echo $raw['type'], ' ', $raw['context']['model_name'], "\n";
POST/v1/ai/attestations/{attestation_id}/verify
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$result = $client->attestations->verify('7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4', [
'contentHash' => 'c4efe15781214a84046ad7e0592977c634a5cf45f4c1e06160daf760a295a8df',
]);
echo $result['match_result'] ? "match\n" : "no match\n";
echo $result['matched_field'] ?? 'none', "\n";
TracesReference
POST/v1/traces
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$trace = $client->traces->create([
'label' => 'Invoice batch 2026-09',
'metadata' => ['batch_id' => 'b_4471', 'region' => 'eu-west'],
]);
echo $trace['trace_id'], ' ', $trace['status'], "\n";
POST/v1/traces/{trace_id}/seal
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$sealed = $client->traces->seal('7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4');
echo $sealed['status'], ' ', $sealed['message'], "\n";
Audit LogsReference
POST/v1/audit/events
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$result = $client->audit->events->ingest([
'organizationId' => 'org_8472',
'action' => 'user.signed_in',
'occurredAt' => '2026-09-22T08:14:07Z',
'actor' => ['type' => 'user', 'id' => 'u_4821', 'name' => 'Ada Lovelace'],
'targets' => [['type' => 'workspace', 'id' => 'ws_17']],
'context' => ['location' => '203.0.113.10', 'user_agent' => 'Mozilla/5.0'],
'metadata' => ['method' => 'sso', 'mfa' => true],
'idempotencyKey' => 'signin-u_4821-2026-09-22T08:14:07Z',
]);
echo $result['event_id'], ' ', $result['ingested_at'], "\n";
POST/v1/audit/orgs
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$org = $client->audit->orgs->create([
'organizationId' => 'org_8472',
'name' => 'Acme Robotics',
]);
echo $org['id'], ' ', $org['retention_days'], "\n";
PlatformReference
GET/v1/me
PHP
<?php
require 'vendor/autoload.php';
use Invoance\Client;
// Reads INVOANCE_API_KEY from the environment.
$client = new Client();
$me = $client->me();
echo $me['organization']['primary_domain'], "\n";
echo implode(',', $me['api_key']['scopes']), "\n";
echo $me['limits']['rate_limit_per_sec'], "\n";
Verify offlineHow verification works
Two checks run without trusting the server: attestations->verifySignature fetches the record and checks its Ed25519 signature over signed_payload with sodium; AuditVerify::verifyAuditEvent rebuilds the invoance.audit/1 bytes of an audit event and checks its signature. Pass the hex key from GET /keys/{domain} as the second argument to pin it instead of the key on the row.
PHP
<?php
require 'vendor/autoload.php';
use Invoance\AuditVerify;
use Invoance\Client;
$client = new Client();
// AI attestation: Ed25519 over signed_payload, checked locally.
$sig = $client->attestations->verifySignature('a1d4f8c2-7b3e-4e9a-b5c6-0d2e8f4a7c19');
echo $sig['valid'] ? "valid\n" : "{$sig['reason']}\n";
// Audit event: canonical bytes rebuilt locally, signature checked
// against a pinned key (the public_key from GET /keys/{domain}, base64url decoded to hex).
$pinnedHexKey = 'd4443bd9d30ef4c2e0e5db03467e3c5c740358482c1a1e30cdb27a2e02a38176';
$event = $client->audit->events->get('aevt_01J8F3KQ2R7VWX9YB4ND6MCZAH');
$result = AuditVerify::verifyAuditEvent($event, $pinnedHexKey);
echo $result['valid'] ? "valid ({$result['keySource']})\n" : "{$result['reason']}\n";