--- title: Fulfillment Service description: >- Contains functions for verifying fulfillment service requests. See the [fulfillment service documentation](https://shopify.dev/docs/apps/fulfillment/fulfillment-service-apps) for more information. api_version: v1 latest api_name: shopify-app-react-router source_url: html: >- https://shopify.dev/docs/api/shopify-app-react-router/latest/authenticate/fulfillment-service md: >- https://shopify.dev/docs/api/shopify-app-react-router/latest/authenticate/fulfillment-service.md --- # Fulfillment Service Contains functions for verifying fulfillment service requests. See the [fulfillment service documentation](https://shopify.dev/docs/apps/fulfillment/fulfillment-service-apps) for more information. ## authenticate.​fulfillment​Service([request](#authenticatefulfillmentservice-propertydetail-request)​) Verifies requests coming from Shopify to fulfillment service apps ### Parameters * request Request required ### Returns * Promise\ ### FulfillmentServiceContext * admin An admin context for the fulfillment service request. Returned only if there is a session for the shop. ```ts AdminApiContext ``` * payload The payload from the fulfillment service request. ```ts FulfillmentServicePayload ``` * session A session with an offline token for the shop. Returned only if there is a session for the shop. ```ts Session ``` ````ts export interface FulfillmentServiceContext { /** * A session with an offline token for the shop. * * Returned only if there is a session for the shop. * @example * Shopify session for the fulfillment service notification request. * Use the session associated with this request. * ```ts * // /app/routes/fulfillment_service_notification.tsx * import { ActionFunctionArgs } from "react-router"; * import { authenticate } from "../shopify.server"; * * export const action = async ({ request }: ActionFunctionArgs) => { * const { session, admin } = await authenticate.fulfillmentService(request); * * console.log(session.id) * * return new Response(); * }; * ``` * */ session: Session; /** * * An admin context for the fulfillment service request. * * Returned only if there is a session for the shop. * @example * Shopify session for the fulfillment service request. * Use the session associated with this request to use the Admin GraphQL API * ```ts * // /app/routes/fulfillment_order_notification.ts * import { ActionFunctionArgs } from "react-router"; * import { authenticate } from "../shopify.server"; * * export async function action({ request }: ActionFunctionArgs) { * const { admin, session } = await authenticate.fulfillmentService(request); * * console.log(session.id) * * return new Response(); * } * ``` */ admin: AdminApiContext; /** * The payload from the fulfillment service request. * * @example * Fulfillment service request payload. * Get the request's POST payload. * ```ts * /app/routes/fulfillment_order_notification.ts * import { ActionFunction } from "react-router"; * import { authenticate } from "../shopify.server"; * * export const action: ActionFunction = async ({ request }) => { * const { payload } = await authenticate.fulfillmentService(request); * if(payload.kind === 'FULFILLMENT_REQUEST') { * // handle fulfillment request * } else if (payload.kind === 'CANCELLATION_REQUEST') { * // handle cancellation request * }; * return new Response(); * ``` */ payload: FulfillmentServicePayload; } ```` ### AdminApiContext * graphql Methods for interacting with the Shopify Admin GraphQL API ```ts GraphQLClient ``` ````ts export interface AdminApiContext { /** * Methods for interacting with the Shopify Admin GraphQL API * * {@link https://shopify.dev/docs/api/admin-graphql} * {@link https://github.com/Shopify/shopify-app-js/blob/main/packages/apps/shopify-api/docs/reference/clients/Graphql.md} * * @example * Querying the GraphQL API. * Use `admin.graphql` to make query / mutation requests. * ```ts * // /app/routes/**\/*.ts * import { ActionFunctionArgs } from "react-router"; * import { authenticate } from "../shopify.server"; * * export const action = async ({ request }: ActionFunctionArgs) => { * const { admin } = await authenticate.admin(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 ({ * productId: productData.data?.productCreate?.product?.id, * }); * } * ``` * * ```ts * // /app/shopify.server.ts * import { shopifyApp } from "@shopify/shopify-app-react-router/server"; * * const shopify = shopifyApp({ * // ... * }); * export default shopify; * export const authenticate = shopify.authenticate; * ``` * * @example * Handling GraphQL errors. * Catch `GraphqlQueryError` errors to see error messages from the API. * ```ts * // /app/routes/**\/*.ts * import { ActionFunctionArgs } from "react-router"; * import { authenticate } from "../shopify.server"; * * export const action = async ({ request }: ActionFunctionArgs) => { * const { admin } = await authenticate.admin(request); * * try { * const response = await admin.graphql( * `#graphql * query incorrectQuery { * products(first: 10) { * nodes { * not_a_field * } * } * }`, * ); * * return ({ data: await response.json() }); * } catch (error) { * if (error instanceof GraphqlQueryError) { * // error.body.errors: * // { graphQLErrors: [ * // { message: "Field 'not_a_field' doesn't exist on type 'Product'" } * // ] } * return ({ errors: error.body?.errors }, { status: 500 }); * } * return ({ message: "An error occurred" }, { status: 500 }); * } * } * ``` * * ```ts * // /app/shopify.server.ts * import { shopifyApp } from "@shopify/shopify-app-react-router/server"; * * const shopify = shopifyApp({ * // ... * }); * export default shopify; * export const authenticate = shopify.authenticate; * ``` */ graphql: GraphQLClient; } ```` ### 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; } ``` ```ts < Operation extends keyof Operations, >( query: Operation, options?: GraphQLQueryOptions, ) => Promise> ``` ### GraphQLQueryOptions * apiVersion The version of the API to use for the request. ```ts ApiVersion ``` * headers Additional headers to include in the request. ```ts Record ``` * signal An optional AbortSignal to cancel the request. ```ts AbortSignal ``` * tries The total number of times to try the request if it fails. ```ts number ``` * variables The variables to pass to the operation. ```ts ApiClientRequestOptions["variables"] ``` ```ts export interface GraphQLQueryOptions< Operation extends keyof Operations, Operations extends AllOperations, > { /** * The variables to pass to the operation. */ variables?: ApiClientRequestOptions['variables']; /** * The version of the API to use for the request. */ apiVersion?: ApiVersion; /** * Additional headers to include in the request. */ headers?: Record; /** * The total number of times to try the request if it fails. */ tries?: number; /** * An optional AbortSignal to cancel the request. */ signal?: AbortSignal; } ``` ### FulfillmentServicePayload ```ts Record & { kind: string; } ``` Examples ### Examples * #### Consume a fulfillment service notification request ##### Description Handle a fulfillment service notification call ##### /app/routes/\*\*.ts ```typescript import {type ActionFunctionArgs} from 'react-router'; import {authenticate} from '../shopify.server'; export const action = async ({request}: ActionFunctionArgs) => { const {admin, payload} = await authenticate.fulfillmentService(request); const kind = payload.kind; if (kind === 'FULFILLMENT_REQUEST') { const response = await admin?.graphql( `#graphql query { shop { assignedFulfillmentOrders(first: 10, assignmentStatus: FULFILLMENT_REQUESTED) { edges { node { id destination { firstName lastName } lineItems(first: 10) { edges { node { id productTitle sku remainingQuantity } } } merchantRequests(first: 10, kind: FULFILLMENT_REQUEST) { edges { node { message } } } } } } } }`, ); const fulfillments = await response.json(); console.log(fulfillments); } return new Response(); }; ``` * #### Shopify session for the fulfillment service request ##### Description Use the session associated with this request to use the Admin GraphQL API ##### /app/routes/fulfillment\_order\_notification.ts ```typescript import { ActionFunctionArgs } from "react-router"; import { authenticate } from "../shopify.server"; export async function action({ request }: ActionFunctionArgs) { const { admin, session } = await authenticate.fulfillmentService(request); console.log(session.id) return new Response(); } ``` * #### Fulfillment service request payload ##### Description Get the request's POST payload. ##### Example ```typescript /app/routes/fulfillment_order_notification.ts import { ActionFunction } from "react-router"; import { authenticate } from "../shopify.server"; export const action: ActionFunction = async ({ request }) => { const { payload } = await authenticate.fulfillmentService(request); if(payload.kind === 'FULFILLMENT_REQUEST') { // handle fulfillment request } else if (payload.kind === 'CANCELLATION_REQUEST') { // handle cancellation request }; return new Response(); ``` * #### Shopify session for the fulfillment service notification request ##### Description Use the session associated with this request. ##### /app/routes/fulfillment\_service\_notification.tsx ```typescript import { ActionFunctionArgs } from "react-router"; import { authenticate } from "../shopify.server"; export const action = async ({ request }: ActionFunctionArgs) => { const { session, admin } = await authenticate.fulfillmentService(request); console.log(session.id) return new Response(); }; ``` ## Related [Interact with the Admin API. - Admin API context](https://shopify.dev/docs/api/shopify-app-react-router/apis/admin-api) [Receive fulfillment requests and cancellations. - Manage Fulfillments](https://shopify.dev/docs/apps/fulfillment/fulfillment-service-apps/manage-fulfillments)