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

Amazon Alexa Php Laravel Package

minicodemonkey/amazon-alexa-php

A PHP library for building Amazon Alexa skills. It parses incoming Alexa requests, handles intents, slots, and sessions, and builds compliant JSON responses with SSML, cards, and directives, giving Laravel and plain PHP projects a clean, extensible foundation.

Deep Wiki
Context7

Getting Started

Install via Composer:

composer require minicodemonkey/amazon-alexa-php

The package is small — the fastest way to learn it is to read src/Alexa/Request/* and src/Alexa/Response/*. The two directories are the whole mental model: one parses the inbound JSON, the other builds the outbound JSON. There is no kernel, no service container, no event system.

Minimal endpoint:

use Alexa\Request\IntentRequest;
use Alexa\Request\LaunchRequest;
use Alexa\Request\SessionEndedRequest;
use Alexa\Response\Response;

$raw = file_get_contents('php://input');

// Dispatch on the JSON "request.type" field
$data = json_decode($raw, true);

switch ($data['request']['type']) {
    case 'LaunchRequest':
        $request = new LaunchRequest($raw);
        break;
    case 'IntentRequest':
        $request = new IntentRequest($raw);
        break;
    case 'SessionEndedRequest':
        $request = new SessionEndedRequest($raw);
        break;
    default:
        http_response_code(400); exit;
}

$response = new Response();
$response->outputSpeech = 'Hello from your skill.';
$response->endSession   = true;

header('Content-Type: application/json');
echo json_encode($response->render());

Your first real use case is almost always a single-intent skill ("ask my skill for the weather"). Get the raw body through php://input, instantiate IntentRequest, read $request->intentName and $request->slots, and return a Response with render() encoded as JSON. Validate that round trip with the Alexa developer console's test tab before touching certificates or session state.

Implementation Patterns

Route-then-dispatch by request type. Because each request class expects a different shape, build a tiny dispatcher rather than passing raw arrays around. In Laravel:

public function __invoke(Request $http)
{
    $raw = $http->getContent(); // raw body, not $http->all()
    $data = json_decode($raw, true);

    $request = match ($data['request']['type']) {
        'LaunchRequest'       => new LaunchRequest($raw),
        'IntentRequest'       => new IntentRequest($raw),
        'SessionEndedRequest' => new SessionEndedRequest($raw),
    };

    return response()->json($this->handle($request)->render());
}

Map intents to handler methods. The library gives you $request->intentName and $request->slots; wire that to your own classes. A simple match on intent name is the pragmatic day-to-day pattern:

$handler = match ($request->intentName) {
    'WeatherIntent'      => new WeatherHandler(),
    'AMAZON.HelpIntent'  => new HelpHandler(),
    'AMAZON.StopIntent',
    'AMAZON.CancelIntent' => new StopHandler(),
    default              => new FallbackHandler(),
};

Handle AMAZON.HelpIntent, AMAZON.StopIntent, AMAZON.CancelIntent, and AMAZON.FallbackIntent explicitly — Alexa will replay the request otherwise.

Build responses with the response objects, not raw arrays. Response, Card, OutputSpeech, and Reprompt cover the v1 skill response envelope and save you from typo-ing shouldEndSession. Compose:

$response = new Response();
$response->outputSpeech = new OutputSpeech('SSML', '<speak>It is <break time="1s"/> sunny.</speak>');
$response->reprompt     = new Reprompt(new OutputSpeech('PlainText', 'Do you want the forecast?'));
$response->card         = new Card('Simple', 'Weather', 'Sunny, 24°C');
$response->endSession   = false; // keep the mic open

Multi-turn dialogs via session attributes. Read $request->session->attributes on entry, write $response->sessionAttributes on exit. Treat the array as your scratchpad; don't hold state in PHP sessions — the skill is stateless between turns from Amazon's perspective and each turn is a cold request.

SSML by default, plain text by exception. Set OutputSpeech type to SSML whenever you may emit <break>, <emphasis>, or <say-as>. For a pure hello-world, PlainText avoids escaping headaches.

Verification middleware. Amazon's request carries SignatureCertChainUrl and Signature headers plus a timestamp in the body. Perform verification in middleware so handlers stay clean, and only then hand the body into the request classes. In Laravel this is a VerifyAlexaRequest middleware; in vanilla PHP, a small function at the top of your endpoint. Check three things: certificate URL is on s3.amazonaws.com, the body's timestamp is within ~150 seconds, and the RSA signature matches the body using the cert's public key.

Keep handlers single-purpose and testable. Because the request classes just hydrate from JSON, you can build fixture payloads (capture real ones from CloudWatch logs) and unit-test your handlers without any Alexa machinery.

Gotchas and Tips

Read the raw body, not the parsed form. $request->input() in Laravel or $_POST will be empty or mangled for application/json. Always use php://input / $request->getContent(). This is the single most common cause of "my slots are empty".

Verify before you trust slots, not after. The library does not call Amazon for you by default in most setups — signature checking is easy to forget. Skipping it lets anyone spoof intents and, worse, exposes you to SSRF via SignatureCertChainUrl. Validate the host is exactly s3.amazonaws.com and that the path starts with /echo.api/ before fetching. Cache the certificate body by URL for the life of the cert.

Timestamp is your replay defence. Validate request.timestamp against now() with a tight window (~150 s). If you only check the signature, a captured request can be replayed indefinitely.

endSession maps to shouldEndSession. If you set endSession = false or leave it unset, Alexa waits for a follow-up. If you meant to close and forgot, users experience dead air and a timeout. If you intend to keep listening, you must also set a reprompt, otherwise Alexa has nothing to say while it waits.

A Reprompt without OutputSpeech is invalid. Alexa returns a ValueError at runtime. Always pass an OutputSpeech into Reprompt.

render() returns an array, not a string. You must json_encode() it yourself and set Content-Type: application/json. Forgetting this is the second most common failure and produces a silent skill in the simulator.

Cards are strict. Card('Simple', ...) takes title + text only. Card('Standard', ...) requires smallImageUrl and largeImageUrl to be HTTPS and reachable; broken URLs will show a blank card without an error. Don't emit empty text.

Session attributes are JSON-serialised per turn. Keep them small (single-digit KB). Don't put objects with closures or resources in them — they'll serialise to {} and round-trip as nulls.

The library predates APL, display directives, and Dialog delegation. If you need directives (audio player, APL, display), you'll have to either post-process $response->render() or fork/extend Response with your own directives array. Plan for one small subclass rather than sprinkling array_merge everywhere.

AMAZON.FallbackIntent and locale-specific built-ins are not auto-handled. Map them explicitly, and prefer returning a reprompt + endSession = false so the skill can recover instead of hard-failing.

Debug with logged raw bodies. Since the library hands you no request log, log the raw JSON (redact session.user.userId if you care) in middleware. When a slot comes through wrong, the log will show whether Amazon sent it wrong or your parsing did.

Cert fetch needs network access and CA trust. In locked-down containers, cert_get_public_key failures show up as generic signature failures. Ensure openssl extension is installed, outbound HTTPS to s3.amazonaws.com is allowed, and the system CA bundle is current.

Extend Response for custom directives rather than mutating the array downstream. A small class MyResponse extends Response that adds $this->directives and merges it in render() keeps the rest of your code idiomatic and survives package upgrades.

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.
unabomber/timezone
delatbabel/contacts
astritzeqiri/g-recaptcha
kevinongko/laravel-genode
developeruz/laravel-analytics
robbiep/afterthedeadline
frankkessler/incontact-laravel-oauth2-rest
jlxh/laravel-userlog
davidmgilo/timetables
qylinfly/role-permission
reflect-digital/conduit
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr