Download the PHP package linqelio/linqelio-laravel without Composer

On this page you can find all versions of the php package linqelio/linqelio-laravel. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package linqelio-laravel

Linqelio for Laravel

One API for WhatsApp, Telegram and Viber conversations.

Tests Latest Version

Requirements

PHP 8.2+ · Laravel 12 · a Linqelio installation with a client API key.

Laravel 11 is not supported: that line is past its security-support window, so every release in it carries unpatched advisories and Composer refuses to install one under its default policy.

Installation

There is no default URL on purpose. A fallback would quietly send your customers' messages to somebody else's host, and that failure is silent — so an unset LINQELIO_URL raises an exception instead.

Check it works:

Serving several cabinets

LINQELIO_KEY binds the package to one cabinet. An application that serves more than one asks for the key it needs at the call site:

Do not rebind the container to switch cabinets. The client is a singleton, and under Octane or a queue worker it outlives the request that resolved it — the next request would inherit whatever key was set last. forKey() returns a separate instance and leaves the shared one alone.

Sending

A send returns a queued message. The API accepts the command and reaches the provider afterwards, so success means "handed over", not "delivered" — delivery arrives later, on a webhook.

The channel is chosen for you: the contact's most recent conversation, falling back to one matching their identities. Pin it when it matters:

Idempotency

Every unsafe command carries an Idempotency-Key. One is generated for you, so a forgotten key cannot turn a timeout into a duplicate message on somebody's phone. Supply your own when the command has a natural identity:

Then even a redeploy or a replay from another process cannot send it twice.

Prefer the queue for anything triggered by a request — delivery should not be able to slow a checkout down or fail it:

Queued sends derive their key from the job, so a retry repeats the same key rather than sending a second message.

Attachments

Outbound is pull-based — the provider fetches the file — so upload first:

Reading an inbound attachment goes through the platform, not the object store:

The URL stored on an old message is a presigned link that has long expired. The fetch above streams the bytes under your key, and sets nosniff — the content type comes from whoever sent the file, so serving it unguarded on your own origin is how an attachment claiming to be HTML ends up executing there.

Receiving

Register https://your-app.test/linqelio/webhook with Linqelio, put the same secret in LINQELIO_WEBHOOK_SECRET, and listen:

The webhook carries routing identifiers only — never the message body. That is deliberate: a body can contain anything a customer typed or attached, and shipping it to every registered endpoint would spread it further than the API's own access rules reach.

So $event->message() costs a call, and $event->contact() another. Both are memoised. A listener that only needs $event->messageId to queue work pays for neither.

Deliveries are verified (HMAC-SHA256 over the raw body), rejected if older than the tolerance, processed once, and handled on a queue.

Knowing whether a send worked

send() returns when the platform accepts the command, not when the provider is reached — so a 202 is "handed over", never "delivered". Subscribe to message.status and the outcome comes to you:

Every transition is delivered — sent, delivered, read, failed. On a busy cabinet read receipts are the bulk of that, so name only the ones you want in eventTypes.

For one message rather than a stream, Linqelio::messages()->find($id) reads its current status directly; failureReason() on the result answers "why" for a failed one. At volume prefer the event — one call per message does not scale.

Newer platforms also send X-Linqelio-Signature-V2, which signs the send timestamp and delivery id alongside the body. Where the older signature covers the body alone — leaving those two headers unauthenticated, and so unusable for telling a retry from a replay — v2 makes both trustworthy. The middleware uses it when it is there and falls back when it is not, so there is nothing to switch on; the only visible difference is that webhooks.tolerance can stay tight, because freshness is then measured per attempt rather than from the event.

Managing subscriptions

Registering is usually a one-off, but the rest of the lifecycle is not — an endpoint breaks, a deployment moves, a tenant leaves:

Reach for disable() rather than delete() when an endpoint is merely broken: deleting takes the signing key with it, so coming back means handing out a new one. delete() is idempotent — deleting an id that is already gone succeeds, so a retry after a lost response is not an error.

The signing key

Every subscription is signed, and you choose where the key comes from:

$registered->secret is null in the last two cases — you already have the key — and set only when the platform generated it. It is not recoverable: no read returns it, so if it is lost the way back is delete() and register again.

secret is the key; secretRef is a secret:// address in the platform's own store. Passing a secret://… string as secret is refused rather than sent, because the platform would store and sign with it literally, and every delivery would then fail verification here for a reason nothing in the logs explains.

Erasing a person

When someone asks to be deleted, one call removes them:

This is deliberately not a delete of the contact record. Messages carry the person's number in their own columns and have no link back to a contact to cascade through, so the platform redacts them instead — bodies, metadata, chat ids, contact references — in one transaction. The counts come back so you can enter them in your own erasure journal: "we asked and it touched nothing" and "it redacted 412 messages" are different things to be able to show later.

Irreversible, and idempotent: erasing someone already erased returns zero counts ($result->wasAlreadyErased()) rather than failing, so a retry after a timeout is safe.

It cannot reach your copies. The local projection below lives in your database, and so does anything you derived from it:

Local projection

Messages are mirrored into linqelio_messages so you can join, search and report on them without a network call:

It is a projection, not a source of truth. Rows are keyed by the platform's message id — a ULID, stable forever — and never by chat id: an address can be re-keyed underneath you when the platform learns that a phone number and a messenger account are the same person, and a table keyed on it silently splits in two.

Attachment bytes are not copied; $message->media() streams them on demand.

Backfill history for a cabinet that predates the install:

Turn the whole thing off with LINQELIO_PROJECTION=false if events are enough.

Attaching to your models

Contacts themselves are not mirrored. A contact is a person who may be reachable on several channels, and deciding that two addresses are the same person is the platform's job — it never guesses from a matching name. A local copy would diverge exactly there, and quietly.

Errors

Failures raise typed exceptions carrying a stable code:

Switch on $e->errorCode(), not on HTTP status or message text. The registry is additive — codes are never reassigned — so matching one is safe across versions, and a code newer than this package still lands in the right exception family.

Embedded widget

Set LINQELIO_EMBED_ENABLED=true and the widget can fetch a short-lived token from /linqelio/embed-token. It is never rendered into HTML: the token is scoped to one person's conversation, and HTML settles into page caches, browser history and CDN logs.

Testing

The package uses Laravel's HTTP client throughout, so Http::fake() covers it.

Contributing

See SECURITY.md.

License

MIT. See LICENSE.


All versions of linqelio-laravel with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
illuminate/contracts Version ^12.0
illuminate/http Version ^12.0
illuminate/support Version ^12.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package linqelio/linqelio-laravel contains the following files

Loading the files please wait ...