A modern PHP library for building Amazon Alexa skills with clean, maintainable code. This library simplifies handling Alexa requests by providing a robust validation system, flexible request handlers, and helper utilities for common tasks.
- Request Validation: Automatic verification of Amazon request signatures
- Flexible Handler System: Easy-to-extend request handler architecture
- SSML Support: Built-in Speech Synthesis Markup Language generator
- APL Support: Create and send Alexa Presentation Language documents, components, directives, gestures and commands
- Device Address API: Helper for accessing user location data
- PHP 8.2+ Ready: Leverages modern PHP features and type safety
- Symfony Integration: Available bundle for Symfony applications
- PHP 8.2 or higher
- Composer
composer require maxbeckers/amazon-alexa-php
<?php
use MaxBeckers\AmazonAlexa\Request\Request;
use MaxBeckers\AmazonAlexa\Validation\RequestValidator;
use MaxBeckers\AmazonAlexa\RequestHandler\RequestHandlerRegistry;
// 1. Parse incoming request
$requestBody = file_get_contents('php://input');
$alexaRequest = Request::fromAmazonRequest(
$requestBody,
$_SERVER['HTTP_SIGNATURECERTCHAINURL'] ?? '',
$_SERVER['HTTP_SIGNATURE'] ?? ''
);
// 2. Validate request authenticity
$validator = new RequestValidator();
$validator->validate($alexaRequest);
// 3. Handle request
$registry = new RequestHandlerRegistry();
$registry->addHandler(new MyIntentHandler());
$handler = $registry->getSupportingHandler($alexaRequest);
$response = $handler->handleRequest($alexaRequest);
// 4. Send response
header('Content-Type: application/json');
echo json_encode($response);
<?php
use MaxBeckers\AmazonAlexa\Request\Request;
use MaxBeckers\AmazonAlexa\Response\Response;
use MaxBeckers\AmazonAlexa\RequestHandler\AbstractRequestHandler;
use MaxBeckers\AmazonAlexa\Request\Request\Standard\IntentRequest;
class WelcomeIntentHandler extends AbstractRequestHandler
{
public function __construct(
private readonly array $supportedApplicationIds = ['amzn1.ask.skill.your-skill-id']
) {
parent::__construct();
}
public function supportsRequest(Request $request): bool
{
return $request->request instanceof IntentRequest &&
$request->request->intent->name === 'WelcomeIntent';
}
public function handleRequest(Request $request): Response
{
return $this->responseHelper->respond(
outputSpeech: 'Welcome to our amazing skill!',
shouldEndSession: false
);
}
}
<?php
use MaxBeckers\AmazonAlexa\Request\Request;
use MaxBeckers\AmazonAlexa\Response\Response;
use MaxBeckers\AmazonAlexa\RequestHandler\AbstractRequestHandler;
use MaxBeckers\AmazonAlexa\Request\Request\Standard\IntentRequest;
class UserInfoHandler extends AbstractRequestHandler
{
public function __construct(
private readonly array $supportedApplicationIds = ['amzn1.ask.skill.your-skill-id']
) {
parent::__construct();
}
public function supportsRequest(Request $request): bool
{
return $request->request instanceof IntentRequest &&
$request->request->intent->name === 'GetUserInfoIntent';
}
public function handleRequest(Request $request): Response
{
$intentRequest = $request->request;
$userName = $intentRequest->intent->slots['userName']->value ?? 'friend';
$message = match($userName) {
'admin' => 'Hello administrator! You have special privileges.',
'guest' => 'Welcome, guest user. Limited features available.',
default => "Nice to meet you, {$userName}!"
};
return $this->responseHelper->respond($message);
}
}
Create rich speech responses with the SSML generator:
<?php
use MaxBeckers\AmazonAlexa\Helper\SsmlGenerator;
$ssmlGenerator = new SsmlGenerator();
$ssmlGenerator
->say('Welcome to our cooking skill!')
->pauseStrength(SsmlGenerator::BREAK_STRENGTH_MEDIUM)
->say('Today we will learn about')
->emphasis('amazing', SsmlGenerator::EMPHASIS_STRONG)
->say('pasta recipes.')
->pauseTime('2s')
->say('Let\'s get started!');
$ssml = $ssmlGenerator->getSsml();
// Result: <speak>Welcome to our cooking skill! <break strength="medium" /> Today we will learn about <emphasis level="strong">amazing</emphasis> pasta recipes. <break time="2s" /> Let's get started!</speak>
Build multimodal experiences with the included APL directive, component, command, and gesture classes:
<?php
use MaxBeckers\AmazonAlexa\Response\Directives\APL\RenderDocumentDirective;
use MaxBeckers\AmazonAlexa\Response\Response;
use MaxBeckers\AmazonAlexa\ResponseHelper;
// Inside a request handler:
$document = [
'type' => 'APL',
'version' => '1.8',
'mainTemplate' => [
'items' => [
[
'type' => 'Text',
'text' => '${payload.data.message}',
'style' => 'textStylePrimary1'
]
]
],
];
$dataSources = [
'data' => [
'message' => 'Hello from APL!'
],
];
$aplDirective = new RenderDocumentDirective(
token: 'mainScreen',
document: $document,
datasources: $dataSources
);
// Using the response helper (if available in your handler base)
$response = $this->responseHelper->respond(
outputSpeech: 'Showing a visual response.',
directives: [$aplDirective],
shouldEndSession: false
);
// Or manually:
$alexaResponse = new Response();
$alexaResponse->response->directives[] = $aplDirective;
You can also leverage the rich PHP class model (components, commands, gestures, layouts) instead of raw arrays for stronger typing when building complex documents.
Access user location data with proper permissions:
<?php
use MaxBeckers\AmazonAlexa\Helper\DeviceAddressInformationHelper;
$addressHelper = new DeviceAddressInformationHelper();
try {
// Get full address (requires "read::alexa:device:all:address" permission)
$fullAddress = $addressHelper->getAddress($request);
// Get country and postal code only (requires "read::alexa:device:all:address:country_and_postal_code" permission)
$countryAndPostalCode = $addressHelper->getCountryAndPostalCode($request);
$response = $this->responseHelper->respond(
"I found your location in {$fullAddress->city}, {$fullAddress->stateOrRegion}"
);
} catch (Exception $e) {
$response = $this->responseHelper->respond(
'I need permission to access your address. Please check your Alexa app.'
);
}
Implement robust error handling:
<?php
use MaxBeckers\AmazonAlexa\Exception\ValidationException;
try {
$validator = new RequestValidator();
$validator->validate($alexaRequest);
} catch (ValidationException $e) {
http_response_code(400);
echo json_encode(['error' => 'Invalid request signature']);
exit;
} catch (Exception $e) {
http_response_code(500);
error_log('Alexa skill error: ' . $e->getMessage());
echo json_encode(['error' => 'Internal server error']);
exit;
}
<?php
use MaxBeckers\AmazonAlexa\Response\Response;
use MaxBeckers\AmazonAlexa\Response\OutputSpeech;
use MaxBeckers\AmazonAlexa\Response\Card;
public function handleRequest(Request $request): Response
{
$outputSpeech = new OutputSpeech();
$outputSpeech->type = OutputSpeech::TYPE_SSML;
$outputSpeech->ssml = '<speak>Custom SSML response</speak>';
$card = new Card();
$card->type = Card::TYPE_SIMPLE;
$card->title = 'Skill Response';
$card->content = 'This appears in the Alexa app';
$response = new Response();
$response->outputSpeech = $outputSpeech;
$response->card = $card;
$response->shouldEndSession = false;
return $response;
}
<?php
$registry = new RequestHandlerRegistry();
$registry->addHandler(new LaunchRequestHandler());
$registry->addHandler(new WelcomeIntentHandler());
$registry->addHandler(new HelpIntentHandler());
$registry->addHandler(new StopIntentHandler());
$registry->addHandler(new SessionEndedRequestHandler());
For Symfony applications, use the dedicated bundle:
composer require maxbeckers/amazon-alexa-bundle
Visit maxbeckers/amazon-alexa-bundle for detailed integration instructions.
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License - see the LICENSE file for details.