Use Skill Connections to Request Tasks


An Alexa skill can use a skill connection to request a task from Amazon or from a provider skill. For example, a recipe skill can request that a printer skill print a recipe. Before you make your skill a requester skill, determine what task you want a provider skill to fulfill, and whether you want to use an Amazon-predefined task, or a custom task that's offered by a provider skill. For an overview of skill connections, see Understand Skill Connections.

Request a task from a provider skill

A requester skill requests a task from a provider skill. If possible, the provider skill fulfills the request of the requester skill.

To pass control to the provider, the skill sends a Connections.StartConnection directive. To pass control back to the skill after verifying the user, Alexa sends a SessionResumedRequest to the skill. If you have an existing skill, you can modify this skill so that it becomes a requester, which means that it can request a task from skills that are providers.

When requesting a task from a provider skill, the requester skill can specify whether it should receive control back after the task is completed, by setting one of the following values in the onCompletion field:

  • Specify RESUME_SESSION to receive control back and return the user to the same place in the original requester skill session.
  • Specify SEND_ERRORS_ONLY to be notified of errors, without getting control back.
  • The default setting is RESUME_SESSION.

To make your skill a requester for a skill connections task

  1. Implement a handler to return a Connections.StartConnection directive.
  2. Depending on the onCompletion value you specified in your requester skill's Connections.StartConnection directive, implement one of the following.
    • If your requester skill specifies RESUME_SESSION, implement a handler to receive the response from a SessionResumedRequest request. When the provider skill completes its task, this handler enables the provider skill to return control to your requester skill.
    • If your requester skill specifies SEND_ERRORS_ONLY, implement a handler to receive the response from a System.ExceptionEncountered request. If the provider skill fails to complete its task, this handler enables Alexa to return error notification to your requester skill.

Transition prompt

During the transition from the requester skill to the provider skill, Alexa always renders a forwarding prompt. This happens whether the requester skill specifies RESUME_SESSION or SEND_ERRORS_ONLY in the Connections.StartConnection directive. This prompt cannot be customized.

  • Got it. {requester_skill_name} would like to use the skill {provider_skill_name} to do that. May I send the request to {provider_skill_name}?

If the requester skill specifies SEND_ERRORS_ONLY, Alexa doesn't render a returning prompt. If the requester skill specifies RESUME_SESSION, Alexa always renders a returning prompt during the transition from the provider skill back to the requester skill. This prompt cannot be customized.

  • Returning you to {requester_skill_name}.

Implement a handler to return a Connections.StartConnection directive to use skill connection

Your requester skill sends a skill connections request by setting the Connections.StartConnection directive in the response object, as shown in the following examples.

Return Connections.StartConnection directive with RESUME_SESSION set explicitly or by default

When setting the onCompletion field to RESUME_SESSION, your service code must leave the shouldEndSession flag undefined when it returns a Connections.StartConnection directive.

For managed skill connection

Only Amazon predefined tasks are supported in managed skill connection. In the following example, the format for task_name should always be AMAZON.{name}, for example, AMAZON.PrintPDF.

return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://{task_name}/{version_number}',
            'input': {
               ...
            },
            'onCompletion': 'RESUME_SESSION',
            'token': '...'
        })
        .getResponse();

Note that the onCompletion field is not required, and RESUME_SESSION is the default value, so the following example has the same effect as the preceding one:

return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://{task_name}/{version_number}',
            'input': {
               ...
            },
            'token': '...'
        })
        .getResponse();

For direct skill connection

Both Amazon predefined tasks and custom tasks are supported in direct skill connection. In the following example, there are two different formats for task_name:

  • For Amazon predefined tasks, the format is AMAZON.{name}, for example, AMAZON.PrintPDF
  • For custom tasks, the format is {provider_skill_id}.{name}, for example, amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown
return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://{task_name}/{version_number}?provider={provider_skill_id}',
            'input': {
               ...
            },
            'onCompletion': 'RESUME_SESSION',
            'token': '...'
        })
        .getResponse();

