geekcodev/laravel-max-client
A Laravel client for the MAX messaging platform that simplifies bot integration: configure credentials, send messages, alerts, and notifications, and call the MAX API through a clean, framework-friendly PHP wrapper for Laravel services, jobs, and apps. Built to keep MAX bot calls simple inside Larav...
Architecture fit
geekcodev/max-php-client. v1.2.2 adds wrappers, singleton bindings and config keys — no new architectural surface, no migrations, no schema.Security\WebAppContactVerifier); the adapter does not duplicate the signing/verification algorithm. Good for security posture, but it converts the core into a hard dependency floor (^1.1.10) that we now have to track as a first-class dependency, not a transitive detail.WebAppSession is final readonly and reads keys written by the existing max.webapp middleware (ResolveWebAppIdentity) — it slots into the current request lifecycle without new middleware.Integration feasibility
composer update geekcodev/max-php-client), plus optional config. No DB backfill: the confirmed-contact flag lives in the session, not in max_users.php artisan max:subscribe <url> per URL. Verified empirically (2026-10-16) on a live subscription: GET getSubscriptions() went 6 → 13 types with one URL and one subscription. Then confirm with php artisan max:subscriptions.App\Services\WebAppContactVerifier / App\Support\WebAppSession map to WebApp\WebAppContactService / WebApp\WebAppSession, same behavior.Technical risk
~1.2.0 picks this up without a major-version signal; the actual behavior change only lands after re-subscribe, so the blast radius is deferred and easy to lose track of.message_edited, message_removed, dialog_cleared, dialog_removed, chat_title_changed, user_added, user_removed. Non-idempotent or order-sensitive listeners (edits arriving after creates, deletes for records already gone) can corrupt state or resurrect rows.user_added/user_removed are wired ahead of the chat-member-sync plan; PersistMaxChatListener currently returns on default => null. Low risk now, but it is a planned dependency we are pre-paying for and should track against that plan.contact_confirmed by default). Integrators carrying the old key (max.webapp.contact_confirmed in i2tech) silently lose confirmation state and force re-auth unless they set MAX_WEBAPP_SESSION_CONTACT_CONFIRMED.comment_* and bot_admin_permissions_changed are not in the default; any future feature needing them requires a config change and a re-subscribe, not a code change.webapp.max_age drives auth_date freshness; max_age=0 disables replay protection (tested and allowed). That is a security-relevant value a well-meaning operator could set.Key questions
max_users.phone? v1.2.2 explicitly does not write them — only chat-button request_contact does via PersistMaxUserPhoneListener. If the product assumes otherwise, that gap must be closed separately.comment_* types? If yes, we own a webhook.update_types override that will diverge from package defaults forever.geekcodev/max-php-client version floor and its patch cadence, given security logic now lives there?Stack fit
max.webapp middleware: direct fit.^1.1.10. Run composer update geekcodev/max-php-client explicitly rather than relying on a lockfile refresh, and check for transitive conflicts in the same pass.window.WebApp.requestContact() and posts the payload; the server verifies with WebAppContactService::resolve()/verify() and records confirmation through WebAppSession::confirm().Migration path
webapp.session.contact_confirmed if we want a non-default flag key; otherwise set MAX_WEBAPP_SESSION_CONTACT_CONFIRMED=max.webapp.contact_confirmed to carry existing sessions through.webhook.update_types; omission is the right default for most hosts.php artisan max:subscribe <url> per environment, then php artisan max:subscriptions and assert 13 types in the release checklist.Compatibility
Support\Config::webhookUpdateTypes(), two config keys with defaults. No signature churn; WebAppContext::verifyContact() was intentionally not added, so no facade surface to maintain.max:listen) is untouched — polling deployments get zero delta from the webhook change.webhook.update_types overrides win over the new default, so hosts that pinned a list see no change at all.Sequencing
max:subscriptions; treat a mismatch as a release blocker.user_added/user_removed no-op path produces no error noise.max:subscribe executed as part of the release and gated on the max:subscriptions assertion.Maintenance
geekcodev/max-php-client at or above ^1.1.10 and tracking its security fixes — assign an owner.MAX_WEBAPP_SESSION_CONTACT_CONFIRMED, MAX_WEBHOOK_UPDATE_TYPES), both optional with working defaults.Support
max:subscriptions output first.max_users.phone." By design — bridge contacts and chat-button contacts are independent mechanisms. Needs product messaging, not engineering.user_id (OWASP A09 compliant; no phone, no hash). Correct for compliance, but it means confirm-failure tickets have thin diagnostics — support will need a repro procedure around auth_date and max_age.Scaling
PersistMaxChatListener, so their marginal cost is dispatch only, not writes.confirm() regenerates the session id — cheap and once-per-confirmation, but it invalidates existing session payloads, so any client caching session data must handle the rotation.Failure modes
max:subscriptions count, not a manual eyeball.webhook.update_types → the named type is silently not delivered. Empty/blank/duplicate values degrade safely to the 13-type default, but a mistyped name does not — validate against the known list.^1.1.10 → Security\WebAppContactVerifier unresolvable; surfaces at first container resolution. Catch it at boot by resolving the binding in a health check.message_edited/message_removed → duplicate rows or deleted-then-resurrected records.webapp.max_age misconfiguration, especially 0, silently disables replay protection — a security regression that no test will flag for us.Ramp-up
max_age=0, empty inputs, log-redaction assertions, session key rotation, config parsing edge cases, and command output. That substantially reduces bespoke QA; the remaining gap is one staging end-to-end test posting a real requestContact payload.How can I help you explore Laravel packages today?