Kit skills endpoints
This guide contains example endpoint calls to help you add a Kit Skill to your app.
Endpoint requirements
The requirements for the Kit Skills extension are as follows:
rule/concern | type/requirement |
---|---|
API format | REST |
Content type | JSON |
Security mechanism | HMAC/Signed requests. See Using webhooks to learn how to verify a webhook created through the API. |
Protocol | HTTPS (app domain requires valid SSL certificate) |
Endpoint naming requirements
Your app's endpoints must use the following server URL format:
https://#{app_url}/#{custom_namespace}
The URL must meet the following criteria:
- The protocol is HTTPS (the app must have a valid SSL certificate).
- The endpoint's URL includes the app URL defined in the Partner Dashboard.
- A fixed namespace is used, provided in the app extension.
The following example shows a typical endpoint:
https://google-shopping.shopify.com/kit_skills
Execution endpoint
If the merchant accepts the task, then Shopify sends a request to your app's execution endpoint to execute it.
HTTP request
POST "#{base_endpoint}/kit_skills"
Expected request header:
X-Shopify-Hmac-Sha256
For more information, see Implement verification.
Expected HTTP status response:
- 200 - OK
- 201 - Created
- 204 - No Content
It is preferable to return a 200 or 201 response if possible. A 204 response is also acceptable based on the needs of your app.
JSON input
{
"conversation": {
"uid": "<generated_uid>",
"shop_id": "<shop_id>" ,
"<action_parameter_key_1>": "<action_parameter_selected_value_1>",
...
"<action_parameter_key_N>": "<action_parameter_selected_value_N>",
}
}
Parameter | Description | Type |
---|---|---|
uid |
The uid of the unique conversation generated by Shopify. |
string |
shop_id |
The shop ID. | integer |
action_parameter_key |
The variable name of a question provided as part of the Kit Skill. | string |
action_parameter_value |
The merchant-provided value for a Kit Skill question. | string |
Example
In the following example, the key daily_budget
corresponds to an action_parameter_key
and the assigned value was collected from the merchant response. In the example, the merchant picked the option of a $5 daily budget.
{
"conversation": {
"uid": "655e0106-61b9-4156-9031-fddf2b744ef3",
"shop_id": "22172021",
"daily_budget": 5
}
}
App response
The app responds with the appropriate HTTP status code: 200, 201, 204, or a 5xx error. Returning a response body is optional.
Feedback endpoint
Shopify sends a request to your app's feedback endpoint that reports the merchant's acceptance or rejection of the app's action. The signed POST request includes a JSON feedback object as the request payload. If the merchant says “no” to the Opt-in or Prompt message, then Kit prompts the merchant for feedback on why they rejected the proposed action. If feedback is provided, then it is included in the feedback data object. Otherwise, the data field is sent with a value of null
.
If your execution endpoint fails, times out, or responds with a status code other than 200, 201, or 204, then Shopify will send attempt feedback to your app's feedback endpoint.
HTTP request
POST “#{base_endpoint}/kit_skills/feedback”
Expected request header:
X-Shopify-Hmac-Sha256
For more information, see Implement verification.
Expected HTTP status response:
- 200 - OK
- 201 - Created
- 204 - No Content
It is preferable to return a 200 or 201 response if possible. A 204 response is also acceptable based on the needs of your app.
JSON input
{
"feedback": {
"uid": "<conversation.uid>",
"type": "Acceptance|Rejection|Attempt", // one possible value
"data": {
"response": "merchant feedback", // if Rejection
},
},
}
Parameter | Description | Type | |
---|---|---|---|
uid |
The uid of the unique conversation generated by Shopify. |
string |
|
type |
The type of feedback response. Possible values: Acceptance , Rejection , Attempt . |
string |
|
data |
response |
String containing the feedback response from the merchant, only sent on rejection. | string |
Example rejection with feedback
{
"feedback": {
"uid": "40276f05-d5d3-458c-8bd8-0de42594fff7",
"type": "Rejection",
"data": {
"response": "I don't like the products you picked"
},
},
}
Example rejection without feedback
{
"feedback": {
"uid": "40276f05-d5d3-458c-8bd8-0de42594fff7",
"type": "Rejection",
"data": null,
},
}
Example acceptance
{
"feedback": {
"uid": "40276f05-d5d3-458c-8bd8-0de42594fff7",
"type": "Acceptance",
"data": null
}
}
Example attempt feedback
{
"feedback": {
"uid": "40276f05-d5d3-458c-8bd8-0de42594fff7",
"type": "Attempt",
"data": null
}
App response
The app responds with the appropriate HTTP status code: 200, 201, 204, or a 5xx error. Returning a response body is optional.
GraphQL Admin API mutation
After an app detects a conversation trigger, it can initiate a conversation by using the kitSkillTriggerRequest
mutation from the GraphQL Admin API. The mutation needs to include the Kit Skill's UUID, as created during the app extension definition. If you've used Liquid parameters as part of the conversation, placeholders can be included.
Endpoint
The kitSkillTriggerRequest
mutation request is sent to the following GraphQL endpoint:
POST https://{shop}.myshopify.com/admin/api/2020-10/graphql.json
The header Content-Type
must be defined to application/graphql
, in order to send a valid GraphQL mutation kitSkillTriggerRequest
request. If you are using an HTTP client, such as Postman or Insomnia, then you must set Content-Type
to application/json
instead of application/graphql
.
Examples
The following mutation creates the Kit Skill conversation and returns the conversationUid
.
mutation {
kitSkillTriggerRequest(id: "gid://shopify/KitSkill/b06e0a13-8f6e-4f03-8b23-0cc3f702e9b9", locale: EN) {
conversationUid
}
}
Response:
{
"data": {
"kitSkillTriggerRequest": {
"conversationUid": "88122a00-9e8b-4b5d-826f-66434beca1e0"
}
},
...
}
The following mutation triggers the conversation including placeholders
values. These placeholders correspond to the Liquid parameters included in your app extension definition. In the example below, the shop_name
Liquid parameter, provided as part of the proposal message, uses the value "My super shop".
mutation {
kitSkillTriggerRequest(
id: "gid://shopify/KitSkill/b06e0a13-8f6e-4f03-8b23-0cc3f702e9b9",
locale: EN,
placeholders: "{\"locale\":{\"en\":{\"opening_message\":{\"shop_name\":\"My super shop\"}}}}") {
conversationUid
}
}
Response:
{
"data": {
"kitSkillTriggerRequest": {
"conversationUid": "bcd9e151-c8a7-4466-ae90-c91ff9e50b7d"
}
},
...
}
Access scope
Before your app can trigger conversations with merchants, you must prompt the merchant to agree to the write_kit_skills
permission. This can be done as part of the OAuth flow.
Rate limiting
The kitSkillTriggerRequest
mutation rate limit is one request per shop ID and app extension per twenty four hours. After the rate limit is exceeded, any mutation requests return an error message: You may only send a Kit Skill once every 24 hours to a shop
. This limit does not apply to development stores.
Errors
When the GraphQL mutation kitSkillTriggerRequest
is sent and the Kit app is not installed, the following error response is returned:
{
"data": {
"kitSkillTriggerRequest": null,
},
“errors”: [{
“message”: “Kit App not installed.”
...
}]
...
}
When the GraphQL mutation kitSkillTriggerRequest
is sent and the access scope write_kit_skills
is missing, the following error response is returned:
{
"data": {
"kitSkillTriggerRequest": null,
},
“errors”: [{
“message”: “KitSkillTriggerRequest access denied.”
...
}]
...
}
Implement verification
App extension requests by Shopify can be verified by calculating a digital signature.
Each request includes a base64-encoded X-Shopify-Hmac-SHA256 header, which is generated using the app's shared secret along with the data sent in the request.
To verify that the request came from Shopify, compute the HMAC digest and compare it to the value in the X-Shopify-Hmac-SHA256 header. If they match, then the app extension request was sent from Shopify.
For more information see Using webhooks to learn how to verify a webhook created through the API. The procedure for app extensions is the same.