Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Crisp Api Laravel Package

crispchat/php-crisp-api

A PHP client for the Crisp Chat REST API, making it easy to manage conversations, contacts, websites, operators, and other Crisp resources from Laravel or any PHP application. Install via Composer and authenticate with your Crisp API credentials.

Deep Wiki
Context7

Getting Started

Install with Composer and confirm the client class is autoloadable:

composer require crispchat/php-crisp-api

The first place to look is the package's README.md and the src/ directory — the entry point is the Crisp\CrispClient class (sometimes referenced as just CrispClient). Everything else is organized as resource namespaces hanging off that client, e.g. website, conversation, message, operator, contact, plugin, helpdesk.

Authentication uses Crisp's two-part token model. Grab a token identifier and token key from your Crisp dashboard under Settings → API, then:

use Crisp\CrispClient;

$client = new CrispClient();
$client->authenticate($tokenIdentifier, $tokenKey);

Most calls also need a website ID (the website_id you see in Crisp URLs):

$websites = $client->website->listWebsites();
$websiteId = $websites[0]['website_id'];

A sensible first use case: send a test message into a conversation so you can verify both auth and the resource namespacing in one shot.

$client->message->sendMessage(
    $websiteId,
    $sessionId,          // conversation session_id
    ['type' => 'text', 'content' => 'Hello from PHP', 'from' => 'operator', 'origin' => 'php-app']
);

If that returns without throwing, you have auth, resource wiring, and payload shape all confirmed.

Implementation Patterns

Bind the client in Laravel's container. Don't instantiate CrispClient in controllers. Register a singleton in a service provider so the token is read from config once and the object is reused:

$this->app->singleton(CrispClient::class, function () {
    $client = new CrispClient();
    $client->authenticate(
        config('services.crisp.identifier'),
        config('services.crisp.key')
    );
    return $client;
});

Then inject it anywhere via the container. This is the single highest-value integration tip — it keeps credentials in config/services.php and out of call sites.

Keep the website ID in config, not hardcoded. Almost every method takes it as the first argument, and it's easy to lose track of which environment's site you're hitting.

Wrap outbound messaging in queued jobs. Outbound calls to Crisp are network-bound and can fail; a SendCrispMessage job with $tries and backoff gives you retries without blocking the request that triggered it. Handle the case where the conversation session expired (Crisp returns an error but the wrapper may surface it as a generic exception).

Use resource namespaces as your mental model. Calls read left-to-right: $client->conversation->listConversations($websiteId) returns paginated conversations; $client->message->sendMessage(...) writes into one; $client->website->getWebsite($websiteId) fetches metadata. Once you know the resource, the method names follow Crisp's REST endpoints fairly closely.

Inbound flows belong in your webhook handler, not the wrapper. Crisp pushes events (new message, conversation resolved, operator assigned) to your endpoint. The package talks to Crisp, not the other way around. Validate the webhook, then use the client for any follow-up reads (e.g., fetch the full conversation after a message:received event). This split — webhooks for inbound, client for outbound — is the standard architecture.

Centralize error handling in a small wrapper service. Write a thin CrispService around the client that:

  • normalizes responses to associative arrays (some endpoints return lists, some return objects),
  • logs request/response on failure,
  • converts the package's exceptions into your domain exceptions.

This keeps the vendor package at arm's length so you can swap or upgrade later.

For testing, point the underlying HTTP client at a mock. The wrapper uses Guzzle under the hood (via a standard HTTP client), so Http::fake() in Laravel or a Guzzle MockHandler in plain PHP lets you assert the request URL, method, and JSON body without hitting Crisp. Assert on paths like /v1/website/{id}/conversation/{session}/message.

Gotchas and Tips

Token tiers gate functionality. Crisp scopes tokens to specific tiers/websites. A production token won't have access to another website's conversations, and some endpoints return 403 for tokens not scoped to the right tier. If a call fails inexplicably, check token scope before assuming a wrapper bug.

Website ID is positional and unforgiving. Omitting it, or passing a session ID where a website ID is expected, results in 404s that look like auth problems. The error bodies from Crisp are usually explicit — log the raw response body in your exception handler, because the wrapper's thrown exceptions may not preserve it.

Responses are arrays, not typed objects. There are no DTOs — you'll get nested associative arrays back. Reach for data_get() (Laravel) or defensive ?? null access; Crisp occasionally omits keys on older records (e.g. assigned operator fields). Don't assume a field exists across all conversations.

Pagination is manual. List endpoints return up to a page size; iterate with whatever page/per_page (or cursor) parameter the endpoint accepts and stop when a page comes back empty. There's no magic ->all() helper in the wrapper, so build a small collectAllConversations() method once and reuse it.

Rate limits are real but undocumented in the SDK. Crisp enforces per-token limits; the wrapper doesn't throttle or retry for you. For bulk operations (backfills, migrations), sleep between calls or use a queue with a rate-limited worker. A 429 should trigger backoff, not a tight retry loop.

Version pinning matters. This is a small community package (59 stars), so the API surface moves. Pin a minor version in composer.json ("crispchat/php-crisp-api": "^1.x") and run your HTTP assertions in CI after upgrades — that's your real regression test.

No first-class framework integration. There's no service provider, facade, config file, or published migration. Everything in the "Implementation Patterns" section (singleton binding, config, wrapper service) is on you — which is fine, but don't expect package docs to explain it.

Extension points are limited. You can't easily swap the HTTP client or inject middleware; the client constructs its own Guzzle stack. If you need request signing, tracing, or custom retry logic, wrap the whole client (or fork it) rather than reaching inside. For anything the wrapper doesn't cover — newer Crisp endpoints, websocket events — call the REST API directly with Guzzle and treat the wrapper as a convenience for the well-trodden paths (messages, conversations, websites, operators).

Debugging tip: when a call fails, hit the same path with curl using the same token. If curl succeeds and the wrapper fails, the difference is usually a malformed JSON body (wrong type/from/origin fields on sendMessage) or a misencoded header — both are easier to spot in a raw request than in a stack trace.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings