PHP code example of getokta / okta-connect-sdk

1. Go to this page and download the library: Download getokta/okta-connect-sdk 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/ */

    

getokta / okta-connect-sdk example snippets


use Okta\Connect\WhatsApp\Client;

$client = new Client(
    baseUrl: 'https://connect.example.com',
    token: 'sanctum_token_here',
    options: ['timeout' => 30, 'retries' => 2],
);

// Typed helpers build the correct request shape for you:
$client->messages()->sendText('01H...channel', '966500000000', 'Hello');
$client->messages()->sendMedia('01H...channel', '966500000000', 'image', 'https://cdn.example.com/a.jpg', 'Look!');
$client->messages()->reply('01H...conversation', 'Thanks!');

// Or send a raw payload (flat shape: channel_id + wa_id + body, or conversation_id + body):
$client->messages()->send([
    'channel_id' => '01H...',
    'wa_id'      => '966500000000',
    'type'       => 'text',
    'body'       => 'Hello',
]);

$messages      = $client->messages()->list(['conversation_id' => '01H...', 'per_page' => 50]);
$conversations = $client->conversations()->list();
$conversation  = $client->conversations()->get($id);
$contacts      = $client->contacts()->list(['search' => '+966']);
$client->contacts()->upsert(['phone' => '+9665...', 'name' => 'Ali']);
$channels      = $client->channels()->list();
$client->webhooks()->register(['url' => 'https://...', 'events' => ['message.received']]);

// Channels filter by platform type and connection status — `type` takes a
// channel type value (cloud_api / baileys / telegram / instagram_dm /
// twitter / linkedin / tiktok / email) or the family alias `whatsapp`
// (covers cloud_api + baileys); `status` is connected / disconnected /
// pending / failed:
$client->channels()->list(['type' => 'telegram', 'status' => 'connected']);
$client->channels()->listByType('tiktok', 'connected', ['per_page' => 5]);
$client->channels()->whatsapp('connected');       // both WhatsApp flavours
$client->channels()->connected();                 // any platform, connected
$client->channels()->disconnected('instagram_dm');

// Prune stale channels — e.g. old WhatsApp links never scanned. delete()
// needs a `write` (or `admin`) token; it disconnects + emits channel.deleted.
foreach ($client->channels()->awaitingScan('baileys')->items() as $stale) {
    $client->channels()->delete($stale->id);
}

// Meta message templates
$templates = $client->templates()->list(['status' => 'APPROVED', 'language' => 'ar']);
$client->templates()->send([
    'channel_id'    => '01H...',
    'wa_id'         => '966500000000',
    'template_name' => 'order_ready',
    'language'      => 'ar',
    'variables'     => ['12345', '120 SAR'],
]);

// WhatsApp groups (Baileys-only)
$group = $client->groups()->create('Sales pod', ['966500000000', '966500000001']);
$client->groups()->addParticipants($group->id, ['966500000002']);

// Send an email
$email = $client->emails()->send([
    'from'    => 'Acme <[email protected]>',   // bare address also accepted
    'to'      => ['[email protected]'],
    'subject' => 'Your receipt',
    'html'    => '<h1>Thanks!</h1>',
    'text'    => 'Thanks!',                       // at least one of html/text/template
], idempotencyKey: 'order-1042-receipt');

echo $email->status;   // queued | sent | delivered | bounced | complained | failed

// …or render a stored template with variables
$client->emails()->sendTemplate(
    from: 'Acme <[email protected]>',
    to: ['[email protected]'],
    template: 'order-receipt',                    // slug or ULID
    variables: ['order_id' => '1042'],
);

// …or design a branded message in code — HtmlMessageBuilder emits
// email-client-safe HTML (table layout, inlined CSS, 600px centered card;
// Gmail/Outlook-proof). RTL-first: make() defaults to dir="rtl" lang="ar".
use Okta\Connect\WhatsApp\Email\HtmlMessageBuilder;