Return Connections.StartConnection directive with SEND_ERRORS_ONLY

When setting the onCompletion field to SEND_ERRORS_ONLY, your service code must set the shouldEndSession flag to true.

For managed skill connection

Only Amazon predefined tasks are supported in managed skill connection. In the following example, the format for task_name should always be AMAZON.{name}, for example, AMAZON.PrintPDF.

return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://{task_name}/{version_number}',
            'input': {
               ...
            },
            'onCompletion': 'SEND_ERRORS_ONLY'
        })
        .withShouldEndSession(true)
        .getResponse();

For direct skill connection

Both Amazon predefined tasks and custom tasks are supported in direct skill connection. In the following example, there are two different formats for task_name:

  • For Amazon predefined tasks, the format is AMAZON.{name}, for example, AMAZON.PrintPDF
  • For custom tasks, the format is {provider_skill_id}.{name}, for example, amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown
return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://{task_name}/{version_number}?provider={provider_skill_id}',
            'input': {
               ...
            },
            'onCompletion': 'SEND_ERRORS_ONLY'
        })
        .withShouldEndSession(true)
        .getResponse();

Response attributes

AttributeDescription
typeRequired. Type of the directive, which is Connections.StartConnection in this case.
uriRequired. Resource that defines the task and the task version.
inputOptional. Contains the request object for the task request being sent.
tokenOptional. Token comes back to the skill as-is in the SessionResumedRequest. It can be used to resume the requester skill after the task request is complete.
onCompletionOptional. Enum field that defines whether your requester skill is resumed after the task is completed. It can be either RESUME_SESSION or SEND_ERRORS_ONLY. If it is RESUME_SESSION, the requester skill receives SessionResumedRequest when the task is completed. If it is SEND_ERRORS_ONLY, the requester skill receives System.ExceptionEncountered only when an error happens.
The default value is RESUME_SESSION.

Implement a handler to receive a response from a skill connections request

If it does not set the onCompletion attribute to SEND_ERRORS_ONLY, your requester skill must also implement a handler to receive a skill connection response for the original task request. If you don't implement a response handler, your skill will have an unhandled exception, which means that your requester skill cannot take back control from the provider skill.

To implement a handler to receive a skill connection response for a task request

  • Add a SessionResumedRequest handler to the skill, as shown in the following example. When the requester skill receives a SessionResumedRequest, it restores the previous session of the skill from when the original Connections.StartConnection directive was returned.

Example: implement a response handler

The following example shows how to implement a handler to receive a response from a skill connections request.

const SessionResumedRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionResumedRequest';
  },
  handle(handlerInput) {
    const status = handlerInput.requestEnvelope.request.cause.status;
    const code = status.code;
    const message = status.message;
    console.log(`SessionResumedRequest received status code : ${code} and message : ${message}`);

    // The current sessionId is same as the one in previous IntentRequest when the original Connections.StartConnection directive was returned.
    const currentSessionId = handlerInput.requestEnvelope.session.sessionId;

    // Continue requester skill experience. In this example, it renders a speech.

    return handlerInput.responseBuilder
        .speak("Requester skill received SessionResumedRequest")
        .getResponse();
  }
};

Example: JSON schema for the SessionResumedRequest request

When onCompletion is set to RESUME_SESSION, the requester receives a SessionResumedRequest object. The result of the request is defined in the task definition.

{
    "type": "SessionResumedRequest",
    "requestId": "string",
    "timestamp": "string",
    "locale": "string",
    "cause": {
        "type": "ConnectionCompleted",
        "token": "...",
        "status": {
            "code": "200",
            "message": "OK"
        },
        "result": {
            "key1": "value1",
            "key2": "value2"
        }
    }
}

Status code attributes in SessionResumedRequest

For managed skill connection

Alexa can return any of the following status codes on a task request call.

