Search by

sendity / phone-channel

chsch

Framework-agnostic Sendity inbound phone channel for RCS/SMS provider webhooks, deep links, and code extraction.

Package info

gitlab.com/sendity/channels/phone/php

Issues

pkg:composer/sendity/phone-channel

Statistics

Installs: 100

Dependents: 1

Suggesters: 0

Stars: 0

v0.3.0-beta.4 2026-10-26 15:30 UTC

README

Framework-agnostic PHP package for Sendity inbound phone verification via provider webhooks.

Meta's optional contacts[].profile.name is exposed as ParsedMessage::name for greetings only when exactly one contact matches the message sender's phone number or BSUID, with no conflicting identifier. Missing or ambiguous names remain null and do not block phone verification. This is user-chosen display copy, not verified real-world identity.

sendity/phone-channel parses inbound phone-channel webhooks, normalizes RCS/SMS transport evidence, extracts Sendity authentication codes through the sendity/core AuthCodeServiceInterface contract, and returns a normalized phone-channel result.

The first provider adapter is Twilio Programmable Messaging/RCS. It understands Twilio incoming message webhooks, including RCS ChannelMetadata with senderPhoneNumber, RBM agentId, Google provider metadata, and SMS fallback payloads.

Boundaries

This package intentionally contains no Laravel/server glue and no persistence/session matching. sendity/laravel-server remains responsible for HTTP routing, Twilio request signature validation, replay protection, app policy, domain state mutation, and events/jobs.

Dependencies on sendity/core are limited to contracts/DTOs. The package does not depend on Sendity server internals.

Basic usage

use Sendity\Core\Contract\AuthCodeServiceInterface;
use Sendity\PhoneChannel\PhoneChannel;
use Sendity\PhoneChannel\PhoneProcessingStatus;

/** @var AuthCodeServiceInterface $authCodeService */
/** @var Psr\Http\Message\RequestInterface $request */
$channel = new PhoneChannel($authCodeService);

$result = $channel->process($request);

if ($result->status === PhoneProcessingStatus::Verified) {
    // Hand off $result->sender, $result->codes, $result->transport,
    // and $result->identityData to the server glue.
}

Twilio RCS deep links

Twilio/Google RCS Business deep links use the sms: URI scheme with an RCS service_id and optional body/fallback number:

use Sendity\PhoneChannel\RcsDeepLink;

$link = new RcsDeepLink(
    serviceId: 'sendity_agent@rbm.goog',
    fallbackNumber: '+491234567890',
    body: 'SENDITY ABC123',
);

$link->toUri();
// sms:+491234567890?service_id=sendity_agent%40rbm.goog&body=SENDITY%20ABC123

Twilio evidence

For RCS, Twilio may send ChannelMetadata similar to:

{
  "type": "rcs",
  "data": {
    "context": {
      "channelPayload": {
        "senderPhoneNumber": "+491701234567",
        "messageId": "MxXXXXXXXXXXXXXXXX",
        "sendTime": "2026-01-14T23:45:20.041253Z"
      },
      "agentId": "sendity_agent@rbm.goog",
      "provider": "google"
    }
  }
}

The Twilio adapter prefers channelPayload.senderPhoneNumber for the sender and falls back to the top-level From field. SMS fallback payloads are normalized as transport = sms.

Verification policy

A verified result requires:

  • supported provider payload
  • parseable sender/message fields from the provider adapter
  • message body within PhoneChannelOptions::$maxBodyBytes
  • at least one extractable Sendity code

The package does not perform provider webhook signature validation. That belongs to the server/framework adapter because it needs the exact public URL, raw request body, and provider secret configuration.

Direct WhatsApp Cloud API

The phone channel supports direct Meta WhatsApp webhooks, with strict provider-observed phone evidence. The Laravel server verifies the raw signature and account/phone metadata at GET|POST /{route-prefix}/incoming-messages/phone/meta. BSUIDs and arbitrary contact cards are never treated as phone numbers.

When Meta is fully configured, phone actions add transport: "whatsapp" and an HTTPS wa.me URL. Apps permitting SMS also receive sms_fallback: {recipient, url}. The client lets the user switch deliberately and preserves the choice, URL and QR across browser return. Disabled/incomplete Meta configuration retains the existing action.

See the setup guide for protected configuration, publication and hidden-number disclosure handling.