particle-academy / twilio-php
Twilio for PHP — the service descriptor, its faker, its webhook verification, one class per operation, and a fancy-flow-php executor per node. Plain HTTP on particle-academy/fancy-connector-core; no vendor SDK.
Requires
- php: ^8.4
- particle-academy/fancy-connector-core: >=0.4.0 <2.0
Requires (Dev)
- laravel/framework: ^13.0
- laravel/pint: ^1.26
- pestphp/pest: ^5.0
Suggests
- laravel/framework: ^13.0 — the Laravel integration (src/Laravel/): a service provider, config, verified webhook routes, and Twilio::fake(). Everything outside Laravel\ works without it.
- particle-academy/fancy-flow-php: >=0.51.0 <2.0 — runs this connector's nodes on a fancy-flow-php host (src/Flow/). Everything outside Flow\ works without it.
Provides
None
Conflicts
- particle-academy/fancy-flow-php: <0.51.0 || >=2.0
Replaces
None
README
Twilio for fancy-flow — as four imported, versioned packages, one per runtime. Not vendored source: a copy cannot be upgraded, and third-party APIs change.
| Runtime | Package | Install |
|---|---|---|
| Authoring surface (every host) | @particle-academy/twilio-ui |
npm install @particle-academy/twilio-ui |
| Node | @particle-academy/twilio-js |
npm install @particle-academy/twilio-js |
| PHP 8.4+ | particle-academy/twilio-php |
composer require particle-academy/twilio-php |
| Python 3.11+ | fancy-twilio |
pip install fancy-twilio |
The ui package is the editor surface and is React on every host — a PHP or
Python project installs it and its own runtime package, and never the js one.
What it costs you
One dependency: @particle-academy/fancy-connector-core (or
particle-academy/fancy-connector-core on Composer), which the js and php
packages pull in themselves. The Python package has zero runtime
dependencies.
No Twilio SDK. Plain HTTP, deliberately: a vendor SDK is third-party code subject to the kit's full approval bar, and one per provider is hundreds of dependencies nobody is tracking.
Setting it up
Everything below is generated from provider/manifest.json, so it cannot disagree with what the packages do.
Credentials
A Twilio connection holds 3 values.
Every value here is account scope: one per connected account, not one per installation.
| Field | Scope | Secret | Where it comes from |
|---|---|---|---|
| Account SID | per connected account | not secret | AC followed by 32 hex characters, from the Twilio Console. It is part of every request URL. |
| API key SID (or Account SID) | per connected account | not secret | An API key SID from the Twilio Console (API keys & tokens), recommended. Or the Account SID again, to authenticate with the Auth Token. |
| API key secret (or Auth Token) | per connected account | secret | The secret shown once when the API key was created, or the account's Auth Token. The Auth Token can do everything on the account; an API key can be revoked on its own. |
The estate
Twilio decides live-or-test by the KEY, not by the endpoint. The same host serves both, and a live key pointed at a node marked “sandbox” reaches the real estate and SUCCEEDS. Nothing in the request distinguishes them, which is why credentials sit on the connection rather than on each node.
Twilio's test estate is selected by the CREDENTIALS, not the URL: a separate test Account SID and test Auth Token (Console -> API keys & tokens), against the same api.twilio.com. A live key on a node marked sandbox texts a real phone and is billed. With test credentials only message_send works -- every other resource, including message_get, answers 403 -- nothing is sent or charged, no status callback fires, and From must be Twilio's magic +15005550006 (+15005550004 as To returns 21610, the STOP case). Test credentials are the test Account SID and Auth Token, not an API key.
What it can do
Actions
message_get — Twilio message
Read a message's current status, segments, price and error code.
GET /2010-04-01/Accounts/{AccountSid}/Messages/{Sid}.json · reads only — safe to replay
| Input | Required | What it is |
|---|---|---|
sid |
yes | From message_send's data.sid. |
message_send — Send an SMS with Twilio
Send a text message.
POST /2010-04-01/Accounts/{AccountSid}/Messages.json · unsafe to replay — a retried durable run does it TWICE
| Input | Required | What it is |
|---|---|---|
to |
yes | The recipient in E.164, e.g. +14155550100. |
from |
no | A Twilio number you own, in E.164, or an alphanumeric sender ID where the destination allows one. Give this or a Messaging Service. |
messagingServiceSid |
no | MG... A Messaging Service picks the sender from its pool. Give this or From. |
body |
yes | The text. Up to 1,600 characters. A character outside GSM-7 makes the whole message UCS-2, which halves how much fits in each billed segment. |
statusCallback |
no | Optional. Twilio POSTs delivery status changes here. Verifying those requests arrives in 0.2.0. |
Run it before you have credentials
Every operation ships a faker, whether or not Twilio has a sandbox. Set a
node's mode to fake and it returns the shape Twilio actually publishes — the
same field names, deterministically — so you can wire the downstream nodes before
touching an account, a key, or a network.
This repository is generated
provider/ is the source. Everything under packages/ is emitted from it and
must not be hand-edited — CI regenerates and diffs on every push, and the
next protocol sync destroys anything it finds. See AGENTS.md.
Two namespaces, which do not match on purpose
The repo is github.com/Fancy-Friends/twilio; the packages publish under
particle-academy. Nothing derives one from the other — the names come from
weaver's friends.json and nowhere else.
Licence
MIT.