$message = HtmlMessageBuilder::make()             // make(false) ⇒ LTR
    ->brandColor('#10b981')
    ->logo('https://cdn.acme.com/logo.png')
    ->preheader('طلبك في الطريق')                 // hidden inbox preview text
    ->heading('شكراً لطلبك!')
    ->paragraph('طلبك رقم 1042 قيد التجهيز الآن.')
    ->button('تتبع الطلب', 'https://acme.com/orders/1042')
    ->divider()
    ->footer('© 2026 Acme — جميع الحقوق محفوظة');

// sendHtml() accepts the builder directly (any Stringable) and a bare
// string recipient; both are normalised for you:
$client->emails()->sendHtml(
    'Acme <[email protected]>',
    '[email protected]',
    'طلبك رقم 1042',
    $message,
);

// Send log + a single message
$sent = $client->emails()->list(['status' => 'delivered', 'per_page' => 50]);
$one  = $client->emails()->get('01H...');

// Delivery analytics (defaults to the last 30 days)
$stats = $client->emails()->analytics(from: '2026-06-01', to: '2026-06-30');
echo $stats->summary['delivery_rate'];

// Reusable templates
$tpl = $client->emails()->templates()->create([
    'name'    => 'Order receipt',
    'subject' => 'Your order {{ order_id }} is confirmed',
    'html'    => '<p>Hi {{ name }}, order {{ order_id }} is on the way.</p>',
]);
$client->emails()->templates()->update($tpl->id, ['subject' => 'Order {{ order_id }} shipped']);

// Bulk broadcasts to a CRM-tag audience
$bc = $client->emails()->broadcasts()->create([
    'name'     => 'July newsletter',
    'from'     => 'Acme <[email protected]>',
    'subject'  => "What's new in July",
    'html'     => '<h1>Hello!</h1>',
    'audience' => ['tag_slugs' => ['newsletter']],   // omit ⇒ everyone with an email
]);
$client->emails()->broadcasts()->queue($bc->id);      // fan out one send per recipient

// Suppression list (bounces/complaints are added automatically; you can add manually)
$client->emails()->suppressions()->add('[email protected]');
$client->emails()->suppressions()->remove('[email protected]');

$post = $client->socialPosts()->schedule(
    text: 'New drop is live! 🎉',
    channelIds: ['01H...x', '01H...telegram'],
    scheduledAt: '2026-07-20T09:00:00+00:00',
    media: [['url' => 'https://cdn.example.com/promo.jpg', 'type' => 'image']],
);

$client->socialPosts()->draft('Behind the scenes…', ['01H...instagram']);

// Read each platform's outcome — including the upstream failure reason
foreach ($client->socialPosts()->get($post->id)->targets as $t) {
    echo "{$t->status} → {$t->permalink}\n";
}

$campaign = $client->campaigns()->create([
    'name'            => 'Ramadan promo',
    'channel_id'      => '01H...channel',
    'template_id'     => '01H...template',
    'audience_filter' => ['tag_slugs' => ['vip']],
]);
$client->campaigns()->queue($campaign->id);

use Okta\Connect\WhatsApp\Client;

$connect     = Client::connect('https://connect.getokta.io'); // no token yet
$redirectUri = 'https://crm.example.com/oktawa/callback';

// 1) Redirect the user to the consent screen. Keep `state` in the session.
$state = \Okta\Connect\WhatsApp\Connect\Connect::generateState();
$_SESSION['okta_state'] = $state;

$url = $connect->authorizationUrl(
    appName:     'My CRM',
    redirectUri: $redirectUri,
    abilities:   ['read', 'send'],   // subset of read/write/send/webhooks/admin
    state:       $state,
    logoUrl:     'https://cdn.my-crm.com/logo.png', // optional — shown on consent (https only)
);
// header('Location: '.$url);

// 2) On the callback, verify state and exchange the code in one call:
$token  = $connect->handleCallback($_GET, $redirectUri, $_SESSION['okta_state']);

// 3) You now have a ready-to-use token — build a client and go.
$client = new Client('https://connect.getokta.io', $token->accessToken);

