apertur/sdk

Official Apertur SDK for PHP

Maintainers

Package info

github.com/Apertur-dev/apertur-php

pkg:composer/apertur/sdk

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-04-18 17:37 UTC

This package is auto-updated.

Last update: 2026-05-18 18:10:24 UTC


README

Official PHP SDK for the Apertur API. Supports API key and OAuth token authentication, session management, image uploads (plain and encrypted), long polling, webhook verification, and full resource CRUD.

Installation

Requires PHP 8.1+ and is installed via Composer.

composer require apertur/sdk

Quick Start

Create a client, open an upload session, and upload an image in a few lines. See the API documentation for a full overview.

use Apertur\Sdk\Apertur;

$client = new Apertur(['apiKey' => 'aptr_live_...']);

$session = $client->sessions->create(['label' => 'My shoot']);
$image   = $client->upload->image($session['uuid'], '/path/to/photo.jpg');

echo $image['id'];

Authentication

The client accepts either a long-lived API key or a short-lived OAuth bearer token. Only one is required; providing both will result in the API key being used. See Authentication documentation.

use Apertur\Sdk\Apertur;

// API key
$client = new Apertur(['apiKey' => 'aptr_live_...']);

// OAuth token (e.g. obtained via your auth server)
$client = new Apertur(['oauthToken' => $accessToken]);

// Custom base URL (sandbox)
$client = new Apertur([
    'apiKey'  => 'aptr_live_...',
    'baseUrl' => 'https://sandbox.api.aptr.ca',
]);

Sessions

Upload sessions scope every image upload. You can create a session with optional settings, retrieve it, protect it with a password, and check delivery status. See Sessions documentation.

use Apertur\Sdk\Apertur;

$client = new Apertur(['apiKey' => 'aptr_live_...']);

// Create a session
$session = $client->sessions->create([
    'label'    => 'Wedding reception',
    'password' => 's3cr3t',
    'maxImages' => 200,
]);

// Retrieve session details
$details = $client->sessions->get($session['uuid']);

// Verify a password-protected session before uploading
$result = $client->sessions->verifyPassword($session['uuid'], 's3cr3t');

// Check delivery status — snapshot
$status  = $client->sessions->deliveryStatus($session['uuid']);
$overall = $status['status'];       // pending|active|completed|expired
$files   = $status['files'];
$changed = $status['lastChanged'];  // ISO 8601

// Long-poll for the next change (server holds up to 5 min; use 6 min client timeout)
$next = $client->sessions->deliveryStatus($session['uuid'], $changed, 360.0);

Uploading Images

Upload a plain image using a file path or a PHP stream resource. For end-to-end encrypted uploads, use imageEncrypted with the server's RSA public key. See Upload documentation.

use Apertur\Sdk\Apertur;

$client = new Apertur(['apiKey' => 'aptr_live_...']);
$uuid   = 'session-uuid-here';

// Upload from a file path
$image = $client->upload->image($uuid, '/tmp/photo.jpg', [
    'filename' => 'photo.jpg',
    'mimeType' => 'image/jpeg',
    'source'   => 'my-app',
]);

// Upload from a stream resource
$stream = fopen('/tmp/photo.jpg', 'rb');
$image  = $client->upload->image($uuid, $stream);
fclose($stream);

// Upload to a password-protected session
$image = $client->upload->image($uuid, '/tmp/photo.jpg', [
    'password' => 's3cr3t',
]);

// Encrypted upload (fetch the server key first — see Encryption section)
$serverKey = $client->encryption->getServerKey();
$image = $client->upload->imageEncrypted($uuid, '/tmp/photo.jpg', $serverKey['publicKey'], [
    'filename' => 'photo.jpg',
    'mimeType' => 'image/jpeg',
]);

Long Polling

Poll a session for new images, download each one, and acknowledge receipt to advance the queue. The pollAndProcess helper loops automatically and calls your handler for every image. See Long Polling documentation.

use Apertur\Sdk\Apertur;

$client = new Apertur(['apiKey' => 'aptr_live_...']);
$uuid   = 'session-uuid-here';

// Manual poll / download / ack cycle
$result = $client->polling->list($uuid);
foreach ($result['images'] as $image) {
    $data = $client->polling->download($uuid, $image['id']); // raw binary string
    file_put_contents("/tmp/{$image['id']}.jpg", $data);
    $client->polling->ack($uuid, $image['id']);
}

// Automatic loop with 60-second timeout and 3-second interval
$client->polling->pollAndProcess(
    $uuid,
    function (array $image, string $data): void {
        file_put_contents("/tmp/{$image['id']}.jpg", $data);
        echo "Saved {$image['id']}\n";
    },
    ['interval' => 3, 'timeout' => 60],
);

Receiving Webhooks

Apertur signs every webhook payload so you can verify it was not tampered with. Three verification methods are available: verifySignature for image delivery webhooks, verifyEventSignature for HMAC-signed event webhooks, and verifySvixSignature for Svix-signed event webhooks. See Webhooks documentation.

use Apertur\Sdk\Webhook;

// Laravel middleware example
class VerifyAperturWebhook
{
    public function handle(Request $request, Closure $next): mixed
    {
        $body      = $request->getContent();
        $signature = $request->header('X-Apertur-Signature');
        $secret    = config('services.apertur.webhook_secret');

        if (!Webhook::verifySignature($body, $signature, $secret)) {
            abort(401, 'Invalid webhook signature');
        }

        return $next($request);
    }
}

// Event webhook — HMAC method
$valid = Webhook::verifyEventSignature(
    body:      $body,
    timestamp: $request->header('X-Apertur-Timestamp'),
    signature: $request->header('X-Apertur-Signature'),
    secret:    $secret,
);

