Search by

uchara / uchara-php

Official PHP SDK for Uchara Chat Platform — server-side API integration and visitor widget SDK

Maintainers

Fund package maintenance!

bayubmtr

Statistics

Installs: 41

Dependents: 0

Suggesters: 0

Stars: 0

v1.2.0 2026-08-31 15:31 UTC

This package is auto-updated.

Last update: 2026-08-31 15:31:34 UTC


README

Official PHP SDK for the Uchara Chat Platform. It provides:

  • ServerSDK — server-to-server integration with the authenticated /v1/* REST API (members/agents, invites, channels, bots, conversations, messages, contacts, canned responses, API keys).
  • AgentSDK — authenticate human workspace agents with email/password JWTs and send messages attributed to the logged-in agent.
  • VisitorSDK — embed the chat widget in customer applications via the public /v1/widget/* endpoints.
  • Laravel integration — a service provider, manager, facade and config file with auto-discovery for Laravel 10/11. The native SDK itself has no Laravel dependency.

Requirements

  • PHP 8.1 or higher
  • Composer
  • ext-json

Installation

composer require uchara/uchara-php

For Laravel 10/11 the service provider and facade are registered automatically via package auto-discovery. Publish the config file with:

php artisan vendor:publish --tag=uchara-config

Quick Start — Server SDK

<?php

require 'vendor/autoload.php';

use Uchara\SDK\ServerSDK;

$client = new ServerSDK(
    apiUrl: 'https://api.uchara.com',
    apiKey: getenv('UCHARA_API_KEY')
);

// Send a message
$message = $client->sendMessage('conv_abc123', [
    'content' => 'Your order has shipped!',
    'sender_type' => 'bot',
]);

echo "Message sent: {$message['id']}\n";

// List conversations
$conversations = $client->listConversations([
    'status' => 'open',
    'limit' => 10,
]);

foreach ($conversations as $conv) {
    echo "Conversation: {$conv['id']} - {$conv['contact_name']}\n";
}

Members (a.k.a. agents)

Workspace members are the human users of a workspace. Because many users refer to them as "agents", ergonomic Agent aliases are provided alongside the canonical Member methods.

// Canonical member methods
$members = $client->listMembers(['role' => 'agent']);
$member  = $client->getMember('member_123');
$created = $client->createMember(['email' => 'a@b.com', 'role' => 'agent'], 'idem-key-1');
$client->updateMember('member_123', ['name' => 'Alice']);
$client->updateMemberRole('member_123', 'admin');
$client->deactivateMember('member_123');
$client->reactivateMember('member_123');
$client->deleteMember('member_123');

// Agent aliases — identical behaviour
$agents = $client->listAgents();
$agent  = $client->getAgent('member_123');
$client->createAgent(['email' => 'a@b.com']);
$client->updateAgent('member_123', ['name' => 'Alice']);
$client->deactivateAgent('member_123');
$client->reactivateAgent('member_123');
$client->deleteAgent('member_123');

Invites

$invite = $client->inviteMember(['email' => 'x@y.com', 'role' => 'agent']);
$invites = $client->listInvites();
$client->revokeInvite('invite_123');

Channels, Bots & Messages

$channels = $client->listChannels();
$channel  = $client->getChannel('channel_123'); // filters the list (no GET-by-id route)
$client->createChannel(['name' => 'WhatsApp', 'type' => 'whatsapp']);
$client->updateChannel('channel_123', ['name' => 'WA']);
$client->deleteChannel('channel_123');

$bots = $client->listBots();
$client->createBot(['name' => 'Support Bot']);
$client->updateBot('bot_123', ['name' => 'Support Bot v2']);
$client->deleteBot('bot_123');

// Message aliases
$client->sendMessageToConversation('conv_1', ['content' => 'hi']);
$messages = $client->listMessages('conv_1');
$messages = $client->getConversationMessages('conv_1');

Quick Start — Agent SDK

Use AgentSDK when messages must appear as a specific human agent. The API derives sender_type=agent and sender_id from the access token, so do not provide those fields yourself.

<?php

require 'vendor/autoload.php';

use Uchara\SDK\AgentSDK;

$agent = new AgentSDK('https://api.uchara.com');
$agent->login(
    email: getenv('UCHARA_AGENT_EMAIL'),
    password: getenv('UCHARA_AGENT_PASSWORD'),
    workspaceSlug: getenv('UCHARA_WORKSPACE_SLUG') ?: null,
);

$message = $agent->sendMessage('conv_abc123', [
    'content' => 'Halo, saya siap membantu.',
]);

The access and refresh tokens are stored in the SDK instance. Refresh the session when needed:

$agent->refresh();

Multi-agent collaboration and approval flow

Conversations support multiple collaborating agents. There is no separate "approval" endpoint: an authorized assignee/admin invites an existing same-workspace member, and that member accepts by joining. Identity and authorization are always derived from the authenticated member's JWT — the SDK never sends an inviter field.

// Authorized assignee/admin invites an existing workspace member to collaborate.
$agent->inviteToConversation('conv_abc123', 'member_456');

// The invited agent (a separate authenticated AgentSDK session) accepts by joining.
// Join persists multi-agent membership and emits `conversation.joined`.
$agent->joinConversation('conv_abc123');

// The joined agent can now operate as a collaborator (send messages, add notes,
// resolve, etc.) on the conversation.
$agent->sendMessage('conv_abc123', ['content' => 'Saya ikut menangani.']);

// A collaborator removes their membership when done.
$agent->leaveConversation('conv_abc123');

takeoverConversation() is a separate bot-to-agent takeover — it transitions a bot conversation to open and assigns it to the calling agent. It is not a collaborator approval step and does not replace the invite → join flow above.

// Bot-to-agent takeover (distinct from collaborator approval).
$agent->takeoverConversation('conv_abc123');

Secure backend-to-browser agent session (legacy agent-token flow)

Prefer the one-time dashboard SSO flow described under the Server SDK section below for seamless dashboard handoff. This agent-token flow remains supported for existing integrations.

For a custom browser dashboard, do not expose the Server API key. Create the short-lived agent session on your backend and return only the token pair to the browser:

// Backend only — UCHARA_API_KEY must remain server-side.
$server = new ServerSDK('https://api.uchara.com', getenv('UCHARA_API_KEY'));
$session = $server->createAgentSession('agent@example.com');

// Return $session to your dashboard frontend over your own authenticated HTTPS endpoint.

Then initialize the browser Agent SDK with the returned session:

const agent = new AgentSDK({ apiURL: 'https://api.uchara.com', autoConnect: false });
agent.loginWithToken(session);

The agent-token endpoint verifies that the email belongs to an active member in the API key's workspace. Access tokens are short-lived; keep and rotate the refresh token according to your frontend session policy.

One-time dashboard SSO

For a seamless handoff from your own authenticated backend to the Uchara dashboard, issue a one-time SSO ticket with the Server SDK and return the resulting redirect_url to the browser. The API key stays on your backend; the browser only ever sees an opaque, short-lived ticket in the URL fragment.

There is no dedicated SDK helper for this — use the underlying HTTP client via ServerSDK::http()->post(...):

<?php

require 'vendor/autoload.php';

use Uchara\SDK\ServerSDK;

// Backend only — UCHARA_API_KEY must remain server-side.
$server = new ServerSDK('https://api.uchara.com', getenv('UCHARA_API_KEY'));

// Issue a one-time ticket for the target member (optional channel scope).
$result = $server->http()->post('/v1/auth/sso/ticket', [
    'email' => 'agent@company.com',
    // 'channel_ids' => ['<channel-uuid>'], // optional; omitted = full workspace
]);

// Return $result['redirect_url'] from your own authenticated HTTPS endpoint.
// The browser opens it; the dashboard bootstrap exchanges the ticket and
// strips it from the URL.
$redirectUrl = $result['redirect_url'];

Security guidance:

  • Keep the API key backend-only — never expose it in browser code.
  • Do not log, store, or reuse redirect_url values.
  • The ticket is short-lived (60 seconds), one-time, and consumed atomically on exchange; only its hash is stored server-side.
  • No JWT, API key, or refresh token ever appears in the URL.

Quick Start — Visitor SDK

<?php

require 'vendor/autoload.php';

use Uchara\SDK\VisitorSDK;

$visitor = new VisitorSDK(
    apiUrl: 'https://api.uchara.com',
    widgetToken: 'widget_token_123'
);

// Create a visitor session (stores the visitor JWT for subsequent calls)
$session = $visitor->init(['name' => 'Alice', 'email' => 'a@b.com']);

$config = $visitor->getConfig();

$active = $visitor->getActiveConversation(); // null when none exists
if ($active === null) {
    $active = $visitor->startConversation(['message' => 'Hello']);
}

$visitor->sendMessage($active['id'], ['content' => 'Hi there']);
$messages = $visitor->getMessages($active['id'], ['limit' => 20]);
$visitor->close($active['id']);

Read receipts & delivery status

Every message carries a delivery_status field (plus delivery_status_at and, on failure, delivery_error). The lifecycle is monotonic and idempotent:

queued → sent → delivered → read

with failed (and recovered for messages that later succeed). The possible values are exposed as constants on Uchara\SDK\DeliveryStatus:

use Uchara\SDK\DeliveryStatus;

if ($message['delivery_status'] === DeliveryStatus::READ) {
    // the recipient has read the message
}

Mark a conversation as read so the other side sees a read receipt on their own sent messages:

// Visitor marks the responder's messages as read (widget)
$visitor->markConversationRead($conversationId); // ['updated' => int]

// Agent marks the visitor's messages as read (dashboard)
$agent->markConversationRead($conversationId);   // ['marked_read' => int]

Factory

The Uchara factory builds SDK instances from a config array or directly:

use Uchara\SDK\Uchara;

$server = Uchara::server('https://api.uchara.com', 'uchara_sk_...');
$agent = Uchara::agent('https://api.uchara.com');
$visitor = Uchara::visitor('https://api.uchara.com', 'widget_token_...');

// From a config array
$sdk = Uchara::make([
    'api_url' => 'https://api.uchara.com',
     'api_key' => 'uchara_sk_...',
     'access_token' => 'agent_access_token',
     'default' => 'server', // or 'agent' or 'visitor'

]);

Laravel

Set the environment variables and use the facade:

// .env
UCHARA_API_URL=https://api.uchara.com
UCHARA_API_KEY=uchara_sk_...
UCHARA_ACCESS_TOKEN=agent_access_token
UCHARA_DEFAULT=server
use Uchara\SDK\Laravel\Facades\Uchara;

$members = Uchara::listMembers();          // forwards to the default SDK
$server  = Uchara::server();               // explicit ServerSDK
$agent   = Uchara::agent();                // explicit AgentSDK
$visitor = Uchara::visitor();              // explicit VisitorSDK

Error Handling

use Uchara\SDK\UcharaException;

try {
    $message = $client->sendMessage('conv_id', ['content' => 'Hello!']);
} catch (UcharaException $e) {
    echo "Error ({$e->getStatus()}): {$e->getMessage()}\n";
    if ($e->getDetails()) {
        print_r($e->getDetails());
    }
}

UcharaException exposes the HTTP status via getStatus() (alias of getCode()), the parsed error payload via getDetails(), and the full structured response via getResponse().

Advanced HTTP access

The simple helpers (get/post/patch/put/delete) return the unwrapped data payload. When you need the status code, pagination meta or response headers, use request():

$response = $client->http()->request('GET', '/v1/workspace/members', ['query' => ['limit' => 10]]);
$status = $response->status();
$meta   = $response->meta();
$data   = $response->data();

Development

composer install
composer test      # PHPUnit
composer analyse   # PHPStan
composer validate  # composer validate --strict

Documentation

Full documentation: https://www.uchara.com/docs/sdk/php

License

MIT