querri / embed
PHP SDK for embedding Querri analytics into your application
Requires
- php: ^8.3
- ext-hash: *
- ext-json: *
- symfony/http-client: ^7.2
Requires (Dev)
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-28 10:46:42 UTC
README
Embed Querri analytics in your PHP application. One method call, zero config.
Laravel | Symfony | Plain PHP | WordPress
PHP SDK for creating embed sessions, managing users, and controlling access policies via the Querri API. Use it with any PHP framework alongside the @querri-inc/embed frontend component. One getSession() call, one server endpoint, and you're done.
Get Started in 60 Seconds
1. Install
composer require querri/embed
2. Create a session
use Querri\Embed\QuerriClient; $client = new QuerriClient([ 'api_key' => 'qk_your_api_key', 'org_id' => 'org_your_org_id', ]); $session = $client->getSession([ 'user' => 'customer-42', // external ID from your system 'ttl' => 3600, ]); echo $session->sessionToken; // opaque `es_…` session token to pass to the frontend
3. Add the embed (React)
import { QuerriEmbed } from '@querri-inc/embed/react'; <QuerriEmbed style={{ width: '100%', height: '600px' }} serverUrl="https://app.querri.com" auth={{ sessionEndpoint: '/api/querri-session' }} />
4. Wire the endpoint
// public/api/querri-session.php (or your framework's route handler) $client = new QuerriClient(); // reads QUERRI_API_KEY + QUERRI_ORG_ID from env $session = $client->getSession([ 'user' => ['external_id' => $authUser->id, 'email' => $authUser->email], // ?: (not ??) so an EMPTY Origin header also falls through to null — // same-origin requests and some proxies send none. A null origin makes // the SDK use your configured default_origin / QUERRI_EMBED_ORIGIN // instead of silently minting a session with no origin binding. 'origin' => ($_SERVER['HTTP_ORIGIN'] ?? '') ?: null, 'ttl' => 3600, ]); header('Content-Type: application/json'); echo json_encode($session);
Set QUERRI_API_KEY and QUERRI_ORG_ID environment variables. In production, always derive user identity from your auth system — never from the request body.
5. Done.
The embed handles auth, token caching, and cleanup automatically.
sequenceDiagram
participant Browser
participant PHP Server
participant Querri API
Browser->>PHP Server: POST /api/querri-session
PHP Server->>Querri API: getOrCreate user + create session
Querri API-->>PHP Server: { session_token }
PHP Server-->>Browser: { session_token }
Browser->>Querri API: Load embed with token
Loading
Security: Always derive user identity and access from your server-side auth system. Never read
useroraccessfrom the request body — a malicious client can impersonate any user or escalate access.
Configuration
The SDK reads configuration from constructor arguments or environment variables:
| Parameter | Env Variable | Default | Description |
|---|---|---|---|
api_key |
QUERRI_API_KEY |
(required) | Your Querri API key (qk_...) |
org_id |
QUERRI_ORG_ID |
(required) | Organization ID — every API call needs it (sent as X-Tenant-ID) |
host |
QUERRI_URL |
https://app.querri.com |
Querri API host |
timeout |
— | 30.0 |
Request timeout in seconds |
max_retries |
— | 3 |
Max retries on 429/5xx errors |
default_origin |
QUERRI_EMBED_ORIGIN |
null |
Origin used for embed sessions when no explicit origin is passed |
// Read from environment variables (QUERRI_API_KEY + QUERRI_ORG_ID) $client = new QuerriClient(); // API key string shorthand (org_id still read from QUERRI_ORG_ID) $client = new QuerriClient('qk_...'); // Full config array $client = new QuerriClient([ 'api_key' => 'qk_...', 'org_id' => 'org_...', 'host' => 'https://app.querri.com', 'timeout' => 30.0, 'max_retries' => 3, 'default_origin' => 'https://app.yoursite.com', // or QUERRI_EMBED_ORIGIN ]);
getSession() — Embed Sessions
The flagship method that creates an embed session in three steps:
- User resolution — creates or retrieves a Querri user by your external ID
- Access policy — auto-creates or reuses a deterministic policy with row-level filters
- Session creation — generates an opaque
es_…session token for the embed iframe
With inline access rules
$session = $client->getSession([ 'user' => [ 'external_id' => 'customer-42', 'email' => 'alice@acme.com', 'first_name' => 'Alice', ], 'access' => [ 'sources' => ['src_sales_data'], 'filters' => [ 'tenant_id' => 'acme', 'region' => ['us-east', 'us-west'], ], ], 'origin' => 'https://app.acme.com', 'ttl' => 7200, ]);
With pre-created policy IDs
$session = $client->getSession([ 'user' => ['external_id' => 'customer-42'], 'access' => ['policy_ids' => ['pol_abc123', 'pol_def456']], ]);
GetSessionResult
$session->sessionToken; // string — opaque `es_…` session token for the embed $session->expiresIn; // int — seconds until expiry $session->userId; // string — Querri user ID $session->externalId; // string|null — your external ID // JSON-serializable for API responses echo json_encode($session); // {"session_token":"...","expires_in":3600,"user_id":"...","external_id":"..."}
Direct Resource Usage
For advanced use cases, access the API resources directly:
Users
$user = $client->users->getOrCreate('ext-123', [ 'email' => 'user@example.com', 'role' => 'member', ]); $user = $client->users->retrieve('usr_abc123'); $users = $client->users->list(['limit' => 50]); $client->users->update('usr_abc123', ['first_name' => 'Alice']); $client->users->del('usr_abc123');
Policies
$policy = $client->policies->create([ 'name' => 'APAC Sales', 'source_ids' => ['src_1'], 'row_filters' => [ ['column' => 'region', 'values' => ['APAC']], ], ]); $client->policies->assignUsers($policy['id'], ['user_ids' => ['usr_abc123']]); $client->policies->removeUser($policy['id'], 'usr_abc123');
Embed Sessions
$session = $client->embed->createSession([ 'user_id' => 'usr_abc123', 'ttl' => 3600, ]); $refreshed = $client->embed->refreshSession($session['session_token']); $client->embed->revokeSession('ses_abc123'); $client->embed->revokeUserSessions('usr_abc123');
All Resources
Beyond the core embed resources above, the SDK provides full access to the Querri API:
| Resource | Access | Key Methods |
|---|---|---|
$client->dashboards |
Dashboard management | list, create, retrieve, update, del, refresh |
$client->projects |
Analysis projects | list, create, retrieve, run, runStatus |
$client->chats |
Chats within projects | create, list, retrieve, del, cancel |
$client->data |
Data sources & queries | list, create, query, appendRows |
$client->sources |
Connectors & sync | listConnectors, list, create, sync |
$client->files |
File management | list, retrieve, del |
$client->keys |
API key management | create, list, retrieve, revoke |
$client->audit |
Audit log | listEvents |
$client->usage |
Usage metrics | getOrgUsage, getUserUsage |
$client->sharing |
Sharing & permissions | shareProject, shareDashboard, shareSource |
See docs/server-sdk.md for complete method signatures and examples.
Error Handling
All errors extend QuerriException. API errors are mapped to specific exception types:
QuerriException
├── ConfigException — missing/invalid configuration
├── ConnectionException — network failures (auto-retried)
│ └── TimeoutException — request timeout exceeded
└── ApiException — HTTP error responses
├── ValidationException — 400/422 (also thrown client-side for invalid ttl/origin)
├── AuthenticationException — 401
├── PermissionException — 403
├── NotFoundException — 404
├── ConflictException — 409
├── RateLimitException — 429 (auto-retried)
└── ServerException — 5xx (auto-retried)
use Querri\Embed\Exceptions\ApiException; use Querri\Embed\Exceptions\AuthenticationException; use Querri\Embed\Exceptions\RateLimitException; use Querri\Embed\Exceptions\ConfigException; try { $session = $client->getSession([...]); } catch (AuthenticationException $e) { // 401 — invalid API key echo "Auth failed: {$e->getMessage()}"; } catch (RateLimitException $e) { // 429 — rate limited (auto-retried up to maxRetries) echo "Rate limited, retry after: {$e->retryAfter}s"; } catch (ApiException $e) { // Any other API error echo "API error {$e->status}: {$e->getMessage()}"; echo "Request ID: {$e->requestId}"; } catch (ConfigException $e) { // Missing API key or invalid config echo $e->getMessage(); }
The SDK automatically retries 429 (always) and 5xx (idempotent methods only) with exponential backoff + jitter, up to max_retries attempts.
Example App
See examples/react-embed/ for a complete working example with a PHP backend and React frontend.
Full Reference
See docs/server-sdk.md for the complete API reference, including every method signature, framework integration guides (Laravel, Symfony), error handling details, and the getSession() deep dive.
Troubleshooting
"API key is required" / "Organization ID is required" errors
Set the QUERRI_API_KEY and QUERRI_ORG_ID environment variables (both are
required since 1.0.0). An org admin creates API keys at app.querri.com/settings/api.
# .env or your server config
QUERRI_API_KEY=qk_your_api_key
QUERRI_ORG_ID=org_your_org_id
The SDK checks getenv(), $_ENV, and $_SERVER — covering CLI, Apache, nginx+FPM, and Docker.
Embed is blank / session endpoint returns 500
Verify your PHP endpoint returns JSON with the correct Content-Type:
header('Content-Type: application/json'); echo json_encode($session); // GetSessionResult is JsonSerializable
CORS errors in development
Use Vite's dev proxy to forward /api requests to your PHP server — no CORS headers needed:
// vite.config.ts server: { proxy: { '/api': 'http://localhost:8080' } }
Class not found errors
Ensure Composer's autoloader is loaded before using SDK classes:
require_once __DIR__ . '/vendor/autoload.php';
Important Notes
- This SDK uses the Server Token auth mode. Your PHP backend creates session tokens and the frontend embed consumes them. For other auth modes (Share Key, Popup Login), see the JS SDK docs.
- Pair this release with
@querri-inc/embed^1.0.0on the frontend. - The session token is an opaque
es_…string, not a JWT — don't try to decode or verify it client-side; pass it through as-is. - React/Vue/Angular: Memoize the
authprop if it's an object. A new object reference on every render cycle causes the iframe to be destroyed and recreated. - The PHP SDK covers the full Querri API (all 13 resources). For frontend-only use cases, see the JS SDK.
Requirements
- PHP 8.3+
ext-jsonext-hashsymfony/http-client^7.2
License
MIT
Support policy
Versions below 1.0.0 receive security fixes only, for 6 months from the 1.0.0 release (2026-08-31). Their data-surface methods call routes the server has removed; migrate with docs/MIGRATION.md.