// Event webhook — Svix method
$valid = Webhook::verifySvixSignature(
    body:      $body,
    svixId:    $request->header('svix-id'),
    timestamp: $request->header('svix-timestamp'),
    signature: $request->header('svix-signature'),
    secret:    $secret,
);

Destinations

Destinations define where uploaded images are delivered (S3, webhook, long-poll queue, etc.). You can list, create, update, delete, and trigger a test delivery for any destination. See Destinations documentation.

use Apertur\Sdk\Apertur;

$client    = new Apertur(['apiKey' => 'aptr_live_...']);
$projectId = 'proj_...';

// List all destinations for a project
$list = $client->destinations->list($projectId);

// Create a new destination
$dest = $client->destinations->create($projectId, [
    'type'   => 's3',
    'label'  => 'Primary S3 bucket',
    'config' => ['bucket' => 'my-bucket', 'region' => 'us-east-1'],
]);

// Update a destination
$updated = $client->destinations->update($projectId, $dest['id'], [
    'label' => 'Primary S3 bucket (updated)',
]);

// Trigger a test delivery
$testResult = $client->destinations->test($projectId, $dest['id']);

// Delete a destination
$client->destinations->delete($projectId, $dest['id']);

API Keys

API keys are scoped to a project and optionally restricted to specific destinations. You can list, create, update, delete, and reassign destinations for any key. See API Keys documentation.

use Apertur\Sdk\Apertur;

$client    = new Apertur(['apiKey' => 'aptr_live_...']);
$projectId = 'proj_...';

// List keys
$keys = $client->keys->list($projectId);

// Create a key
$key = $client->keys->create($projectId, [
    'label' => 'Mobile app key',
]);

// Update a key
$client->keys->update($projectId, $key['id'], ['label' => 'Mobile app key v2']);

// Assign destinations (and optionally enable long polling)
$client->keys->setDestinations($key['id'], ['dest_abc', 'dest_def'], longPolling: true);

// Delete a key
$client->keys->delete($projectId, $key['id']);

Event Webhooks

Event webhooks push real-time notifications to your endpoint for events such as image uploads and session state changes. You can manage webhooks, inspect delivery history, and retry failed deliveries. See Event Webhooks documentation.

use Apertur\Sdk\Apertur;

$client    = new Apertur(['apiKey' => 'aptr_live_...']);
$projectId = 'proj_...';

// List webhooks
$webhooks = $client->webhooks->list($projectId);

// Create a webhook
$webhook = $client->webhooks->create($projectId, [
    'url'    => 'https://example-website.com/webhooks/apertur',
    'events' => ['image.uploaded', 'session.completed'],
]);

// Update a webhook
$client->webhooks->update($projectId, $webhook['id'], [
    'events' => ['image.uploaded'],
]);

// Trigger a test delivery
$client->webhooks->test($projectId, $webhook['id']);

// List delivery attempts (paginated)
$deliveries = $client->webhooks->deliveries($projectId, $webhook['id'], [
    'page'  => 1,
    'limit' => 25,
]);

// Retry a failed delivery
$client->webhooks->retryDelivery($projectId, $webhook['id'], $deliveries['data'][0]['id']);

// Delete a webhook
$client->webhooks->delete($projectId, $webhook['id']);

Encryption

Apertur supports end-to-end encrypted uploads using RSA-OAEP + AES-256-GCM. Fetch the server's RSA public key, then pass it to upload->imageEncrypted. The Crypto class handles key wrapping and encryption automatically. See Encryption documentation.

use Apertur\Sdk\Apertur;

$client = new Apertur(['apiKey' => 'aptr_live_...']);

// Step 1: retrieve the server's RSA public key
$serverKey = $client->encryption->getServerKey();
// $serverKey['publicKey'] is a PEM-encoded RSA public key

// Step 2: upload an encrypted image — the SDK handles AES-256-GCM + RSA-OAEP wrapping
$image = $client->upload->imageEncrypted(
    'session-uuid-here',
    '/tmp/photo.jpg',
    $serverKey['publicKey'],
    ['filename' => 'photo.jpg', 'mimeType' => 'image/jpeg'],
);

echo $image['id'];

Error Handling

All API errors throw typed exceptions that extend AperturException. Catch the specific subclass you care about, or catch AperturException as a fallback for any API error. See Error Handling documentation.

use Apertur\Sdk\Apertur;
use Apertur\Sdk\Exception\AperturException;
use Apertur\Sdk\Exception\AuthenticationException;
use Apertur\Sdk\Exception\NotFoundException;
use Apertur\Sdk\Exception\RateLimitException;
use Apertur\Sdk\Exception\ValidationException;

$client = new Apertur(['apiKey' => 'aptr_live_...']);

try {
    $session = $client->sessions->create(['label' => 'My shoot']);
    $image   = $client->upload->image($session['uuid'], '/tmp/photo.jpg');
} catch (AuthenticationException $e) {
    // 401 — invalid or missing API key / token
    echo "Auth failed: {$e->getMessage()}\n";
} catch (NotFoundException $e) {
    // 404 — session or resource not found
    echo "Not found: {$e->getMessage()}\n";
} catch (RateLimitException $e) {
    // 429 — back off and retry
    $retryAfter = $e->getRetryAfter(); // seconds, or null
    echo "Rate limited. Retry after {$retryAfter}s\n";
} catch (ValidationException $e) {
    // 400 — invalid request payload
    echo "Validation error: {$e->getMessage()}\n";
} catch (AperturException $e) {
    // Any other API error
    echo "API error {$e->getStatusCode()}: {$e->getMessage()} [{$e->getErrorCode()}]\n";
}

API Reference

Full API reference, guides, and changelog are available at docs.apertur.ca.

License

This package is open-source software licensed under the MIT license.