The provider skill that is fulfilling the task request can return any valid HTTP code.

  • status: Status of the request
  • code: status code
    • 200 : Request was successfully fulfilled
    • 204 : User denied to use the Connection
    • 227 : Provider was not account linked
    • 400 : Bad request - request was invalid
    • 403 : Requester was not allowed to invoke provider
    • 404 : No providers available at this time
    • 500 : Server error
  • message : Plain string message that describes the outcome of the request. For example, this message might be "Ride has been booked successfully."

For direct skill connection

The requester skill will only receive the following status codes. The provider skill that is fulfilling the task request can only return one of the following status code.

  • status: Status of the request
  • code: status code
    • 200 : Request was successfully fulfilled
    • 400 : Bad request - request was invalid
    • 403 : Requester was not allowed to invoke provider
    • 404 : No providers available at this time
    • 500 : Server error
  • message : Plain string message that describes the outcome of the request. For example, this message might be "Ride has been booked successfully."

For more information, see Handle Requests Sent by Alexa.

Implement a handler to handle System.ExceptionEncountered

If your requester skill sets onCompletion to SEND_ERRORS_ONLY and you want to know if the requested task is not completed, you must implement a handler in the requester skill to handle the System.ExceptionEncountered request. The System.ExceptionEncountered request looks like the following example.

{
   "type": "System.ExceptionEncountered",
   "requestId": "unique.id.for.the.request",
   "timestamp": "timestamp of request in format: 2018-04-11T15:15:25Z",
   "locale": "a locale code such as en-US",
   "error": {
      "type": "error code such as INVALID_RESPONSE",
      "message": "description of the error that occurred"
   },
   "cause": {
      "requestId": "unique identifier for the request that caused the error"
   }
}

Following is example code for handling System.ExceptionEncountered. Note: This request is for notification only, and any response is ignored.

const SystemExceptionEncounteredHandler = {
   canHandle(handlerInput) {
      const request = handlerInput.requestEnvelope.request;
      return request.type === 'System.ExceptionEncountered';
   },
   handle(handlerInput) {
      console.dir(handlerInput.requestEnvelope.request);
      return handlerInput.responseBuilder
         .getResponse();
   },
};

Error types in System.ExceptionEncountered request

For both managed skill connections and direct skill connections, requester skills receive only the following error types in the System.ExceptionEncountered request.

  • error: Contains an object with error information
  • type: Identifies the specific type of error:
    • INVALID_RESPONSE: The response from the requester skill to start a connection was invalid.
    • INTERNAL_ERROR: An internal service error occurred.
  • message: A description of the error the device has encountered, for example, "The ride booking request failed."

Task request examples

The following examples show how a skill might request the fulfillment of an Amazon predefined task AMAZON.PrintPDF and custom task amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown when handling an IntentRequest.

For managed skill connection with RESUME_SESSION

const TestIntentRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'TestIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .addDirective({
        'type': 'Connections.StartConnection',
        'uri': 'connection://AMAZON.PrintPDF/1',
        'onCompletion': 'RESUME_SESSION',
        'input': {
          '@type': 'PrintPDFRequest',
          '@version': '1',
          'title': 'title',
          'description': 'description',
          'url': 'http://www.example.com/flywheel.pdf'
        },
        'token': '...'
      })
      .getResponse();
  }
};

For managed skill connection with SEND_ERRORS_ONLY

const TestIntentRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'TestIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .addDirective({
        'type': 'Connections.StartConnection',
        'uri': 'connection://AMAZON.PrintPDF/1',
        'onCompletion': 'SEND_ERRORS_ONLY',
        'input': {
          '@type': 'PrintPDFRequest',
          '@version': '1',
          'title': 'title',
          'description': 'description',
          'url': 'http://www.example.com/flywheel.pdf'
        }
      })
    .withShouldEndSession(true)
    .getResponse();
  }
};

For Amazon predefined task direct skill connection with RESUME_SESSION

