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']);
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);