Skip to content

PHP SDK

The Querri PHP SDK (querri/embed) lets you embed Querri analytics into PHP applications. It handles user provisioning, access policy management, embed session creation, and data operations from your server.

Requires PHP 8.3+. Built on Symfony HttpClient.

Terminal window
composer require querri/embed

The fastest way to get an embedded analytics session running in a PHP backend:

use Querri\Embed\QuerriClient;
$querri = new QuerriClient([
'api_key' => $_ENV['QUERRI_API_KEY'], // qk_...
'org_id' => $_ENV['QUERRI_ORG_ID'], // org_...
]);
// Create a session for an end user — one call does everything
$session = $querri->getSession([
'user' => [
'external_id' => $currentUser->id,
'email' => $currentUser->email,
'first_name' => $currentUser->firstName,
'last_name' => $currentUser->lastName,
],
]);
// Return the token to your frontend
echo json_encode(['sessionToken' => $session->sessionToken]);

Then use the Embed SDK on the frontend to render the iframe with that session token.

API keys start with qk_ and are scoped to a single organization. Generate one from Settings > API Keys in the Querri web app.

Every request requires both an API key and an organization ID. You can provide them in three ways:

Option 1: Config array

$querri = new QuerriClient([
'api_key' => 'qk_live_...',
'org_id' => 'org_...',
]);

Option 2: API key string only (org ID from environment)

$querri = new QuerriClient('qk_live_...');
// Reads QUERRI_ORG_ID from environment

Option 3: Environment variables only

Terminal window
export QUERRI_API_KEY="qk_live_..."
export QUERRI_ORG_ID="org_..."
$querri = new QuerriClient(); // reads from environment
ParameterEnv VariableDefaultDescription
api_keyQUERRI_API_KEY(required)Your qk_ API key
org_idQUERRI_ORG_ID(required)Organization ID
hostQUERRI_URLhttps://app.querri.comServer URL
timeout30.0Request timeout in seconds
max_retries3Retry attempts for transient errors

getSession() is the flagship method. It orchestrates three API calls into one:

  1. User resolution — creates or finds the user by external_id
  2. Access policy — auto-creates/reuses a deterministically-named policy (if inline filters are provided)
  3. Session creation — returns an embed session token
$session = $querri->getSession([
'user' => [
'external_id' => 'user-123',
'email' => 'alice@example.com',
'first_name' => 'Alice',
'last_name' => 'Smith',
],
'access' => [
'sources' => ['SOURCE_UUID'],
'filters' => ['region' => 'US'],
],
'ttl' => 3600, // session lifetime in seconds (default: 1 hour)
]);
// GetSessionResult properties:
$session->sessionToken; // pass to the client SDK
$session->userId; // Querri's internal user ID
$session->externalId; // your external_id echoed back
$session->expiresIn; // seconds until expiry

The result implements JsonSerializable, so you can pass it directly to json_encode():

header('Content-Type: application/json');
echo json_encode($session);
// {"session_token":"es_...","expires_in":3600,"user_id":"...","external_id":"user-123"}

User shorthand — if you only need the external ID:

$session = $querri->getSession([
'user' => 'tenant_123',
'origin' => 'https://app.example.com',
]);

You can control what data the user sees in two ways:

Inline filters (recommended for most cases) — the SDK auto-manages the policy:

'access' => [
'sources' => ['source-uuid-1', 'source-uuid-2'],
'filters' => [
'region' => 'US', // single value
'department' => ['Sales', 'Marketing'], // multiple values (OR)
],
],

Pre-created policy IDs — when you manage policies yourself:

'access' => [
'policy_ids' => ['policy-uuid-1', 'policy-uuid-2'],
],

No access block — the user gets full access to all shared resources (no RLS filtering).

If you need more control beyond getSession() auto-management, you can manage policies directly:

Create a policy:

$policy = $querri->policies->create([
'name' => 'US Region Only',
'description' => 'Only see US rows',
'source_ids' => ['source-uuid'],
'row_filters' => [
['column' => 'region', 'values' => ['US']],
],
]);

Assign users to a policy:

$querri->policies->assignUsers($policy['id'], ['user-id-1', 'user-id-2']);

Remove a user from a policy:

$querri->policies->removeUser($policyId, $userId);

Replace all policy assignments for a user:

$querri->policies->replaceUserPolicies($userId, ['policy-id-1', 'policy-id-2']);
// Pass an empty array to remove all policies

Resolve what a user can see:

$resolved = $querri->policies->resolve($userId, $sourceId);

Discover available columns (for building policy UIs):

$columns = $querri->policies->columns($sourceId);

List, retrieve, update, delete:

$policies = $querri->policies->list(['name' => 'US Region']);
$policy = $querri->policies->retrieve($policyId);
$querri->policies->update($policyId, ['name' => 'New Name']);
$querri->policies->del($policyId);
  • Same column, multiple policies = OR. Policies for region = US and region = EU means the user sees US or EU rows.
  • Different columns = AND. Policies for region = US and department = Sales means only rows matching both.
  • No policies assigned = full access (permissive default).
// Create a user
$user = $querri->users->create([
'email' => 'alice@example.com',
'external_id' => 'cust-42',
'first_name' => 'Alice',
'last_name' => 'Smith',
'role' => 'member',
]);
// Get or create by external ID (idempotent)
$user = $querri->users->getOrCreate('cust-42', [
'email' => 'alice@example.com',
'first_name' => 'Alice',
]);
// Retrieve by Querri user ID
$user = $querri->users->retrieve($userId);
// List users
$page = $querri->users->list(['limit' => 50]);
// Filter by external ID
$page = $querri->users->list(['external_id' => 'cust-42']);
// Update a user
$querri->users->update($userId, ['role' => 'admin']);
// Delete a user
$querri->users->del($userId);
// Remove an external ID mapping (without deleting the user)
$querri->users->removeExternalId('cust-42');