$token->abilities;          // ['read', 'send'] — what the user granted
$token->can('send');        // true
$token->expiresAt;          // ISO-8601 string, or null

$conn = $client->connection();          // DTO\Connection
$conn->abilities;                       // ['read', 'send']
$conn->logoUrl;                         // the app logo you passed at connect (or its favicon)
$conn->can('admin');                    // false
$missing = $conn->missing(['read', 'admin']);   // ['admin']

if ($missing !== []) {
    // Send the user back through Connect with the fuller ability set.
    $url = Client::connect($baseUrl)->authorizationUrl(
        appName: 'My CRM', redirectUri: $redirectUri,
        abilities: ['read', 'send', 'admin'], state: $state,
    );
}

$client->revokeConnection();   // true; every later call with this token 401s

use Okta\Connect\WhatsApp\Embed\EmbedUser;
use Okta\Connect\WhatsApp\Embed\UiHide;

$embed = $client->embed($sharedSecret);              // base URL reused from the client
$operator = new EmbedUser(sub: 'partner-user-7', email: '[email protected]', name: 'Op');

// Cookieless per-request flow (survives third-party-cookie blocking). The token
// rides every request inside the iframe — recommended for white-label embeds.
$src = $embed->inboxUrl($operator, uiHide: [UiHide::AI, UiHide::ASSIGN_AGENT]);
// <iframe src="<?= $src 

$operator = new EmbedUser(
    sub: 'partner-user-7',
    email: '[email protected]',
    name: 'Op',
    workspace: $workspaceUlid,   // rides along as the `workspace` claim
);

use Okta\Connect\WhatsApp\Partner\PartnerClient;

$partner = PartnerClient::withKeyPair(
    'https://connect.getokta.io',
    $clientId,
    $clientSecret,
);

// Prove the key is live before a provisioning run half-completes.
$me = $partner->me();
$me->can('workspaces.write');   // → bool

// Idempotent on external_id: a retry after a timeout matches instead of
// minting a duplicate, and says which happened.
$result = $partner->workspaces()->create([
    'name'        => 'Acme Support',
    'external_id' => 'acct_8891',
    'locale'      => 'ar',
    'owner'       => ['name' => 'Sara', 'email' => '[email protected]', 'password_auto' => true],
]);

$result->created;               // false on a repeat
$result->oneTimePassword();     // shown once, on creation only

// Membership — an email Connect already knows is reused, never overwritten.
$member = $partner->users()->add($result->workspace->id, [
    'name' => 'Khalid', 'email' => '[email protected]', 'role' => 'agent', 'password_auto' => true,
]);

// A tenant token for that workspace's own data plane…
$token = $partner->tokens()->create(
    $result->workspace->id,
    'Acme product sync',
    $member->user->id,
    ['read', 'send'],
);

// …and a client that uses it. `admin` is not mintable here, by design.
$workspace = $partner->workspaceClient($token);
$workspace->contacts()->list();

// Drop an existing member straight into the dashboard. Single-use, 5 minutes,
// membership re-checked at redemption.
$link = $partner->sso()->issue($result->workspace->id, $member->user->id, '/app/inbox');

$secret = $partner->embed()->issueSecret(['https://mygurb.com', 'https://*.mygurb.com']);
$secret->secret;    // returned exactly once

// Check what the platform refused: an origin that did not parse fails later as a
// blank iframe with a 200 and no failed request.
$origins = $partner->embed()->setOrigins(['https://mygurb.com', 'https://inbox.customer.example']);
$origins->rejected;

// A signer already wired to partner:{your-ulid} — the issuer is derived, not typed.
$embed = $partner->embedSigner($secret->secret);
$src = $embed->inboxUrl(new EmbedUser('gurb-1', '[email protected]', 'Op', $workspaceUlid));

$session = $workspace->qr()->start('Community line');

