Alexa+ Add-on API Reference
The Alexa+ Add-on API (AAPI) is the representational state transfer (REST) API that backs the Alexa AI CLI. You can call AAPI directly to integrate add-on lifecycle management into your own tools and your continuous integration/continuous deployment (CI/CD) pipelines.
AAPI endpoints
The AAPI root endpoint is https://api.amazonalexa.com. Each operation path includes its own version prefix. Refer to the individual operation sections for the full path.
Authentication
All requests must include a Login with Amazon (LWA) OAuth 2.0 Bearer token in the Authorization header. You can obtain a token by running alexa-ai configure. Pass tokens in the Authorization header. For details, see Access Token Retrieval REST API Reference.
CLI-to-API mapping
The following table maps each Alexa AI CLI command to the AAPI operations it calls.
| Alexa AI CLI command | AAPI operations |
|---|---|
alexa-ai configure |
Client-side only with LWA OAuth flow, no API calls. |
alexa-ai new |
Client-side only. It generates project files locally, no API calls. |
alexa-ai deploy |
CreateAddOnUpload, CreateAddOnPackageWithoutAddOnId, CreateAddOnPackage, GetAddOnPackageStatus, DeployAddOnVersionToStage, GetAddOnDeploymentStatus |
alexa-ai test |
ExecuteAddOnTests, GetAddOnTestResults |
alexa-ai submit |
SubmitAddOnForCertification |
alexa-ai list |
ListAddOns |
alexa-ai create-catalog |
CreateCatalog |
alexa-ai upload-catalog |
CreateContentUpload, CompleteContentUpload |
alexa-ai get-content-upload-by-id |
GetContentUpload |
alexa-ai associate-catalog-with-addon |
AssociateCatalogWithAddOn |
Request headers
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | Bearer token from LWA OAuth. Format: Bearer {access_token} |
Content-Type |
Yes (POST/PUT) | application/json |
Accept |
Yes | application/json |
X-Amzn-RequestId |
No | Client-generated request ID for tracing. If omitted, the server generates one. |
Response headers
| Header | Description |
|---|---|
X-Amzn-RequestId |
Server-generated or echoed request ID for tracing. |
Location |
Returned on 201/202 responses with the URI of the created or asynchronous resource. |
Retry-After |
Returned on 429 responses. Number of seconds to wait before retrying. |
For the error response format and a full list of error codes, see Error responses.
CreateAddOnUpload
Returns a pre-signed S3 URL for uploading the addon-package ZIP.
Operation ID: createAddOnUpload
POST /v1/addons/uploads
Request body
{
"vendorId": "M2XXXXXXXX"
}
| Field | Type | Required | Description |
|---|---|---|---|
vendorId |
String | Yes | Your vendor identifier. |
Success response
200 OK
{
"uploadUrl": "https://s3.amazonaws.com/...",
"expiresAt": "2026-03-30T12:00:00Z"
}
| Field | Type | Description |
|---|---|---|
uploadUrl |
String (URI) | Pre-signed S3 URL for uploading the ZIP. Pass this as location to CreateAddOnPackage. |
expiresAt |
String (ISO 8601) | Expiration time of the pre-signed URL (default: one hour). |
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
CreateAddOnPackageWithoutAddOnId
Triggers the asynchronous build pipeline for a new add-on (no existing add-on ID).
Operation ID: createAddOnPackageWithoutAddOnId
POST /v1/addons/packages
Request body
{
"vendorId": "M2XXXXXXXX",
"location": "https://s3.amazonaws.com/addon-uploads/..."
}
| Field | Type | Required | Description |
|---|---|---|---|
vendorId |
String | Yes | Your vendor identifier. |
location |
String (URI) | Yes | S3 URL from CreateAddOnUpload. |
Success response
202 Accepted
Response header: Location: /v1/addons/{addOnId}/packages/{packageId}
{
"addOnId": "amzn1.ask.addon.abc123"
}
| Field | Type | Description |
|---|---|---|
addOnId |
String | The newly created add-on identifier. |
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 ADDON_NOT_FOUND, 409 CONFLICT, 412 PRECONDITION_FAILED, 413 PAYLOAD_TOO_LARGE, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
CreateAddOnPackage
Triggers the asynchronous build pipeline for an existing add-on.
Operation ID: createAddOnPackage
POST /v1/addons/{addOnId}/packages
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
addOnId |
String | Yes | Add-on identifier. |
Request body
{
"location": "https://s3.amazonaws.com/addon-uploads/..."
}
| Field | Type | Required | Description |
|---|---|---|---|
location |
String (URI) | Yes | S3 URL from CreateAddOnUpload. |
Success response
202 Accepted
Response header: Location: /v1/addons/{addOnId}/packages/{packageId}
{
"addOnId": "amzn1.ask.addon.abc123"
}
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 ADDON_NOT_FOUND, 409 CONFLICT, 412 PRECONDITION_FAILED, 413 PAYLOAD_TOO_LARGE, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
GetAddOnPackageStatus
Polls the build status of a package.
Operation ID: getAddOnPackageStatus
GET /v1/addons/{addOnId}/packages/{packageId}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
addOnId |
String | Yes | Add-on identifier. |
packageId |
String | Yes | Package identifier from CreateAddOnPackage (extracted from Location header). |
Success response
200 OK
{
"addOnId": "amzn1.ask.addon.abc123",
"packageId": "pkg-def456",
"status": "BUILT"
}
| Field | Type | Description |
|---|---|---|
addOnId |
String | Add-on identifier. |
packageId |
String | Package identifier. |
status |
String | IN_PROGRESS, BUILT, or FAILED. |
errors |
Array or null | Build errors. Present when FAILED. |
warnings |
Array or null | Build warnings. May be present on any terminal status. |
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 PACKAGE_NOT_FOUND, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
DeployAddOnVersionToStage
Deploys a built package to the development stage.
Operation ID: deployAddOnVersionToStage
POST /v1/addons/{addOnId}/deployments
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
addOnId |
String | Yes | Add-on identifier. |
Request body
{
"builtPackageId": "pkg-def456",
"stage": "development"
}
| Field | Type | Required | Description |
|---|---|---|---|
builtPackageId |
String | Yes | Package identifier from CreateAddOnPackage. Must be in BUILT state. |
stage |
String | Yes | Target stage. development is the supported stage. |
Success response
202 Accepted
Response header: Location: /v1/addons/{addOnId}/deployments/{deploymentId}
Response body is empty.
Error responses
400 INVALID_REQUEST, 400 INVALID_STAGE, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 ADDON_NOT_FOUND, 404 PACKAGE_NOT_FOUND, 409 INVALID_LIFECYCLE_STATE, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
GetAddOnDeploymentStatus
Polls deployment progress.
Operation ID: getAddOnDeploymentStatus
GET /v1/addons/{addOnId}/deployments/{deploymentId}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
addOnId |
String | Yes | Add-on identifier. |
deploymentId |
String | Yes | Deployment identifier from DeployAddOnVersionToStage (extracted from Location header). |
Success response
200 OK
{
"status": "SUCCEEDED",
"version": 1,
"startedAt": "2026-03-29T10:00:00Z",
"completedAt": "2026-03-29T10:00:45Z"
}
| Field | Type | Description |
|---|---|---|
status |
String | IN_PROGRESS, SUCCEEDED, or FAILED. |
version |
Integer | Assigned version number. Present only when SUCCEEDED. |
errors |
Array or null | Deployment errors. Present when FAILED. |
warnings |
Array or null | Deployment warnings. May be present on any terminal status. |
startedAt |
String (ISO 8601) | When the deployment started. |
completedAt |
String (ISO 8601) or null | When the deployment completed. Null while in progress. |
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 ADDON_NOT_FOUND, 404 DEPLOYMENT_NOT_FOUND, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
SubmitAddOnForCertification
Submits the current development version for certification.
Operation ID: submitAddOnForCertification
POST /v1/addons/{addOnId}/submit
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
addOnId |
String | Yes | Add-on identifier. |
Request body
None.
Success response
202 Accepted
{
"status": "SUBMITTED_FOR_CERTIFICATION",
"version": 3
}
| Field | Type | Description |
|---|---|---|
status |
String | SUBMITTED_FOR_CERTIFICATION |
version |
Integer | The version number submitted for certification. |
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 ADDON_NOT_FOUND, 409 CONFLICT, 409 INVALID_LIFECYCLE_STATE, 412 PRECONDITION_FAILED, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
ListAddOns
Lists all add-ons for a vendor.
Operation ID: listAddOns
GET /v1/addons
Query parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
vendorId |
String | Yes | — | Your vendor identifier. |
maxResults |
Integer | No | 10 |
Max items per page. Maximum value is 50. |
nextToken |
String | No | — | Pagination token from a previous response. |
Success response
200 OK
{
"addOns": [
{
"addOnId": "amzn1.ask.addon.abc123",
"name": "Expedia Travel",
"stage": "development",
"lastUpdated": "2026-03-29T10:00:00Z"
}
],
"nextToken": null
}
| Field | Type | Description |
|---|---|---|
addOns |
Array | List of add-on summaries. |
addOns[].addOnId |
String | Add-on identifier. |
addOns[].name |
String | Display name. |
addOns[].stage |
String | Current stage: development, certification, or live. |
addOns[].lastUpdated |
String (ISO 8601) | Last modification timestamp. |
nextToken |
String or null | Pagination token. Null if no more results. |
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 ADDON_NOT_FOUND, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
ExecuteAddOnTests
Submits a test suite for execution against a deployed add-on.
npm test rather than through this API.Operation ID: executeAddOnTests
POST /v1/addons/{addOnId}/stages/{stage}/tests
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
addOnId |
String | Yes | Add-on identifier. |
stage |
String | Yes | Stage to test against. Values: development, live. |
Success response
202 Accepted
{
"testExecutionId": "test-exec-abc123",
"status": "IN_PROGRESS"
}
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 ADDON_NOT_FOUND, 409 INVALID_LIFECYCLE_STATE, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
GetAddOnTestResults
Polls for test execution results.
Operation ID: getAddOnTestResults
GET /v1/addons/{addOnId}/tests/{testExecutionId}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
addOnId |
String | Yes | Add-on identifier. |
testExecutionId |
String | Yes | Test execution identifier from ExecuteAddOnTests. |
Success response
200 OK
{
"testExecutionId": "test-exec-abc123",
"status": "COMPLETED",
"summary": {
"totalTests": 3,
"passed": 2,
"failed": 1
},
"reportUrl": "https://s3.amazonaws.com/addon-test-reports/test-exec-abc123.json",
"reportHtmlUrl": "https://s3.amazonaws.com/addon-test-reports/test-exec-abc123.html",
"expiresAt": "2026-03-30T10:00:00Z"
}
| Field | Type | Description |
|---|---|---|
status |
String | IN_PROGRESS, COMPLETED, or SYSTEM_ERROR. |
summary |
Object or null | Test summary. Present when COMPLETED. |
summary.totalTests |
Integer | Total test cases executed. |
summary.passed |
Integer | Number of passed test cases. |
summary.failed |
Integer | Number of failed test cases. |
reportUrl |
String (URI) or null | Pre-signed URL to download the full JSON test report. Expires in 24 hours. |
reportHtmlUrl |
String (URI) or null | Pre-signed URL to download the full HTML test report. Expires in 24 hours. |
expiresAt |
String (ISO 8601) or null | Expiration time of the report download URLs. |
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 ADDON_NOT_FOUND, 404 TEST_EXECUTION_NOT_FOUND, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
CreateCatalog
Creates a new catalog for a vendor.
Operation ID: createCatalog
POST /v0/catalogs
Request body
{
"vendorId": "M2XXXXXXXX",
"title": "My POI Catalog",
"type": "AMAZON.BroadcastChannel",
"usage": "AlexaMusic.Catalog.BroadcastChannel"
}
| Field | Type | Required | Description |
|---|---|---|---|
vendorId |
String | Yes | Your vendor identifier. |
title |
String | Yes | Human-readable name for the catalog. |
type |
String | Yes | Catalog type (for example, AMAZON.BroadcastChannel). |
usage |
String | Yes | The catalog's usage (for example, AlexaMusic.Catalog.BroadcastChannel). |
Success response
201 Created
{
"catalogId": "amzn1.ask-catalog.cat.abc123"
}
| Field | Type | Description |
|---|---|---|
catalogId |
String | The newly created catalog identifier. |
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 NOT_FOUND, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
CreateContentUpload
Creates a content upload and returns pre-signed S3 URLs for multipart upload.
Operation ID: createContentUpload
POST /v0/catalogs/{catalogId}/uploads
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
catalogId |
String | Yes | Catalog identifier from CreateCatalog. |
Request body
{
"numberOfUploadParts": 1
}
| Field | Type | Required | Description |
|---|---|---|---|
numberOfUploadParts |
Integer | Yes | Number of upload parts. Calculated as ceil(fileSize / partSize) where partSize = max(ceil(fileSize / 1000), 5MB). |
Success response
201 Created
{
"uploadId": "upload-abc123",
"presignedUploadParts": [
{
"url": "https://s3.amazonaws.com/...",
"partNumber": 1
}
]
}
| Field | Type | Description |
|---|---|---|
uploadId |
String | Upload identifier. Use this to complete the upload and check status. |
presignedUploadParts |
Array | Pre-signed S3 URLs for each upload part. |
presignedUploadParts[].url |
String (URI) | Pre-signed URL to upload the part. |
presignedUploadParts[].partNumber |
Integer | Part number for this URL. |
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 NOT_FOUND, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
CompleteContentUpload
Completes a multipart upload by providing the ETags returned from each part upload.
Operation ID: completeContentUpload
POST /v0/catalogs/{catalogId}/uploads/{uploadId}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
catalogId |
String | Yes | Catalog identifier. |
uploadId |
String | Yes | Upload identifier from CreateContentUpload. |
Request body
{
"partETags": [
{ "eTag": "\"abc123def456\"", "partNumber": 1 }
]
}
| Field | Type | Required | Description |
|---|---|---|---|
partETags |
Array | Yes | List of ETag and part number pairs from the S3 upload responses. |
partETags[].eTag |
String | Yes | ETag returned by S3 after uploading the part. |
partETags[].partNumber |
Integer | Yes | Part number that corresponds to the ETag. |
Success response
202 Accepted
Response body is empty.
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 NOT_FOUND, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
GetContentUpload
Gets the processing status of a catalog content upload.
Operation ID: getContentUpload
GET /v1/catalogs/{catalogId}/uploads/{uploadId}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
catalogId |
String | Yes | Catalog identifier. |
uploadId |
String | Yes | Upload identifier from CreateContentUpload. |
Request body
None.
Success response
200 OK
{
"uploadId": "upload-abc123",
"status": "SUCCEEDED",
"ingestionSteps": [
{
"name": "UPLOAD",
"status": "SUCCEEDED"
},
{
"name": "VALIDATION",
"status": "SUCCEEDED"
}
]
}
| Field | Type | Description |
|---|---|---|
uploadId |
String | Upload identifier. |
status |
String | Overall status: IN_PROGRESS, SUCCEEDED, or FAILED. |
ingestionSteps |
Array | Processing steps with individual statuses. |
ingestionSteps[].name |
String | Step name (for example, UPLOAD, VALIDATION). |
ingestionSteps[].status |
String | Step status: IN_PROGRESS, SUCCEEDED, or FAILED. |
ingestionSteps[].errors |
Array or null | Errors for this step. Present when step status is FAILED. |
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 NOT_FOUND, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
AssociateCatalogWithAddOn
Associates a catalog with an add-on. Required after creating and uploading catalog data so the add-on can access it.
Operation ID: associateCatalogWithAddOn
PUT /v1/addons/{addOnId}/catalogs/{catalogId}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
addOnId |
String | Yes | Add-on identifier. |
catalogId |
String | Yes | Catalog identifier. |
Request body
None.
Success response
204 No Content
Response body is empty.
Error responses
400 INVALID_REQUEST, 401 NOT_AUTHENTICATED, 403 NOT_AUTHORIZED, 404 ADDON_NOT_FOUND, 404 CATALOG_NOT_FOUND, 429 TOO_MANY_REQUESTS, 500 INTERNAL_SERVER_ERROR, 503 SERVICE_UNAVAILABLE
Error responses
All AAPI endpoints return errors in the following format:
{
"code": "ERROR_CODE",
"message": "Human-readable error description."
}
| Field | Type | Description |
|---|---|---|
code |
String | Machine-readable error code. |
message |
String | Human-readable error description. |
Common error codes
| HTTP status | Code | Description |
|---|---|---|
| 400 | INVALID_REQUEST |
Malformed request body or missing required fields. |
| 400 | INVALID_STAGE |
Invalid stage value. Must be development or live. |
| 401 | NOT_AUTHENTICATED |
The request has a missing, invalid, or expired authentication token. |
| 403 | NOT_AUTHORIZED |
The caller doesn't have permission to perform this operation on the specified resource. |
| 404 | ADDON_NOT_FOUND |
Add-on with the specified ID doesn't exist. |
| 404 | PACKAGE_NOT_FOUND |
Package with the specified ID doesn't exist. |
| 404 | DEPLOYMENT_NOT_FOUND |
Deployment with the specified ID doesn't exist. |
| 404 | CATALOG_NOT_FOUND |
Catalog with the specified ID doesn't exist. |
| 404 | TEST_EXECUTION_NOT_FOUND |
Test execution with the specified ID doesn't exist. |
| 409 | CONFLICT |
Operation conflicts with current state. For example, another version is already in certification. |
| 409 | INVALID_LIFECYCLE_STATE |
Add-on isn't in the required lifecycle state for this operation. For example, attempting to publish an add-on that isn't in CERTIFICATION_APPROVED state. |
| 429 | TOO_MANY_REQUESTS |
Rate limit exceeded. Use the Retry-After response header value, in seconds, before retrying. Use exponential back-off starting from the Retry-After value. |
| 500 | INTERNAL_SERVER_ERROR |
Unexpected server error. |
Related topics
Last updated: Jul 10, 2026