const TestIntentRequestHandler = {
   canHandle(handlerInput) {
     const request = handlerInput.requestEnvelope.request;
     return request.type === 'IntentRequest'
       && request.intent.name === 'TestIntent';
   },
   handle(handlerInput) {
     return handlerInput.responseBuilder
       .addDirective({
         'type': 'Connections.StartConnection',
         'uri': 'connection://AMAZON.PrintPDF/1?provider=amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef',
         'onCompletion': 'RESUME_SESSION',
         'input': {
           '@type': 'PrintPDFRequest',
           '@version': '1',
           'title': 'title',
           'description': 'description',
           'url': 'http://www.example.com/flywheel.pdf'
         },
         'token': '...'
       })
       .getResponse();
   }
};

For Amazon predefined task direct skill connection with SEND_ERRORS_ONLY

const TestIntentRequestHandler = {
   canHandle(handlerInput) {
     const request = handlerInput.requestEnvelope.request;
     return request.type === 'IntentRequest'
       && request.intent.name === 'TestIntent';
   },
   handle(handlerInput) {
     return handlerInput.responseBuilder
       .addDirective({
         'type': 'Connections.StartConnection',
         'uri': 'connection://AMAZON.PrintPDF/1?provider=amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef',
         'onCompletion': 'SEND_ERRORS_ONLY',
         'input': {
           '@type': 'PrintPDFRequest',
           '@version': '1',
           'title': 'title',
           'description': 'description',
           'url': 'http://www.example.com/flywheel.pdf'
         }
       })
       .withShouldEndSession(true)
       .getResponse();
   }
};

For custom task direct skill connection with RESUME_SESSION

const TestIntentRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'TestIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .addDirective({
        'type': 'Connections.StartConnection',
        'uri': 'connection://amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown/1?provider=amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef',
        'onCompletion': 'RESUME_SESSION',
        'input': {
          'upperLimit': 10,
          'lowerLimit': 1
        },
        'token': '...'
      })
      .getResponse();
  }
};

For custom task direct skill connection with SEND_ERRORS_ONLY

const TestIntentRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'TestIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .addDirective({
        'type': 'Connections.StartConnection',
        'uri': 'connection://amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown/1?provider=amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef',
        'input': {
          'upperLimit': 10,
          'lowerLimit': 1
        },
        'onCompletion': 'SEND_ERRORS_ONLY'
      })
      .withShouldEndSession(true)
      .getResponse();
  }
};

Test your requester skill

After you make your skill a requester skill, you can test it as you would normally test for other invocations. After your requester skill initiates the task request, Alexa selects a suitable provider for the task request from the list of possible providers, and the Alexa service routes the request to the selected live provider skill.

Additionally, if your requester skill specifies RESUME_SESSION, you should test how it handles various status codes that it might receive. To test how your skill responds when it receives SessionResumedRequest with a specific status code, alter your requester skill to return a Connections.StartConnection directive with the AMAZON.TestStatusCode task defined. In the return body of this directive, the input includes the status code you want to test.

Example: test how your SessionResumedRequest handler deals with a 404 status code

To test how your SessionResumedRequest handler deals with receiving a 404 status code, your skill should return the following directive:

return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://AMAZON.TestStatusCode/1',
            'input': {
                'code': '404'
            }
        })
        .getResponse();

The requester skill then receives a SessionResumedRequest object that contains the status code defined in the input.

{
    "type": "SessionResumedRequest",
    "requestId": "string",
    "timestamp": "string",
    "locale": "string",
    "cause": {
        "type": "ConnectionCompleted",
        "status": {
            "code": "404",
            "message": "Status code testing succeeded"
        }
    }
}

Publish your requester skill

The certification requirements for a requester skill are no different from the requirements for a skill that is not a requester.

If you have not already published your requester skill, complete the testing and skill submission requirements as usual, and submit your skill for certification. When Amazon certifies your skill, they make it publicly available, and your skill can then function as a requester skill. If Amazon has already certified your skill, and you later make changes to make your skill a requester skill, you make those changes publicly available when you publish them.

For more information about publishing Alexa skills, see Skill Certification and Publication.

Developer support

For inquiries and support, please reach out to the Skill Connections team at skill-connections-v2-beta@amazon.com


Was this page helpful?

Last updated: Apr 30, 2024