PHP code example of allus / company-data

1. Go to this page and download the library: Download allus/company-data library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

allus / company-data example snippets



Allus\CompanyData\Client;
use Allus\CompanyData\Model\Change;

$client = Client::fromConfig('config.json');

$client->processChanges(function (Change $change): void {
    // one update at a time: event, person, slug, value, live, at
    printf("%s %s %s %s %s %s\n",
        $change->event, $change->personId, $change->slug ?? '—',
        is_scalar($change->value) ? (string) $change->value : '…',
        $change->live ? 'live' : 'snapshot',
        $change->at?->format('c') ?? '—',
    );
});   // returns when the feed is empty


Allus\CompanyData\Client;

$client = Client::fromConfig('allus.json');

// Iterate every connected person (lazy, auto-paged Generator).
foreach ($client->connections() as $conn) {
    echo $conn->displayName, ' ', $conn->personId, PHP_EOL;
    foreach ($conn->values as $slug => $val) {
        printf("  %s = %s  (live=%s, updated=%s)\n",
            $slug,
            is_scalar($val->value) ? (string) $val->value : json_encode($val->value),
            $val->live ? 'true' : 'false',
            $val->updatedAt?->format('c') ?? '—',
        );
    }
    break; // just the first one for the demo
}

$conn  = $client->connection('019xxxxxxxxxxxxxxxxxxxxxxxxx');
$email = $conn->values['work_email']->value;   // "[email protected]"  (a string)

Client::fromConfig(string $path, ?HttpClient $http = null, ?Logger $logger = null, ?callable $sleep = null): Client
Client::fromEnv(?HttpClient $http = null, ?Logger $logger = null, ?callable $sleep = null): Client

requestFields(): array  // list<RequestField>

foreach ($client->requestFields() as $f) {
    $flag = $f->mandatory ? 'mandatory' : 'optional';
    printf("%-20s %-10s %s%s\n", $f->slug, $f->type, $flag, $f->oneTime ? ' (one-time)' : '');
}

connections(int $limit = 100, int $offset = 0): \Generator   // Generator<Connection>

// Initial full sync, streaming so a 100k-connection book never lands in memory.
foreach ($client->connections(limit: 200) as $conn) {
    upsertLocalRecord($conn);
}

connection(string $id): Connection

$conn  = $client->connection($connId);
$phone = $conn->values['mobile'] ?? null;
if ($phone !== null) {
    echo $phone->value, ' ', $phone->live ? 'live' : 'snapshot', PHP_EOL;
}

logs(int $limit = 50, int $offset = 0): array   // list<LogEntry>

foreach ($client->logs(limit: 20) as $entry) {
    echo $entry->at?->format('c'), ' ', $entry->type, ' ', $entry->message, PHP_EOL;
}

processChanges(
    callable $handler,                 // callable(Change): void
    int $batchSize = 100,              // clamped to ≤ 500
    int $maxRetries = 3,
    string $onError = 'deadletter',    // 'deadletter' | 'halt'
    ?callable $backoff = null,         // callable(int $attempt): float (seconds)
): void

$client->processChanges(function (\Allus\CompanyData\Model\Change $change): void {
    if (alreadyProcessed($change->id)) {   // idempotency — dedup on the stable id
        return;
    }
    match ($change->event) {
        'field_updated'                       => store($change->personId, $change->slug, $change->value),
        'field_deleted', 'connection_deleted' => remove($change->personId, $change->slug),
        default                               => null,
    };
    markProcessed($change->id);
});                                          // returns when the feed is empty

drainBatch(int $max = 100): array                      // list<Change> — raw, UNBUFFERED (you own durability)
deadLetters(): array                                   // list<array> — the local dead-letter store
retryDeadLetters(callable $handler, ...$options): int  // re-drive dead-lettered events; returns count re-driven

foreach ($client->deadLetters() as $dl) {
    printf("stuck: %s %s after %d attempts\n", $dl['id'], $dl['error'], $dl['attempts']);
}

$n = $client->retryDeadLetters($handler);   // after you've fixed the bug
echo "re-drove {$n} dead letters", PHP_EOL;

$client->verifyWebhook(string $rawBody, array $headers): bool
$client->parseWebhook(string $rawBody, array $headers):  Change
$client->handleWebhook(string $rawBody, array $headers): Change   // verify + parse

createDocument(array $opts): Document

use Allus\CompanyData\Client;

$client = Client::fromConfig('allus.json');

// A BROADCAST plaintext JSON document — visible to everyone connected, no target.
$terms = $client->createDocument([
    'name'         => 'Terms of Service v3',
    'payload_kind' => 'json',
    'json_value'   => ['version' => 3, 'effective' => '2026-07-01', 'url' => 'https://acme.example/tos'],
    // no connection_id / person_user_id  → broadcast → plaintext
    // is_private MUST stay false here (a broadcast can't be locked)
]);
echo $terms->id, ' ', $terms->status, PHP_EOL;

// A PER-PERSON document — automatically end-to-end encrypted to the recipient.
// Address it with ONE of: connection_id, person_user_id, or share_code.
$contract = $client->createDocument([
    'name'          => 'Service Agreement',
    'payload_kind'  => 'json',
    'json_value'    => ['plan' => 'pro', 'monthly' => 4900, 'currency' => 'EUR'],
    'connection_id' => $someConnectionId,   // or 'person_user_id' => …, or 'share_code' => 'AB12CD'
    'is_private'    => true,                 // device-display-only; encryption happens regardless
    'status'        => 'offering',
    'metadata'      => ['ref' => 'AGR-2026-118'],
]);