do {
    sleep(3);
    $session = $workspace->qr()->status($session->id);

    if ($session->hasError()) {
        // gateway_unavailable is worth retrying; pairing_failed and qr_expired
        // need a NEW session, and disconnected means it linked and dropped.
        if (! $session->isRetryable()) {
            break;
        }
    }

    // $session->qr is the string to render; $session->qrTtlSeconds the countdown.
} while (! $session->isTerminal());

use Okta\Connect\WhatsApp\Enums\WebhookEvent;
use Okta\Connect\WhatsApp\Resources\Webhooks;

$hook = $client->webhooks()->create([
    'name'   => 'Lifecycle',
    'url'    => 'https://example.test/hooks/okta',
    'events' => [
        WebhookEvent::SubscriptionExpired->value,   // subscription ended
        WebhookEvent::SubscriptionCancelled->value, // cancelled
        WebhookEvent::ChannelDeleted->value,        // a channel was removed
        WebhookEvent::ChannelDisconnected->value,   // …or disconnected
    ],
    // 'events' => [WebhookEvent::All->value],       // or receive everything
]);

$secret = $hook->secret; // shown ONCE — persist it now

$client->webhooks()->list();          // PaginatedResult<Webhook> (no secret)
$client->webhooks()->delete($hook->id);

$ok = Webhooks::verifySignature(
    rawBody: file_get_contents('php://input'),
    signatureHeader: $_SERVER['HTTP_X_OKTA_SIGNATURE'] ?? '',
    secret: $secret,
);

use Okta\Connect\WhatsApp\Enums\WebhookEvent;
use Okta\Connect\WhatsApp\Resources\Webhooks;

$hook = Webhooks::parse(
    rawBody: file_get_contents('php://input'),
    signatureHeader: $_SERVER['HTTP_X_OKTA_SIGNATURE'] ?? '',
    secret: $secret,                                 // throws on a bad signature
);

match ($hook->type()) {
    WebhookEvent::MessageSent, WebhookEvent::MessageReceived => handleMessage(
        conversation: $hook->conversationId(),   // which conversation
        channel:      $hook->channelType(),      // which channel
        body:         $hook->messageBody(),
        isReply:      $hook->isReply(),          // …and whether it's a reply
    ),
    WebhookEvent::MessageDelivered, WebhookEvent::MessageRead => updateReceipt($hook),
    WebhookEvent::ChannelDeleted   => teardown($hook->get('channel.id')),
    default => null,
};
// $hook->get('any.dotted.path') reads anything from the event payload.

use Okta\Connect\WhatsApp\Enums\WebhookEvent;
use Okta\Connect\WhatsApp\Webhook\WebhookRouter;

(new WebhookRouter($secret))                     // verifies the signature
    ->on(WebhookEvent::MessageReceived, fn ($h) => reply($h->message()->conversationId()))
    ->onMessage(fn ($h) => log($h->message()->status()))   // any message.*
    ->onChannel(fn ($h) => sync($h->channel()->channelId()))
    ->onSubscription(fn ($h) => billing($h->subscription()->status()))
    ->onAny(fn ($h) => audit($h))                          // fallback
    ->dispatch(file_get_contents('php://input'), $_SERVER['HTTP_X_OKTA_SIGNATURE'] ?? '');

// Support tickets
$ticket = $client->tickets()->open(['subject' => 'Order stuck', 'contact_id' => $contactUlid]);
$client->tickets()->transition($ticket->id, ['stage_id' => $resolvedStageUlid]);
$client->tickets()->list(['status' => 'open']);   // PaginatedResult<Ticket>

// CRM tags — apply slugs to a contact (unknown slugs are created)
$client->tags()->applyToContact($contactUlid, ['vip', 'lead']);
$client->tags()->list();                           // PaginatedResult<Tag>

// Read-only analytics — aggregate totals over a date range
$m = $client->analytics()->metrics(['from' => '2026-06-01', 'to' => '2026-06-30', 'platform' => 'whatsapp']);
$m->metric('messages.inbound');                    // 120

$client->messages()->send($payload, idempotencyKey: 'order-1234-confirmation');