---
title: Webhook
description: >-
Contains functions for verifying Shopify webhooks.
> Note: The format of the `admin` object returned by this function changes
with the `v3_webhookAdminContext` future flag. Learn more about [gradual
feature adoption](/docs/api/shopify-app-remix/guide-future-flags).
api_version: v2
api_name: shopify-app-remix
source_url:
html: 'https://shopify.dev/docs/api/shopify-app-remix/v2/authenticate/webhook'
md: 'https://shopify.dev/docs/api/shopify-app-remix/v2/authenticate/webhook.md'
---
# Webhook
Contains functions for verifying Shopify webhooks.
**Note:** The format of the \admin\ object returned by this function changes with the \\v3\\_webhook\Admin\Context\\ future flag. Learn more about \gradual feature adoption\.
## authenticate.webhook(**[request](#authenticatewebhook-propertydetail-request)**)
Verifies requests coming from Shopify webhooks.
### Parameters
* **request**
**Request**
**required**
### Returns
* **Promise\>**
### WebhookContext
```ts
WebhookContextWithoutSession | WebhookContextWithSession
```
### WebhookContextWithoutSession
* session
```ts
undefined
```
* admin
```ts
undefined
```
* apiVersion
The API version used for the webhook.
```ts
string
```
* shop
The shop where the webhook was triggered.
```ts
string
```
* topic
The topic of the webhook.
```ts
Topics
```
* webhookId
A unique ID for the webhook. Useful to keep track of which events your app has already processed.
```ts
string
```
* payload
The payload from the webhook request.
```ts
Record
```
* subTopic
The sub-topic of the webhook. This is only available for certain webhooks.
```ts
string
```
### WebhookContextWithSession
* session
A session with an offline token for the shop. Returned only if there is a session for the shop.
```ts
Session
```
* admin
An admin context for the webhook. Returned only if there is a session for the shop.
```ts
WebhookAdminContext
```
* apiVersion
The API version used for the webhook.
```ts
string
```
* shop
The shop where the webhook was triggered.
```ts
string
```
* topic
The topic of the webhook.
```ts
Topics
```
* webhookId
A unique ID for the webhook. Useful to keep track of which events your app has already processed.
```ts
string
```
* payload
The payload from the webhook request.
```ts
Record
```
* subTopic
The sub-topic of the webhook. This is only available for certain webhooks.
```ts
string
```
### Session
Stores App information from logged in merchants so they can make authenticated requests to the Admin API.
* id
The unique identifier for the session.
```ts
string
```
* shop
The Shopify shop domain, such as \`example.myshopify.com\`.
```ts
string
```
* state
The state of the session. Used for the OAuth authentication code flow.
```ts
string
```
* isOnline
Whether the access token in the session is online or offline.
```ts
boolean
```
* scope
The desired scopes for the access token, at the time the session was created.
```ts
string
```
* expires
The date the access token expires.
```ts
Date
```
* accessToken
The access token for the session.
```ts
string
```
* onlineAccessInfo
Information on the user for the session. Only present for online sessions.
```ts
OnlineAccessInfo
```
* isActive
Whether the session is active. Active sessions have an access token that is not expired, and has the given scopes.
```ts
(scopes: string | string[] | AuthScopes) => boolean
```
* isScopeChanged
Whether the access token has the given scopes.
```ts
(scopes: string | string[] | AuthScopes) => boolean
```
* isExpired
Whether the access token is expired.
```ts
(withinMillisecondsOfExpiry?: number) => boolean
```
* toObject
Converts an object with data into a Session.
```ts
() => SessionParams
```
* equals
Checks whether the given session is equal to this session.
```ts
(other: Session) => boolean
```
* toPropertyArray
Converts the session into an array of key-value pairs.
```ts
(returnUserData?: boolean) => [string, string | number | boolean][]
```
### OnlineAccessInfo
* expires\_in
How long the access token is valid for, in seconds.
```ts
number
```
* associated\_user\_scope
The effective set of scopes for the session.
```ts
string
```
* associated\_user
The user associated with the access token.
```ts
OnlineAccessUser
```
### OnlineAccessUser
* id
The user's ID.
```ts
number
```
* first\_name
The user's first name.
```ts
string
```
* last\_name
The user's last name.
```ts
string
```
* email
The user's email address.
```ts
string
```
* email\_verified
Whether the user has verified their email address.
```ts
boolean
```
* account\_owner
Whether the user is the account owner.
```ts
boolean
```
* locale
The user's locale.
```ts
string
```
* collaborator
Whether the user is a collaborator.
```ts
boolean
```
### AuthScopes
A class that represents a set of access token scopes.
* has
Checks whether the current set of scopes includes the given one.
```ts
(scope: string | string[] | AuthScopes) => boolean
```
* equals
Checks whether the current set of scopes equals the given one.
```ts
(otherScopes: string | string[] | AuthScopes) => boolean
```
* toString
Returns a comma-separated string with the current set of scopes.
```ts
() => string
```
* toArray
Returns an array with the current set of scopes.
```ts
() => any[]
```
### SessionParams
* \[key: string]
```ts
any
```
* id
The unique identifier for the session.
```ts
string
```
* shop
The Shopify shop domain.
```ts
string
```
* state
The state of the session. Used for the OAuth authentication code flow.
```ts
string
```
* isOnline
Whether the access token in the session is online or offline.
```ts
boolean
```
* scope
The scopes for the access token.
```ts
string
```
* expires
The date the access token expires.
```ts
Date
```
* accessToken
The access token for the session.
```ts
string
```
* onlineAccessInfo
Information on the user for the session. Only present for online sessions.
```ts
OnlineAccessInfo | StoredOnlineAccessInfo
```
### StoredOnlineAccessInfo
```ts
Omit & {
associated_user: Partial;
}
```
### WebhookAdminContext
```ts
FeatureEnabled extends true
? AdminApiContext
: LegacyWebhookAdminApiContext
```
### AdminApiContext
* rest
Methods for interacting with the Shopify Admin REST API There are methods for interacting with individual REST resources. You can also make \`GET\`, \`POST\`, \`PUT\` and \`DELETE\` requests should the REST resources not meet your needs.
```ts
RestClientWithResources
```
* graphql
Methods for interacting with the Shopify Admin GraphQL API
```ts
GraphQLClient
```
### RestClientWithResources
```ts
RemixRestClient & {resources: Resources}
```
### RemixRestClient
* session
```ts
Session
```
* get
Performs a GET request on the given path.
```ts
(params: GetRequestParams) => Promise
```
* post
Performs a POST request on the given path.
```ts
(params: PostRequestParams) => Promise
```
* put
Performs a PUT request on the given path.
```ts
(params: PostRequestParams) => Promise
```
* delete
Performs a DELETE request on the given path.
```ts
(params: GetRequestParams) => Promise
```
### GetRequestParams
* path
The path to the resource, relative to the API version root.
```ts
string
```
* type
The type of data expected in the response.
```ts
DataType
```
* data
The request body.
```ts
string | Record
```
* query
Query parameters to be sent with the request.
```ts
SearchParams
```
* extraHeaders
Additional headers to be sent with the request.
```ts
HeaderParams
```
* tries
The maximum number of times the request can be made if it fails with a throttling or server error.
```ts
number
```
### DataType
* JSON
```ts
application/json
```
* GraphQL
```ts
application/graphql
```
* URLEncoded
```ts
application/x-www-form-urlencoded
```
### HeaderParams
Headers to be sent with the request.
### PostRequestParams
```ts
GetRequestParams & {
data: Record | string;
}
```
### GraphQLClient
* query
```ts
Operation extends keyof Operations
```
* options
```ts
GraphQLQueryOptions
```
interface Promise\ { /\*\* \* Attaches callbacks for the resolution and/or rejection of the Promise. \* @param onfulfilled The callback to execute when the Promise is resolved. \* @param onrejected The callback to execute when the Promise is rejected. \* @returns A Promise for the completion of which ever callback is executed. \*/ then\(onfulfilled?: ((value: T) => TResult1 | PromiseLike\) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike\) | undefined | null): Promise\; /\*\* \* Attaches a callback for only the rejection of the Promise. \* @param onrejected The callback to execute when the Promise is rejected. \* @returns A Promise for the completion of the callback. \*/ catch\(onrejected?: ((reason: any) => TResult | PromiseLike\) | undefined | null): Promise\; }, interface Promise\ {}, Promise: PromiseConstructor, interface Promise\ { readonly \[Symbol.toStringTag]: string; }, interface Promise\ { /\*\* \* Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The \* resolved value cannot be modified from the callback. \* @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). \* @returns A Promise for the completion of the callback. \*/ finally(onfinally?: (() => void) | undefined | null): Promise\; }
```ts
interface Promise {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise;
}, interface Promise {}, Promise: PromiseConstructor, interface Promise {
readonly [Symbol.toStringTag]: string;
}, interface Promise {
/**
* Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The
* resolved value cannot be modified from the callback.
* @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected).
* @returns A Promise for the completion of the callback.
*/
finally(onfinally?: (() => void) | undefined | null): Promise;
}
```
### GraphQLQueryOptions
* variables
The variables to pass to the operation.
```ts
ApiClientRequestOptions["variables"]
```
* apiVersion
The version of the API to use for the request.
```ts
ApiVersion
```
* headers
Additional headers to include in the request.
```ts
Record
```
* tries
The total number of times to try the request if it fails.
```ts
number
```
### ApiVersion
* October22
```ts
2022-10
```
* January23
```ts
2023-01
```
* April23
```ts
2023-04
```
* July23
```ts
2023-07
```
* October23
```ts
2023-10
```
* January24
```ts
2024-01
```
* April24
```ts
2024-04
```
* Unstable
```ts
unstable
```
### LegacyWebhookAdminApiContext
* rest
A REST client.
```ts
RestClient & Resources
```
* graphql
A GraphQL client.
```ts
InstanceType
```
### RestClient
* loggedDeprecations
```ts
Record
```
* client
```ts
AdminRestApiClient
```
* session
```ts
Session
```
* apiVersion
```ts
ApiVersion
```
* get
Performs a GET request on the given path.
```ts
(params: GetRequestParams) => Promise>
```
* post
Performs a POST request on the given path.
```ts
(params: PostRequestParams) => Promise>
```
* put
Performs a PUT request on the given path.
```ts
(params: PostRequestParams) => Promise>
```
* delete
Performs a DELETE request on the given path.
```ts
(params: GetRequestParams) => Promise>
```
### RestRequestReturn
* body
```ts
T
```
* headers
```ts
Headers
```
* pageInfo
```ts
PageInfo
```
### Headers
### PageInfo
* limit
```ts
string
```
* fields
```ts
string[]
```
* previousPageUrl
```ts
string
```
* nextPageUrl
```ts
string
```
* prevPage
```ts
PageInfoParams
```
* nextPage
```ts
PageInfoParams
```
### PageInfoParams
* path
```ts
string
```
* query
```ts
SearchParams
```
Examples
### Examples
* #### Update a metafield when a product is updated
##### Description
Update a metafield when a product is updated
##### /app/routes/\*\*.ts
```typescript
import {type ActionFunctionArgs} from '@remix-run/node';
import {authenticate} from '../shopify.server';
export const action = async ({request}: ActionFunctionArgs) => {
const {topic, admin, payload} = await authenticate.webhook(request);
switch (topic) {
case 'PRODUCTS_UPDATE':
await admin.graphql(
`#graphql
mutation setMetafield($productId: ID!, $time: String!) {
metafieldsSet(metafields: {
ownerId: $productId
namespace: "my-app",
key: "webhook_received_at",
value: $time,
type: "string",
}) {
metafields {
key
value
}
}
}
`,
{
variables: {
productId: payload.admin_graphql_api_id,
time: new Date().toISOString(),
},
},
);
return new Response();
}
throw new Response();
};
```
* #### \[V3] Webhook admin context
##### Description
With the \`v3\_webhookAdminContext\` future flag enabled, use the \`admin\` object in the context to interact with the Admin API.
##### /app/routes/webhooks.tsx
```typescript
import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export async function action({ request }: ActionFunctionArgs) {
const { admin } = await authenticate.webhook(request);
const response = await admin?.graphql(
`#graphql
mutation populateProduct($input: ProductInput!) {
productCreate(input: $input) {
product {
id
}
}
}`,
{ variables: { input: { title: "Product Name" } } }
);
const productData = await response.json();
return json({ data: productData.data });
}
```
* #### Webhook admin context
##### Description
Use the \`admin\` object in the context to interact with the Admin API. This format will be removed in V3 of the package.
##### /app/routes/webhooks.tsx
```typescript
import { json, ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export async function action({ request }: ActionFunctionArgs) {
const { admin } = await authenticate.webhook(request);
const response = await admin?.graphql.query({
data: {
query: `#graphql
mutation populateProduct($input: ProductInput!) {
productCreate(input: $input) {
product {
id
}
}
}`,
variables: { input: { title: "Product Name" } },
},
});
const productData = response?.body.data;
return json({ data: productData.data });
}
```
* #### Webhook API version
##### Description
Get the API version used for webhook request.
##### /app/routes/webhooks.tsx
```typescript
import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export const action = async ({ request }: ActionFunctionArgs) => {
const { apiVersion } = await authenticate.webhook(request);
return new Response();
};
```
* #### Webhook shop
##### Description
Get the shop that triggered a webhook.
##### /app/routes/webhooks.tsx
```typescript
import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export const action = async ({ request }: ActionFunctionArgs) => {
const { shop } = await authenticate.webhook(request);
return new Response();
};
```
* #### Webhook topic
##### Description
Get the event topic for the webhook.
##### /app/routes/webhooks.tsx
```typescript
import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export const action = async ({ request }: ActionFunctionArgs) => {
const { topic } = await authenticate.webhook(request);
switch (topic) {
case "APP_UNINSTALLED":
// Do something when the app is uninstalled.
break;
}
return new Response();
};
```
* #### Webhook ID
##### Description
Get the webhook ID.
##### /app/routes/webhooks.tsx
```typescript
import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export const action = async ({ request }: ActionFunctionArgs) => {
const { webhookId } = await authenticate.webhook(request);
return new Response();
};
```
* #### Webhook payload
##### Description
Get the request's POST payload.
##### /app/routes/webhooks.tsx
```typescript
import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export const action = async ({ request }: ActionFunctionArgs) => {
const { payload } = await authenticate.webhook(request);
return new Response();
};
```
* #### Webhook sub-topic
##### Description
Get the webhook sub-topic.
##### /app/routes/webhooks.tsx
```typescript
import { ActionFunctionArgs } from "@remix-run/node";
import { authenticate } from "../shopify.server";
export const action = async ({ request }: ActionFunctionArgs) => {
const { subTopic } = await authenticate.webhook(request);
return new Response();
};
```
## Related
[Interact with the Admin API. - Admin API context](https://shopify.dev/docs/api/shopify-app-remix/apis/admin-api)