If you need lower-level session control beyond getSession():

// Create a session directly
$session = $querri->embed->createSession([
'user_id' => $userId,
'origin' => 'https://myapp.com',
'ttl' => 7200,
]);
// Refresh before expiry
$refreshed = $querri->embed->refreshSession($session['session_token']);
// List active sessions
$sessions = $querri->embed->listSessions(['limit' => 50]);
// Revoke a specific session
$querri->embed->revokeSession($sessionId);
// Revoke all sessions for a user
$querri->embed->revokeUserSessions($userId);

After creating a session, you can create a client that acts as the user. Resources are FGA-filtered — only data the user has access to is returned:

$session = $querri->getSession(['user' => 'ext-123']);
$userClient = $querri->asUser($session);
// These calls are permission-filtered
$projects = $userClient->projects->list();
$dashboards = $userClient->dashboards->list();
$sources = $userClient->sources->list();

Grant access to resources programmatically:

// Share a project with a user
$querri->sharing->shareProject($projectId, [
'user_id' => $userId,
'permission' => 'view', // "view" or "edit"
]);
// Share a dashboard
$querri->sharing->shareDashboard($dashboardId, [
'user_id' => $userId,
'permission' => 'view',
]);
// Enable org-wide sharing for a data source
$querri->sharing->orgShareSource($sourceId, ['enabled' => true]);
// Share a source with a specific user
$querri->sharing->shareSource($sourceId, [
'user_id' => $userId,
'permission' => 'view',
]);
// List and revoke shares
$querri->sharing->listProjectShares($projectId);
$querri->sharing->revokeProjectShare($projectId, $userId);
// List and revoke dashboard shares
$querri->sharing->listDashboardShares($dashboardId);
$querri->sharing->revokeDashboardShare($dashboardId, $userId);

The SDK throws typed exceptions for different failure modes:

use Querri\Embed\Exceptions\AuthenticationException;
use Querri\Embed\Exceptions\NotFoundException;
use Querri\Embed\Exceptions\RateLimitException;
use Querri\Embed\Exceptions\ValidationException;
use Querri\Embed\Exceptions\ServerException;
use Querri\Embed\Exceptions\QuerriException;
try {
$session = $querri->getSession(['user' => 'ext-123']);
} catch (AuthenticationException $e) {
// 401 — Invalid API key
} catch (RateLimitException $e) {
// 429 — Back off and retry
} catch (NotFoundException $e) {
// 404 — Resource not found
} catch (ValidationException $e) {
// 400 — Bad request parameters
} catch (ServerException $e) {
// 5xx — Server error
} catch (QuerriException $e) {
// Catch-all for any SDK error
}
QuerriException
├── ConfigException — missing/invalid configuration
├── ConnectionException — network failures (auto-retried)
│ └── TimeoutException — request timeout exceeded
└── ApiException — HTTP error responses
├── ValidationException — 400
├── AuthenticationException — 401
├── PermissionException — 403
├── NotFoundException — 404
├── ConflictException — 409
├── RateLimitException — 429 (auto-retried)
└── ServerException — 5xx (auto-retried)

The SDK automatically retries on 429 and 5xx errors (up to maxRetries, default 3).

Complete Example: Multi-Tenant Embed with RLS

Section titled “Complete Example: Multi-Tenant Embed with RLS”

This example shows a Laravel route that creates a per-tenant embed session:

use Querri\Embed\QuerriClient;
// Initialize once (e.g., in a service provider)
$querri = new QuerriClient([
'api_key' => config('services.querri.api_key'),
'org_id' => config('services.querri.org_id'),
]);
// In your controller
Route::get('/api/querri-token', function (Request $request) use ($querri) {
$user = $request->user();
$session = $querri->getSession([
'user' => [
'external_id' => (string) $user->id,
'email' => $user->email,
'first_name' => $user->first_name,
'last_name' => $user->last_name,
],
'access' => [
'sources' => [config('services.querri.source_id')],
'filters' => ['tenant_id' => (string) $user->tenant_id],
],
]);
return response()->json($session);
});

Each tenant sees only their rows. One dataset, one embed, automatic filtering.

  • API keys (qk_*) should only be used server-side — never expose them in client code or version control
  • Session tokens (es_*) are safe for the browser — they are scoped and time-limited
  • Set origin in getSession() to restrict which domains can use the session token
  • Use environment variables for credentials (QUERRI_API_KEY, QUERRI_ORG_ID)
  • Rotate API keys periodically via Settings > API Keys

The PHP SDK wraps the Querri V1 API endpoints. For the complete endpoint reference, see API Reference.

SDK ResourceAPI Endpoints
$querri->users/v1/users/*
$querri->embed/v1/embed/sessions/*
$querri->policies/v1/access/policies/*, /v1/access/resolve, /v1/access/columns
$querri->files/v1/files/*
$querri->projects/v1/projects/*
$querri->dashboards/v1/dashboards/*
$querri->data/v1/data/*
$querri->sharing/v1/projects/*/shares, /v1/dashboards/*/shares, /v1/sources/*/shares
$querri->sources/v1/sources/*
$querri->keys/v1/keys/*
$querri->audit/v1/audit/*
$querri->usage/v1/usage/*