// Read a per-person JSON document back — decryption happens transparently with
// the SDK's own service key (only for the per-person, encrypted shape):
$plain = $client->document($contract->id)->json();   // ['plan' => 'pro', …]

// A file document (raw bytes). Per-person → encrypted; broadcast → plaintext.
$signed = $client->createDocument([
    'name'          => 'Signed PDF',
    'payload_kind'  => 'file',
    'file_bytes'    => file_get_contents('/tmp/agreement.pdf'),
    'file_mime'     => 'application/pdf',
    'person_user_id'=> $personUserId,        // per-person → bytes encrypted on upload
]);

listDocuments(?string $personUserId = null, ?string $status = null, int $limit = 100, int $offset = 0): array  // list<Document>
document(string $documentId): Document

foreach ($client->listDocuments(status: 'active', limit: 50) as $doc) {
    echo $doc->id, ' ', $doc->name, ' [', $doc->status, ']', PHP_EOL;
}

$doc = $client->document($documentId);
$value = $doc->payloadKind === 'json' ? $doc->json() : $doc->value;   // json() decrypts per-person docs

updateDocumentStatus(string $documentId, string $status): Document
updateDocumentMetadata(string $documentId, ?array $metadata = null, ?string $name = null, ?string $description = null): Document
deleteDocument(string $documentId): void

$client->updateDocumentStatus($documentId, 'ready_to_sign');   // offering | ready_to_sign | active | active_but_ending | ended
$client->updateDocumentMetadata($documentId, name: 'Service Agreement (rev B)', metadata: ['ref' => 'AGR-2026-118b']);
$client->deleteDocument($documentId);                          // also removes the on-disk file

$client->processChanges(function (\Allus\CompanyData\Model\Change $change): void {
    if (alreadyProcessed($change->id)) {
        return;
    }
    match ($change->event) {
        'field_updated'           => store($change->personId, $change->slug, $change->value),
        'document_status_changed' => onDocumentStatus($change->documentId, $change->status, $change->personId),
        default                   => null,
    };
    markProcessed($change->id);
});

$addr = $conn->values['home_address']->value;   // array, e.g. ['street' => '...', 'city' => '...', ...]
$dob  = $conn->values['birthday']->value;         // DateTimeImmutable

$handle = $conn->values['passport_scan']->value;   // BinaryHandle (no network yet)

$data = $handle->bytes();                           // GET the slot file → decrypt → file bytes (string)
$n    = $handle->save('/tmp/passport.jpg');         // same, written to disk; returns bytes written
echo $handle->valueUrl();                            // the opaque slot-keyed URL it fetches from


Allus\CompanyData\Client;
use Allus\CompanyData\Model\Change;

$client = Client::fromConfig('allus.json');

$handle = function (Change $change): void {
    if (seen($change->id)) {          // idempotent: skip anything already applied
        return;
    }
    match ($change->event) {
        'field_updated'  => storeValue($change->personId, $change->slug, $change->value, $change->live),
        'field_deleted'  => clearValue($change->personId, $change->slug),
        'connection_deleted' => dropPerson($change->personId),
        'connection_created', 'consent_accepted', 'consent_declined'
                         => noteEvent($change->personId, $change->event, $change->at),
        default          => null,
    };
    recordSeen($change->id);
};

// Schedule your own re-runs; processChanges itself returns when empty.
while (true) {
    $client->processChanges($handle, batchSize: 200, maxRetries: 5);
    sleep(5);
}


Allus\CompanyData\Client;
use Allus\CompanyData\Errors\WebhookError;

$client = Client::fromConfig('allus.json');

$rawBody = file_get_contents('php://input');
$headers = function_exists('getallheaders') ? getallheaders() : [];   // ['X-Allus-Signature' => '…', …]

try {
    $change = $client->handleWebhook($rawBody, $headers);
} catch (WebhookError) {
    http_response_code(401);   // bad / unknown signature, or unparseable envelope
    exit;
}

// Same idempotency rule as the pump: dedup on $change->id.
if (!seen($change->id)) {
    applyChange($change);
    recordSeen($change->id);
}
http_response_code(204);

$headers = [
    'X-Allus-Webhook-Id' => $_SERVER['HTTP_X_ALLUS_WEBHOOK_ID'] ?? '',
    'X-Allus-Signature'  => $_SERVER['HTTP_X_ALLUS_SIGNATURE'] ?? '',
];

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Allus\CompanyData\Errors\WebhookError;

$app->post('/allus/webhook', function (Request $request, Response $response) use ($client) {
    $rawBody = (string) $request->getBody();
    // PSR-7 getHeaders() returns array<string, string[]>; the SDK looks up
    // X-Allus-* case-insensitively and takes the first value of an array.
    try {
        $change = $client->handleWebhook($rawBody, $request->getHeaders());
    } catch (WebhookError) {
        return $response->withStatus(401);
    }
    if (!seen($change->id)) {
        applyChange($change);
        recordSeen($change->id);
    }
    return $response->withStatus(204);
});

if (!$client->verifyWebhook($rawBody, $headers)) {
    http_response_code(401);
    exit;
}
$change = $client->parseWebhook($rawBody, $headers);

use Allus\CompanyData\Client;
use Allus\CompanyData\Errors\{ConfigError, AuthError, ApiError, DecryptError, WebhookError, RateLimitError};

try {
    $client = Client::fromConfig('allus.json');
    foreach ($client->connections() as $conn) {
        // …
    }
} catch (ConfigError $e) {
    // fix the config / key file
} catch (RateLimitError $e) {
    waitSeconds($e->retryAfter ?? 60);
} catch (ApiError $e) {
    log($e->status, $e->errorKey, $e->getMessage());
}
bash
composer g from this repo:  composer install     # from sdks/php/
php -r '