diff --git a/.changeset/wet-jars-love.md b/.changeset/wet-jars-love.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/wet-jars-love.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/shopify-app-remix/docs/generated/generated_docs_data.json b/packages/shopify-app-remix/docs/generated/generated_docs_data.json index 3cf4aba774..05a5341331 100644 --- a/packages/shopify-app-remix/docs/generated/generated_docs_data.json +++ b/packages/shopify-app-remix/docs/generated/generated_docs_data.json @@ -250,29 +250,43 @@ "examples": [ { "title": "Using REST resources", - "description": "Getting the number of orders in a store using REST resources.", + "description": "Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource.", "tabs": [ - { - "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", - "title": "/app/shopify.server.ts" - }, { "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] }, { "title": "Performing a GET request to the REST API", - "description": "Use `admin.rest.` to make custom requests to the API.", + "description": "Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint", "tabs": [ + { + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "title": "/app/routes/**\\/*.ts" + }, { "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "title": "/app/shopify.server.ts" - }, + } + ] + }, + { + "title": "Performing a POST request to the REST API", + "description": "Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email", + "tabs": [ { - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = admin.rest.post({\n path: \"customers/7392136888625/send_invite.json\",\n body: {\n customer_invite: {\n to: \"new_test_email@shopify.com\",\n from: \"j.limited@example.com\",\n bcc: [\"j.limited@example.com\"],\n subject: \"Welcome to my new shop\",\n custom_message: \"My awesome new store\",\n },\n },\n});\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] } @@ -298,7 +312,7 @@ ] } ], - "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.` to make custom requests to the API.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" + "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource. \n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n * @example\n * Performing a POST request to the REST API.\n * Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = admin.rest.post({\n * path: \"customers/7392136888625/send_invite.json\",\n * body: {\n * customer_invite: {\n * to: \"new_test_email@shopify.com\",\n * from: \"j.limited@example.com\",\n * bcc: [\"j.limited@example.com\"],\n * subject: \"Welcome to my new shop\",\n * custom_message: \"My awesome new store\",\n * },\n * },\n * });\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" }, "RestClientWithResources": { "filePath": "/server/clients/admin/rest.ts", @@ -321,7 +335,7 @@ "examples": [ { "title": "Requesting billing right away", - "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to Shopify page to request payment.", + "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.", "tabs": [ { "code": "import { LoaderFunctionArgs } from \"@remix-run/node\";\nimport { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { billing } = await authenticate.admin(request);\n await billing.require({\n plans: [MONTHLY_PLAN],\n isTest: true,\n onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n });\n\n // App logic\n};", @@ -396,7 +410,7 @@ ] } ], - "value": "export interface BillingContext {\n /**\n * Checks if the shop has an active payment for any plan defined in the `billing` config option.\n *\n * @returns A promise that resolves to an object containing the active purchases for the shop.\n *\n * @example\n * Requesting billing right away.\n * Call `billing.request` in the `onFailure` callback to immediately redirect to Shopify page to request payment.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * isTest: true,\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * @example\n * Using a plan selection page.\n * When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, redirect } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN, ANNUAL_PLAN],\n * isTest: true,\n * onFailure: () => redirect('/select-plan'),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * console.log(`Shop is on ${subscription.name} (id ${subscription.id})`);\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n require: (\n options: RequireBillingOptions,\n ) => Promise;\n\n /**\n * Requests payment for the plan.\n *\n * @returns Redirects to the confirmation URL for the payment.\n *\n * @example\n * Using a custom return URL.\n * Change where the merchant is returned to after approving the purchase using the `returnUrl` option.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({\n * plan: MONTHLY_PLAN,\n * isTest: true,\n * returnUrl: '/billing-complete',\n * }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n request: (options: RequestBillingOptions) => Promise;\n\n /**\n * Cancels an ongoing subscription, given its ID.\n *\n * @returns The cancelled subscription.\n *\n * @example\n * Cancelling a subscription.\n * Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`.\n * ```ts\n * // /app/routes/cancel-subscription.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * const cancelledSubscription = await billing.cancel({\n * subscriptionId: subscription.id,\n * isTest: true,\n * prorate: true,\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n cancel: (options: CancelBillingOptions) => Promise;\n}" + "value": "export interface BillingContext {\n /**\n * Checks if the shop has an active payment for any plan defined in the `billing` config option.\n *\n * @returns A promise that resolves to an object containing the active purchases for the shop.\n *\n * @example\n * Requesting billing right away.\n * Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * isTest: true,\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * @example\n * Using a plan selection page.\n * When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, redirect } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN, ANNUAL_PLAN],\n * isTest: true,\n * onFailure: () => redirect('/select-plan'),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * console.log(`Shop is on ${subscription.name} (id ${subscription.id})`);\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n require: (\n options: RequireBillingOptions,\n ) => Promise;\n\n /**\n * Requests payment for the plan.\n *\n * @returns Redirects to the confirmation URL for the payment.\n *\n * @example\n * Using a custom return URL.\n * Change where the merchant is returned to after approving the purchase using the `returnUrl` option.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({\n * plan: MONTHLY_PLAN,\n * isTest: true,\n * returnUrl: '/billing-complete',\n * }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n request: (options: RequestBillingOptions) => Promise;\n\n /**\n * Cancels an ongoing subscription, given its ID.\n *\n * @returns The cancelled subscription.\n *\n * @example\n * Cancelling a subscription.\n * Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`.\n * ```ts\n * // /app/routes/cancel-subscription.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * const cancelledSubscription = await billing.cancel({\n * subscriptionId: subscription.id,\n * isTest: true,\n * prorate: true,\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n cancel: (options: CancelBillingOptions) => Promise;\n}" }, "RequireBillingOptions": { "filePath": "/server/authenticate/admin/billing/types.ts", @@ -801,36 +815,54 @@ "title": "rest", "examples": [ { - "description": "Getting the number of orders in a store using REST resources.", + "description": "Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource.", "codeblock": { "title": "Using REST resources", "tabs": [ { - "title": "/app/shopify.server.ts", - "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/routes/**\\/*.ts", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", "language": "typescript" }, { - "title": "/app/routes/**\\/*.ts", - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", + "title": "/app/shopify.server.ts", + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "language": "typescript" } ] } }, { - "description": "Use `admin.rest.` to make custom requests to the API.", + "description": "Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint", "codeblock": { "title": "Performing a GET request to the REST API", "tabs": [ + { + "title": "/app/routes/**\\/*.ts", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "language": "typescript" + }, { "title": "/app/shopify.server.ts", "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "language": "typescript" - }, + } + ] + } + }, + { + "description": "Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email", + "codeblock": { + "title": "Performing a POST request to the REST API", + "tabs": [ { "title": "/app/routes/**\\/*.ts", - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = admin.rest.post({\n path: \"customers/7392136888625/send_invite.json\",\n body: {\n customer_invite: {\n to: \"new_test_email@shopify.com\",\n from: \"j.limited@example.com\",\n bcc: [\"j.limited@example.com\"],\n subject: \"Welcome to my new shop\",\n custom_message: \"My awesome new store\",\n },\n },\n});\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "language": "typescript" + }, + { + "title": "/app/shopify.server.ts", + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "language": "typescript" } ] @@ -860,7 +892,7 @@ "title": "require", "examples": [ { - "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to Shopify page to request payment.", + "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.", "codeblock": { "title": "Requesting billing right away", "tabs": [ @@ -972,7 +1004,7 @@ "examples": [ { "title": "Requesting billing right away", - "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to Shopify page to request payment.", + "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.", "tabs": [ { "code": "import { LoaderFunctionArgs } from \"@remix-run/node\";\nimport { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { billing } = await authenticate.admin(request);\n await billing.require({\n plans: [MONTHLY_PLAN],\n isTest: true,\n onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n });\n\n // App logic\n};", @@ -1047,7 +1079,7 @@ ] } ], - "value": "export interface BillingContext {\n /**\n * Checks if the shop has an active payment for any plan defined in the `billing` config option.\n *\n * @returns A promise that resolves to an object containing the active purchases for the shop.\n *\n * @example\n * Requesting billing right away.\n * Call `billing.request` in the `onFailure` callback to immediately redirect to Shopify page to request payment.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * isTest: true,\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * @example\n * Using a plan selection page.\n * When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, redirect } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN, ANNUAL_PLAN],\n * isTest: true,\n * onFailure: () => redirect('/select-plan'),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * console.log(`Shop is on ${subscription.name} (id ${subscription.id})`);\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n require: (\n options: RequireBillingOptions,\n ) => Promise;\n\n /**\n * Requests payment for the plan.\n *\n * @returns Redirects to the confirmation URL for the payment.\n *\n * @example\n * Using a custom return URL.\n * Change where the merchant is returned to after approving the purchase using the `returnUrl` option.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({\n * plan: MONTHLY_PLAN,\n * isTest: true,\n * returnUrl: '/billing-complete',\n * }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n request: (options: RequestBillingOptions) => Promise;\n\n /**\n * Cancels an ongoing subscription, given its ID.\n *\n * @returns The cancelled subscription.\n *\n * @example\n * Cancelling a subscription.\n * Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`.\n * ```ts\n * // /app/routes/cancel-subscription.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * const cancelledSubscription = await billing.cancel({\n * subscriptionId: subscription.id,\n * isTest: true,\n * prorate: true,\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n cancel: (options: CancelBillingOptions) => Promise;\n}" + "value": "export interface BillingContext {\n /**\n * Checks if the shop has an active payment for any plan defined in the `billing` config option.\n *\n * @returns A promise that resolves to an object containing the active purchases for the shop.\n *\n * @example\n * Requesting billing right away.\n * Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * isTest: true,\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * @example\n * Using a plan selection page.\n * When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, redirect } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN, ANNUAL_PLAN],\n * isTest: true,\n * onFailure: () => redirect('/select-plan'),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * console.log(`Shop is on ${subscription.name} (id ${subscription.id})`);\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n require: (\n options: RequireBillingOptions,\n ) => Promise;\n\n /**\n * Requests payment for the plan.\n *\n * @returns Redirects to the confirmation URL for the payment.\n *\n * @example\n * Using a custom return URL.\n * Change where the merchant is returned to after approving the purchase using the `returnUrl` option.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({\n * plan: MONTHLY_PLAN,\n * isTest: true,\n * returnUrl: '/billing-complete',\n * }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n request: (options: RequestBillingOptions) => Promise;\n\n /**\n * Cancels an ongoing subscription, given its ID.\n *\n * @returns The cancelled subscription.\n *\n * @example\n * Cancelling a subscription.\n * Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`.\n * ```ts\n * // /app/routes/cancel-subscription.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * const cancelledSubscription = await billing.cancel({\n * subscriptionId: subscription.id,\n * isTest: true,\n * prorate: true,\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n cancel: (options: CancelBillingOptions) => Promise;\n}" }, "RequireBillingOptions": { "filePath": "/server/authenticate/admin/billing/types.ts", @@ -1161,7 +1193,7 @@ "title": "require", "examples": [ { - "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to Shopify page to request payment.", + "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.", "codeblock": { "title": "Requesting billing right away", "tabs": [ @@ -1469,29 +1501,43 @@ "examples": [ { "title": "Using REST resources", - "description": "Getting the number of orders in a store using REST resources.", + "description": "Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource.", "tabs": [ - { - "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", - "title": "/app/shopify.server.ts" - }, { "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] }, { "title": "Performing a GET request to the REST API", - "description": "Use `admin.rest.` to make custom requests to the API.", + "description": "Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint", "tabs": [ + { + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "title": "/app/routes/**\\/*.ts" + }, { "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "title": "/app/shopify.server.ts" - }, + } + ] + }, + { + "title": "Performing a POST request to the REST API", + "description": "Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email", + "tabs": [ { - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = admin.rest.post({\n path: \"customers/7392136888625/send_invite.json\",\n body: {\n customer_invite: {\n to: \"new_test_email@shopify.com\",\n from: \"j.limited@example.com\",\n bcc: [\"j.limited@example.com\"],\n subject: \"Welcome to my new shop\",\n custom_message: \"My awesome new store\",\n },\n },\n});\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] } @@ -1517,7 +1563,7 @@ ] } ], - "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.` to make custom requests to the API.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" + "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource. \n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n * @example\n * Performing a POST request to the REST API.\n * Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = admin.rest.post({\n * path: \"customers/7392136888625/send_invite.json\",\n * body: {\n * customer_invite: {\n * to: \"new_test_email@shopify.com\",\n * from: \"j.limited@example.com\",\n * bcc: [\"j.limited@example.com\"],\n * subject: \"Welcome to my new shop\",\n * custom_message: \"My awesome new store\",\n * },\n * },\n * });\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" }, "RestClientWithResources": { "filePath": "/server/clients/admin/rest.ts", @@ -2208,14 +2254,14 @@ { "filePath": "/server/types.ts", "syntaxKind": "MethodSignature", - "name": "__@iterator@579", + "name": "__@iterator@629", "value": "() => IterableIterator", "description": "Iterator" }, { "filePath": "/server/types.ts", "syntaxKind": "MethodSignature", - "name": "__@unscopables@581", + "name": "__@unscopables@631", "value": "() => { copyWithin: boolean; entries: boolean; fill: boolean; find: boolean; findIndex: boolean; keys: boolean; values: boolean; }", "description": "Returns an object whose properties have the value 'true'\r\nwhen they will be absent when used in a 'with' statement." }, @@ -2507,29 +2553,43 @@ "examples": [ { "title": "Using REST resources", - "description": "Getting the number of orders in a store using REST resources.", + "description": "Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource.", "tabs": [ - { - "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", - "title": "/app/shopify.server.ts" - }, { "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] }, { "title": "Performing a GET request to the REST API", - "description": "Use `admin.rest.` to make custom requests to the API.", + "description": "Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint", "tabs": [ + { + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "title": "/app/routes/**\\/*.ts" + }, { "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "title": "/app/shopify.server.ts" - }, + } + ] + }, + { + "title": "Performing a POST request to the REST API", + "description": "Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email", + "tabs": [ { - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = admin.rest.post({\n path: \"customers/7392136888625/send_invite.json\",\n body: {\n customer_invite: {\n to: \"new_test_email@shopify.com\",\n from: \"j.limited@example.com\",\n bcc: [\"j.limited@example.com\"],\n subject: \"Welcome to my new shop\",\n custom_message: \"My awesome new store\",\n },\n },\n});\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] } @@ -2555,7 +2615,7 @@ ] } ], - "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.` to make custom requests to the API.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" + "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource. \n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n * @example\n * Performing a POST request to the REST API.\n * Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = admin.rest.post({\n * path: \"customers/7392136888625/send_invite.json\",\n * body: {\n * customer_invite: {\n * to: \"new_test_email@shopify.com\",\n * from: \"j.limited@example.com\",\n * bcc: [\"j.limited@example.com\"],\n * subject: \"Welcome to my new shop\",\n * custom_message: \"My awesome new store\",\n * },\n * },\n * });\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" }, "RestClientWithResources": { "filePath": "/server/clients/admin/rest.ts", @@ -2578,7 +2638,7 @@ "examples": [ { "title": "Requesting billing right away", - "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to Shopify page to request payment.", + "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.", "tabs": [ { "code": "import { LoaderFunctionArgs } from \"@remix-run/node\";\nimport { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { billing } = await authenticate.admin(request);\n await billing.require({\n plans: [MONTHLY_PLAN],\n isTest: true,\n onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n });\n\n // App logic\n};", @@ -2653,7 +2713,7 @@ ] } ], - "value": "export interface BillingContext {\n /**\n * Checks if the shop has an active payment for any plan defined in the `billing` config option.\n *\n * @returns A promise that resolves to an object containing the active purchases for the shop.\n *\n * @example\n * Requesting billing right away.\n * Call `billing.request` in the `onFailure` callback to immediately redirect to Shopify page to request payment.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * isTest: true,\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * @example\n * Using a plan selection page.\n * When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, redirect } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN, ANNUAL_PLAN],\n * isTest: true,\n * onFailure: () => redirect('/select-plan'),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * console.log(`Shop is on ${subscription.name} (id ${subscription.id})`);\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n require: (\n options: RequireBillingOptions,\n ) => Promise;\n\n /**\n * Requests payment for the plan.\n *\n * @returns Redirects to the confirmation URL for the payment.\n *\n * @example\n * Using a custom return URL.\n * Change where the merchant is returned to after approving the purchase using the `returnUrl` option.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({\n * plan: MONTHLY_PLAN,\n * isTest: true,\n * returnUrl: '/billing-complete',\n * }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n request: (options: RequestBillingOptions) => Promise;\n\n /**\n * Cancels an ongoing subscription, given its ID.\n *\n * @returns The cancelled subscription.\n *\n * @example\n * Cancelling a subscription.\n * Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`.\n * ```ts\n * // /app/routes/cancel-subscription.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * const cancelledSubscription = await billing.cancel({\n * subscriptionId: subscription.id,\n * isTest: true,\n * prorate: true,\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n cancel: (options: CancelBillingOptions) => Promise;\n}" + "value": "export interface BillingContext {\n /**\n * Checks if the shop has an active payment for any plan defined in the `billing` config option.\n *\n * @returns A promise that resolves to an object containing the active purchases for the shop.\n *\n * @example\n * Requesting billing right away.\n * Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * isTest: true,\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * @example\n * Using a plan selection page.\n * When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, redirect } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN, ANNUAL_PLAN],\n * isTest: true,\n * onFailure: () => redirect('/select-plan'),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * console.log(`Shop is on ${subscription.name} (id ${subscription.id})`);\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n require: (\n options: RequireBillingOptions,\n ) => Promise;\n\n /**\n * Requests payment for the plan.\n *\n * @returns Redirects to the confirmation URL for the payment.\n *\n * @example\n * Using a custom return URL.\n * Change where the merchant is returned to after approving the purchase using the `returnUrl` option.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({\n * plan: MONTHLY_PLAN,\n * isTest: true,\n * returnUrl: '/billing-complete',\n * }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n request: (options: RequestBillingOptions) => Promise;\n\n /**\n * Cancels an ongoing subscription, given its ID.\n *\n * @returns The cancelled subscription.\n *\n * @example\n * Cancelling a subscription.\n * Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`.\n * ```ts\n * // /app/routes/cancel-subscription.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * const cancelledSubscription = await billing.cancel({\n * subscriptionId: subscription.id,\n * isTest: true,\n * prorate: true,\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n cancel: (options: CancelBillingOptions) => Promise;\n}" }, "RequireBillingOptions": { "filePath": "/server/authenticate/admin/billing/types.ts", @@ -3106,29 +3166,43 @@ "examples": [ { "title": "Using REST resources", - "description": "Getting the number of orders in a store using REST resources.", + "description": "Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource.", "tabs": [ - { - "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", - "title": "/app/shopify.server.ts" - }, { "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] }, { "title": "Performing a GET request to the REST API", - "description": "Use `admin.rest.` to make custom requests to the API.", + "description": "Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint", "tabs": [ + { + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "title": "/app/routes/**\\/*.ts" + }, { "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "title": "/app/shopify.server.ts" - }, + } + ] + }, + { + "title": "Performing a POST request to the REST API", + "description": "Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email", + "tabs": [ { - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = admin.rest.post({\n path: \"customers/7392136888625/send_invite.json\",\n body: {\n customer_invite: {\n to: \"new_test_email@shopify.com\",\n from: \"j.limited@example.com\",\n bcc: [\"j.limited@example.com\"],\n subject: \"Welcome to my new shop\",\n custom_message: \"My awesome new store\",\n },\n },\n});\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] } @@ -3154,7 +3228,7 @@ ] } ], - "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.` to make custom requests to the API.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" + "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource. \n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n * @example\n * Performing a POST request to the REST API.\n * Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = admin.rest.post({\n * path: \"customers/7392136888625/send_invite.json\",\n * body: {\n * customer_invite: {\n * to: \"new_test_email@shopify.com\",\n * from: \"j.limited@example.com\",\n * bcc: [\"j.limited@example.com\"],\n * subject: \"Welcome to my new shop\",\n * custom_message: \"My awesome new store\",\n * },\n * },\n * });\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" }, "RestClientWithResources": { "filePath": "/server/clients/admin/rest.ts", @@ -3188,36 +3262,54 @@ "title": "rest", "examples": [ { - "description": "Getting the number of orders in a store using REST resources.", + "description": "Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource.", "codeblock": { "title": "Using REST resources", "tabs": [ { - "title": "/app/shopify.server.ts", - "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/routes/**\\/*.ts", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", "language": "typescript" }, { - "title": "/app/routes/**\\/*.ts", - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", + "title": "/app/shopify.server.ts", + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "language": "typescript" } ] } }, { - "description": "Use `admin.rest.` to make custom requests to the API.", + "description": "Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint", "codeblock": { "title": "Performing a GET request to the REST API", "tabs": [ + { + "title": "/app/routes/**\\/*.ts", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "language": "typescript" + }, { "title": "/app/shopify.server.ts", "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "language": "typescript" - }, + } + ] + } + }, + { + "description": "Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email", + "codeblock": { + "title": "Performing a POST request to the REST API", + "tabs": [ { "title": "/app/routes/**\\/*.ts", - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = admin.rest.post({\n path: \"customers/7392136888625/send_invite.json\",\n body: {\n customer_invite: {\n to: \"new_test_email@shopify.com\",\n from: \"j.limited@example.com\",\n bcc: [\"j.limited@example.com\"],\n subject: \"Welcome to my new shop\",\n custom_message: \"My awesome new store\",\n },\n },\n});\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "language": "typescript" + }, + { + "title": "/app/shopify.server.ts", + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "language": "typescript" } ] @@ -3357,7 +3449,7 @@ "name": "ShopifyApp>", "value": "ShopifyApp>" }, - "value": "export function shopifyApp<\n Config extends AppConfigArg,\n Resources extends ShopifyRestResources,\n Storage extends SessionStorage,\n>(appConfig: Config): ShopifyApp {\n const api = deriveApi(appConfig);\n const config = deriveConfig(appConfig, api.config);\n const logger = overrideLogger(api.logger);\n\n if (appConfig.webhooks) {\n api.webhooks.addHandlers(appConfig.webhooks);\n }\n\n const params: BasicParams = {api, config, logger};\n const oauth = new AuthStrategy(params);\n\n const shopify:\n | AdminApp\n | AppStoreApp\n | SingleMerchantApp = {\n sessionStorage: config.sessionStorage,\n addDocumentResponseHeaders: addDocumentResponseHeadersFactory(params),\n registerWebhooks: registerWebhooksFactory(params),\n authenticate: {\n admin: oauth.authenticateAdmin.bind(oauth),\n public: authenticatePublicFactory(params),\n webhook: authenticateWebhookFactory<\n Config['future'],\n Resources,\n keyof Config['webhooks'] | MandatoryTopics\n >(params),\n },\n unauthenticated: {\n admin: unauthenticatedAdminContextFactory(params),\n storefront: unauthenticatedStorefrontContextFactory(params),\n },\n };\n\n if (\n isAppStoreApp(shopify, appConfig) ||\n isSingleMerchantApp(shopify, appConfig)\n ) {\n shopify.login = loginFactory(params);\n }\n\n return shopify as ShopifyApp;\n}", + "value": "export function shopifyApp<\n Config extends AppConfigArg,\n Resources extends ShopifyRestResources,\n Storage extends SessionStorage,\n>(appConfig: Config): ShopifyApp {\n const api = deriveApi(appConfig);\n const config = deriveConfig(appConfig, api.config);\n const logger = overrideLogger(api.logger);\n\n if (appConfig.webhooks) {\n api.webhooks.addHandlers(appConfig.webhooks);\n }\n\n const params: BasicParams = {api, config, logger};\n const oauth = new AuthCodeFlowStrategy(params);\n const authStrategy = authStrategyFactory({\n ...params,\n strategy: oauth,\n });\n\n const shopify:\n | AdminApp\n | AppStoreApp\n | SingleMerchantApp = {\n sessionStorage: config.sessionStorage,\n addDocumentResponseHeaders: addDocumentResponseHeadersFactory(params),\n registerWebhooks: registerWebhooksFactory(params),\n authenticate: {\n admin: authStrategy,\n public: authenticatePublicFactory(params),\n webhook: authenticateWebhookFactory<\n Config['future'],\n Resources,\n keyof Config['webhooks'] | MandatoryTopics\n >(params),\n },\n unauthenticated: {\n admin: unauthenticatedAdminContextFactory(params),\n storefront: unauthenticatedStorefrontContextFactory(params),\n },\n };\n\n if (\n isAppStoreApp(shopify, appConfig) ||\n isSingleMerchantApp(shopify, appConfig)\n ) {\n shopify.login = loginFactory(params);\n }\n\n return shopify as ShopifyApp;\n}", "examples": [ { "title": "The minimum viable configuration", @@ -3685,29 +3777,43 @@ "examples": [ { "title": "Using REST resources", - "description": "Getting the number of orders in a store using REST resources.", + "description": "Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource.", "tabs": [ - { - "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", - "title": "/app/shopify.server.ts" - }, { "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] }, { "title": "Performing a GET request to the REST API", - "description": "Use `admin.rest.` to make custom requests to the API.", + "description": "Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint", "tabs": [ + { + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "title": "/app/routes/**\\/*.ts" + }, { "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "title": "/app/shopify.server.ts" - }, + } + ] + }, + { + "title": "Performing a POST request to the REST API", + "description": "Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email", + "tabs": [ { - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = admin.rest.post({\n path: \"customers/7392136888625/send_invite.json\",\n body: {\n customer_invite: {\n to: \"new_test_email@shopify.com\",\n from: \"j.limited@example.com\",\n bcc: [\"j.limited@example.com\"],\n subject: \"Welcome to my new shop\",\n custom_message: \"My awesome new store\",\n },\n },\n});\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] } @@ -3733,7 +3839,7 @@ ] } ], - "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.` to make custom requests to the API.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" + "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource. \n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n * @example\n * Performing a POST request to the REST API.\n * Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = admin.rest.post({\n * path: \"customers/7392136888625/send_invite.json\",\n * body: {\n * customer_invite: {\n * to: \"new_test_email@shopify.com\",\n * from: \"j.limited@example.com\",\n * bcc: [\"j.limited@example.com\"],\n * subject: \"Welcome to my new shop\",\n * custom_message: \"My awesome new store\",\n * },\n * },\n * });\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" }, "RestClientWithResources": { "filePath": "/server/clients/admin/rest.ts", @@ -3862,8 +3968,8 @@ "description": "Register webhook topics for a store using the given session. Most likely you want to use this in combination with the afterAuth hook.", "examples": [ { - "title": "Registering webhooks", - "description": "Trigger the registration after a merchant installs your app using the `afterAuth` hook.", + "title": "Registering webhooks after install", + "description": "Trigger the registration to create the webhook subscriptions after a merchant installs your app using the `afterAuth` hook. Learn more about [subscribing to webhooks.](/docs/api/shopify-app-remix/v1/guide-webhooks)", "tabs": [ { "code": "import { DeliveryMethod, shopifyApp } from \"@shopify/shopify-app-remix/server\";\n\nconst shopify = shopifyApp({\n hooks: {\n afterAuth: async ({ session }) => {\n shopify.registerWebhooks({ session });\n }\n },\n webhooks: {\n APP_UNINSTALLED: {\n deliveryMethod: DeliveryMethod.Http,\n callbackUrl: \"/webhooks\",\n },\n },\n // ...etc\n});", @@ -4181,7 +4287,7 @@ "examples": [ { "title": "Requesting billing right away", - "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to Shopify page to request payment.", + "description": "Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.", "tabs": [ { "code": "import { LoaderFunctionArgs } from \"@remix-run/node\";\nimport { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { billing } = await authenticate.admin(request);\n await billing.require({\n plans: [MONTHLY_PLAN],\n isTest: true,\n onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n });\n\n // App logic\n};", @@ -4256,7 +4362,7 @@ ] } ], - "value": "export interface BillingContext {\n /**\n * Checks if the shop has an active payment for any plan defined in the `billing` config option.\n *\n * @returns A promise that resolves to an object containing the active purchases for the shop.\n *\n * @example\n * Requesting billing right away.\n * Call `billing.request` in the `onFailure` callback to immediately redirect to Shopify page to request payment.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * isTest: true,\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * @example\n * Using a plan selection page.\n * When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, redirect } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN, ANNUAL_PLAN],\n * isTest: true,\n * onFailure: () => redirect('/select-plan'),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * console.log(`Shop is on ${subscription.name} (id ${subscription.id})`);\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n require: (\n options: RequireBillingOptions,\n ) => Promise;\n\n /**\n * Requests payment for the plan.\n *\n * @returns Redirects to the confirmation URL for the payment.\n *\n * @example\n * Using a custom return URL.\n * Change where the merchant is returned to after approving the purchase using the `returnUrl` option.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({\n * plan: MONTHLY_PLAN,\n * isTest: true,\n * returnUrl: '/billing-complete',\n * }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n request: (options: RequestBillingOptions) => Promise;\n\n /**\n * Cancels an ongoing subscription, given its ID.\n *\n * @returns The cancelled subscription.\n *\n * @example\n * Cancelling a subscription.\n * Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`.\n * ```ts\n * // /app/routes/cancel-subscription.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * const cancelledSubscription = await billing.cancel({\n * subscriptionId: subscription.id,\n * isTest: true,\n * prorate: true,\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n cancel: (options: CancelBillingOptions) => Promise;\n}" + "value": "export interface BillingContext {\n /**\n * Checks if the shop has an active payment for any plan defined in the `billing` config option.\n *\n * @returns A promise that resolves to an object containing the active purchases for the shop.\n *\n * @example\n * Requesting billing right away.\n * Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * isTest: true,\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * @example\n * Using a plan selection page.\n * When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, redirect } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN, ANNUAL_PLAN],\n * isTest: true,\n * onFailure: () => redirect('/select-plan'),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * console.log(`Shop is on ${subscription.name} (id ${subscription.id})`);\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n require: (\n options: RequireBillingOptions,\n ) => Promise;\n\n /**\n * Requests payment for the plan.\n *\n * @returns Redirects to the confirmation URL for the payment.\n *\n * @example\n * Using a custom return URL.\n * Change where the merchant is returned to after approving the purchase using the `returnUrl` option.\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({\n * plan: MONTHLY_PLAN,\n * isTest: true,\n * returnUrl: '/billing-complete',\n * }),\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n request: (options: RequestBillingOptions) => Promise;\n\n /**\n * Cancels an ongoing subscription, given its ID.\n *\n * @returns The cancelled subscription.\n *\n * @example\n * Cancelling a subscription.\n * Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`.\n * ```ts\n * // /app/routes/cancel-subscription.ts\n * import { LoaderFunctionArgs } from \"@remix-run/node\";\n * import { authenticate, MONTHLY_PLAN } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { billing } = await authenticate.admin(request);\n * const billingCheck = await billing.require({\n * plans: [MONTHLY_PLAN],\n * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),\n * });\n *\n * const subscription = billingCheck.appSubscriptions[0];\n * const cancelledSubscription = await billing.cancel({\n * subscriptionId: subscription.id,\n * isTest: true,\n * prorate: true,\n * });\n *\n * // App logic\n * };\n * ```\n * ```ts\n * // shopify.server.ts\n * import { shopifyApp, BillingInterval } from \"@shopify/shopify-app-remix/server\";\n *\n * export const MONTHLY_PLAN = 'Monthly subscription';\n * export const ANNUAL_PLAN = 'Annual subscription';\n *\n * const shopify = shopifyApp({\n * // ...etc\n * billing: {\n * [MONTHLY_PLAN]: {\n * amount: 5,\n * currencyCode: 'USD',\n * interval: BillingInterval.Every30Days,\n * },\n * [ANNUAL_PLAN]: {\n * amount: 50,\n * currencyCode: 'USD',\n * interval: BillingInterval.Annual,\n * },\n * }\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n cancel: (options: CancelBillingOptions) => Promise;\n}" }, "RequireBillingOptions": { "filePath": "/server/authenticate/admin/billing/types.ts", @@ -5302,14 +5408,14 @@ { "filePath": "/server/types.ts", "syntaxKind": "MethodSignature", - "name": "__@iterator@579", + "name": "__@iterator@629", "value": "() => IterableIterator", "description": "Iterator" }, { "filePath": "/server/types.ts", "syntaxKind": "MethodSignature", - "name": "__@unscopables@581", + "name": "__@unscopables@631", "value": "() => { copyWithin: boolean; entries: boolean; fill: boolean; find: boolean; findIndex: boolean; keys: boolean; values: boolean; }", "description": "Returns an object whose properties have the value 'true'\r\nwhen they will be absent when used in a 'with' statement." }, @@ -5718,8 +5824,8 @@ "description": "Register webhook topics for a store using the given session. Most likely you want to use this in combination with the afterAuth hook.", "examples": [ { - "title": "Registering webhooks", - "description": "Trigger the registration after a merchant installs your app using the `afterAuth` hook.", + "title": "Registering webhooks after install", + "description": "Trigger the registration to create the webhook subscriptions after a merchant installs your app using the `afterAuth` hook. Learn more about [subscribing to webhooks.](/docs/api/shopify-app-remix/v1/guide-webhooks)", "tabs": [ { "code": "import { DeliveryMethod, shopifyApp } from \"@shopify/shopify-app-remix/server\";\n\nconst shopify = shopifyApp({\n hooks: {\n afterAuth: async ({ session }) => {\n shopify.registerWebhooks({ session });\n }\n },\n webhooks: {\n APP_UNINSTALLED: {\n deliveryMethod: DeliveryMethod.Http,\n callbackUrl: \"/webhooks\",\n },\n },\n // ...etc\n});", @@ -5776,7 +5882,7 @@ ] } ], - "value": "export interface ShopifyAppBase {\n /**\n * The `SessionStorage` instance you passed in as a config option.\n *\n * @example\n * Storing sessions with Prisma.\n * Import the `@shopify/shopify-app-session-storage-prisma` package to store sessions in your Prisma database.\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { PrismaSessionStorage } from \"@shopify/shopify-app-session-storage-prisma\";\n * import prisma from \"~/db.server\";\n *\n * const shopify = shopifyApp({\n * sesssionStorage: new PrismaSessionStorage(prisma),\n * // ...etc\n * })\n *\n * // shopify.sessionStorage is an instance of PrismaSessionStorage\n * ```\n */\n sessionStorage: SessionStorageType;\n\n /**\n * Adds the required Content Security Policy headers for Shopify apps to the given Headers object.\n *\n * {@link https://shopify.dev/docs/apps/store/security/iframe-protection}\n *\n * @example\n * Return headers on all requests.\n * Add headers to all HTML requests by calling `shopify.addDocumentResponseHeaders` in `entry.server.tsx`.\n *\n * ```\n * // ~/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n *\n * const shopify = shopifyApp({\n * // ...etc\n * });\n * export default shopify;\n * export const addDocumentResponseheaders = shopify.addDocumentResponseheaders;\n * ```\n *\n * ```ts\n * // entry.server.tsx\n * import { addDocumentResponseHeaders } from \"~/shopify.server\";\n *\n * export default function handleRequest(\n * request: Request,\n * responseStatusCode: number,\n * responseHeaders: Headers,\n * remixContext: EntryContext\n * ) {\n * const markup = renderToString(\n * \n * );\n *\n * responseHeaders.set(\"Content-Type\", \"text/html\");\n * addDocumentResponseHeaders(request, responseHeaders);\n *\n * return new Response(\"\" + markup, {\n * status: responseStatusCode,\n * headers: responseHeaders,\n * });\n * }\n * ```\n */\n addDocumentResponseHeaders: AddDocumentResponseHeaders;\n\n /**\n * Register webhook topics for a store using the given session. Most likely you want to use this in combination with the afterAuth hook.\n *\n * @example\n * Registering webhooks.\n * Trigger the registration after a merchant installs your app using the `afterAuth` hook.\n * ```ts\n * import { DeliveryMethod, shopifyApp } from \"@shopify/shopify-app-remix/server\";\n *\n * const shopify = shopifyApp({\n * hooks: {\n * afterAuth: async ({ session }) => {\n * shopify.registerWebhooks({ session });\n * }\n * },\n * webhooks: {\n * APP_UNINSTALLED: {\n * deliveryMethod: DeliveryMethod.Http,\n * callbackUrl: \"/webhooks\",\n * },\n * },\n * // ...etc\n * });\n * ```\n */\n registerWebhooks: RegisterWebhooks;\n\n /**\n * Ways to authenticate requests from different surfaces across Shopify.\n *\n * @example\n * Authenticate Shopify requests.\n * Use the functions in `authenticate` to validate requests coming from Shopify.\n * ```ts\n * // /app/shopify.server.ts\n * import { LATEST_API_VERSION, shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * ```\n * ```ts\n * // /app/routes/**\\/*.jsx\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import shopify from \"../../shopify.server\";\n *\n * export async function loader({ request }: LoaderFunctionArgs) {\n * const {admin, session, sessionToken, billing} = shopify.authenticate.admin(request);\n *\n * return json(await admin.rest.resources.Product.count({ session }));\n * }\n * ```\n */\n authenticate: Authenticate;\n\n /**\n * Ways to get Contexts from requests that do not originate from Shopify.\n *\n * @example\n * Using unauthenticated contexts.\n * Create contexts for requests that don't come from Shopify.\n * ```ts\n * // /app/shopify.server.ts\n * import { LATEST_API_VERSION, shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * ```\n * ```ts\n * // /app/routes/**\\/*.jsx\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticateExternal } from \"~/helpers/authenticate\"\n * import shopify from \"../../shopify.server\";\n *\n * export async function loader({ request }: LoaderFunctionArgs) {\n * const shop = await authenticateExternal(request)\n * const {admin} = await shopify.unauthenticated.admin(shop);\n *\n * return json(await admin.rest.resources.Product.count({ session }));\n * }\n * ```\n */\n unauthenticated: Unauthenticated>;\n}" + "value": "export interface ShopifyAppBase {\n /**\n * The `SessionStorage` instance you passed in as a config option.\n *\n * @example\n * Storing sessions with Prisma.\n * Import the `@shopify/shopify-app-session-storage-prisma` package to store sessions in your Prisma database.\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { PrismaSessionStorage } from \"@shopify/shopify-app-session-storage-prisma\";\n * import prisma from \"~/db.server\";\n *\n * const shopify = shopifyApp({\n * sesssionStorage: new PrismaSessionStorage(prisma),\n * // ...etc\n * })\n *\n * // shopify.sessionStorage is an instance of PrismaSessionStorage\n * ```\n */\n sessionStorage: SessionStorageType;\n\n /**\n * Adds the required Content Security Policy headers for Shopify apps to the given Headers object.\n *\n * {@link https://shopify.dev/docs/apps/store/security/iframe-protection}\n *\n * @example\n * Return headers on all requests.\n * Add headers to all HTML requests by calling `shopify.addDocumentResponseHeaders` in `entry.server.tsx`.\n *\n * ```\n * // ~/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n *\n * const shopify = shopifyApp({\n * // ...etc\n * });\n * export default shopify;\n * export const addDocumentResponseheaders = shopify.addDocumentResponseheaders;\n * ```\n *\n * ```ts\n * // entry.server.tsx\n * import { addDocumentResponseHeaders } from \"~/shopify.server\";\n *\n * export default function handleRequest(\n * request: Request,\n * responseStatusCode: number,\n * responseHeaders: Headers,\n * remixContext: EntryContext\n * ) {\n * const markup = renderToString(\n * \n * );\n *\n * responseHeaders.set(\"Content-Type\", \"text/html\");\n * addDocumentResponseHeaders(request, responseHeaders);\n *\n * return new Response(\"\" + markup, {\n * status: responseStatusCode,\n * headers: responseHeaders,\n * });\n * }\n * ```\n */\n addDocumentResponseHeaders: AddDocumentResponseHeaders;\n\n /**\n * Register webhook topics for a store using the given session. Most likely you want to use this in combination with the afterAuth hook.\n *\n * @example\n * Registering webhooks after install\n * Trigger the registration to create the webhook subscriptions after a merchant installs your app using the `afterAuth` hook. Learn more about [subscribing to webhooks.](/docs/api/shopify-app-remix/v1/guide-webhooks)\n * ```ts\n * import { DeliveryMethod, shopifyApp } from \"@shopify/shopify-app-remix/server\";\n *\n * const shopify = shopifyApp({\n * hooks: {\n * afterAuth: async ({ session }) => {\n * shopify.registerWebhooks({ session });\n * }\n * },\n * webhooks: {\n * APP_UNINSTALLED: {\n * deliveryMethod: DeliveryMethod.Http,\n * callbackUrl: \"/webhooks\",\n * },\n * },\n * // ...etc\n * });\n * ```\n */\n registerWebhooks: RegisterWebhooks;\n\n /**\n * Ways to authenticate requests from different surfaces across Shopify.\n *\n * @example\n * Authenticate Shopify requests.\n * Use the functions in `authenticate` to validate requests coming from Shopify.\n * ```ts\n * // /app/shopify.server.ts\n * import { LATEST_API_VERSION, shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * ```\n * ```ts\n * // /app/routes/**\\/*.jsx\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import shopify from \"../../shopify.server\";\n *\n * export async function loader({ request }: LoaderFunctionArgs) {\n * const {admin, session, sessionToken, billing} = shopify.authenticate.admin(request);\n *\n * return json(await admin.rest.resources.Product.count({ session }));\n * }\n * ```\n */\n authenticate: Authenticate;\n\n /**\n * Ways to get Contexts from requests that do not originate from Shopify.\n *\n * @example\n * Using unauthenticated contexts.\n * Create contexts for requests that don't come from Shopify.\n * ```ts\n * // /app/shopify.server.ts\n * import { LATEST_API_VERSION, shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * ```\n * ```ts\n * // /app/routes/**\\/*.jsx\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticateExternal } from \"~/helpers/authenticate\"\n * import shopify from \"../../shopify.server\";\n *\n * export async function loader({ request }: LoaderFunctionArgs) {\n * const shop = await authenticateExternal(request)\n * const {admin} = await shopify.unauthenticated.admin(shop);\n *\n * return json(await admin.rest.resources.Product.count({ session }));\n * }\n * ```\n */\n unauthenticated: Unauthenticated>;\n}" }, "ShopifyAppLogin": { "filePath": "/server/types.ts", @@ -5984,9 +6090,9 @@ "title": "registerWebhooks", "examples": [ { - "description": "Trigger the registration after a merchant installs your app using the `afterAuth` hook.", + "description": "Trigger the registration to create the webhook subscriptions after a merchant installs your app using the `afterAuth` hook. Learn more about [subscribing to webhooks.](/docs/api/shopify-app-remix/v1/guide-webhooks)", "codeblock": { - "title": "Registering webhooks", + "title": "Registering webhooks after install", "tabs": [ { "title": "Example", @@ -6150,29 +6256,43 @@ "examples": [ { "title": "Using REST resources", - "description": "Getting the number of orders in a store using REST resources.", + "description": "Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource.", "tabs": [ - { - "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", - "title": "/app/shopify.server.ts" - }, { "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] }, { "title": "Performing a GET request to the REST API", - "description": "Use `admin.rest.` to make custom requests to the API.", + "description": "Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint", "tabs": [ + { + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "title": "/app/routes/**\\/*.ts" + }, { "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "title": "/app/shopify.server.ts" - }, + } + ] + }, + { + "title": "Performing a POST request to the REST API", + "description": "Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email", + "tabs": [ { - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = admin.rest.post({\n path: \"customers/7392136888625/send_invite.json\",\n body: {\n customer_invite: {\n to: \"new_test_email@shopify.com\",\n from: \"j.limited@example.com\",\n bcc: [\"j.limited@example.com\"],\n subject: \"Welcome to my new shop\",\n custom_message: \"My awesome new store\",\n },\n },\n});\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", "title": "/app/routes/**\\/*.ts" + }, + { + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/shopify.server.ts" } ] } @@ -6198,7 +6318,7 @@ ] } ], - "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.` to make custom requests to the API.\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" + "value": "export interface AdminApiContext<\n Resources extends ShopifyRestResources = ShopifyRestResources,\n> {\n /**\n * Methods for interacting with the Shopify Admin REST API\n *\n * 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.\n *\n * {@link https://shopify.dev/docs/api/admin-rest}\n *\n * @example\n * Using REST resources.\n * Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource. \n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * return json(admin.rest.resources.Order.count({ session }));\n * };\n * ```\n *\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n *\n *\n * @example\n * Performing a GET request to the REST API.\n * Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint\n *\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n * @example\n * Performing a POST request to the REST API.\n * Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email\n * ```ts\n * // /app/routes/**\\/*.ts\n * import { LoaderFunctionArgs, json } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export const loader = async ({ request }: LoaderFunctionArgs) => {\n * const { admin, session } = await authenticate.admin(request);\n * const response = admin.rest.post({\n * path: \"customers/7392136888625/send_invite.json\",\n * body: {\n * customer_invite: {\n * to: \"new_test_email@shopify.com\",\n * from: \"j.limited@example.com\",\n * bcc: [\"j.limited@example.com\"],\n * subject: \"Welcome to my new shop\",\n * custom_message: \"My awesome new store\",\n * },\n * },\n * });\n * const response = await admin.rest.get({ path: \"/customers/count.json\" });\n * const customers = await response.json();\n * return json({ customers });\n * };\n * ```\n *\n * ```ts\n * // /app/shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n * import { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n *\n * const shopify = shopifyApp({\n * restResources,\n * // ...etc\n * });\n * export default shopify;\n * export const authenticate = shopify.authenticate;\n * ```\n */\n rest: RestClientWithResources;\n\n /**\n * Methods for interacting with the Shopify Admin GraphQL API\n *\n * {@link https://shopify.dev/docs/api/admin-graphql}\n * {@link https://github.com/Shopify/shopify-api-js/blob/main/packages/shopify-api/docs/reference/clients/Graphql.md}\n *\n * @example\n * Querying the GraphQL API.\n * Use `admin.graphql` to make query / mutation requests.\n * ```ts\n * import { ActionFunctionArgs } from \"@remix-run/node\";\n * import { authenticate } from \"../shopify.server\";\n *\n * export async function action({ request }: ActionFunctionArgs) {\n * const { admin } = await authenticate.admin(request);\n *\n * const response = await admin.graphql(\n * `#graphql\n * mutation populateProduct($input: ProductInput!) {\n * productCreate(input: $input) {\n * product {\n * id\n * }\n * }\n * }`,\n * { variables: { input: { title: \"Product Name\" } } }\n * );\n *\n * const productData = await response.json();\n * return json({ data: productData.data });\n * }\n * ```\n */\n graphql: GraphQLClient;\n}" }, "RestClientWithResources": { "filePath": "/server/clients/admin/rest.ts", @@ -6246,36 +6366,54 @@ "title": "rest", "examples": [ { - "description": "Getting the number of orders in a store using REST resources.", + "description": "Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource.", "codeblock": { "title": "Using REST resources", "tabs": [ { - "title": "/app/shopify.server.ts", - "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", + "title": "/app/routes/**\\/*.ts", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", "language": "typescript" }, { - "title": "/app/routes/**\\/*.ts", - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n return json(admin.rest.resources.Order.count({ session }));\n};", + "title": "/app/shopify.server.ts", + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-07\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "language": "typescript" } ] } }, { - "description": "Use `admin.rest.` to make custom requests to the API.", + "description": "Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint", "codeblock": { "title": "Performing a GET request to the REST API", "tabs": [ + { + "title": "/app/routes/**\\/*.ts", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "language": "typescript" + }, { "title": "/app/shopify.server.ts", "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "language": "typescript" - }, + } + ] + } + }, + { + "description": "Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email", + "codeblock": { + "title": "Performing a POST request to the REST API", + "tabs": [ { "title": "/app/routes/**\\/*.ts", - "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "code": "import { LoaderFunctionArgs, json } from \"@remix-run/node\";\nimport { authenticate } from \"../shopify.server\";\n\nexport const loader = async ({ request }: LoaderFunctionArgs) => {\n const { admin, session } = await authenticate.admin(request);\n const response = admin.rest.post({\n path: \"customers/7392136888625/send_invite.json\",\n body: {\n customer_invite: {\n to: \"new_test_email@shopify.com\",\n from: \"j.limited@example.com\",\n bcc: [\"j.limited@example.com\"],\n subject: \"Welcome to my new shop\",\n custom_message: \"My awesome new store\",\n },\n },\n});\n const response = await admin.rest.get({ path: \"/customers/count.json\" });\n const customers = await response.json();\n return json({ customers });\n};", + "language": "typescript" + }, + { + "title": "/app/shopify.server.ts", + "code": "import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\nimport { restResources } from \"@shopify/shopify-api/rest/admin/2023-04\";\n\nconst shopify = shopifyApp({\n restResources,\n // ...etc\n});\nexport default shopify;\nexport const authenticate = shopify.authenticate;", "language": "typescript" } ] diff --git a/packages/shopify-app-remix/docs/generated/generated_static_pages.json b/packages/shopify-app-remix/docs/generated/generated_static_pages.json index 5e5ce43d77..0a5cf3a77f 100644 --- a/packages/shopify-app-remix/docs/generated/generated_static_pages.json +++ b/packages/shopify-app-remix/docs/generated/generated_static_pages.json @@ -342,8 +342,8 @@ { "type": "Generic", "anchorLink": "config", - "title": "Configuring webhooks", - "sectionContent": "To set up webhooks first we need to configure `shopifyApp` with 2 pieces:\n1. The webhooks you want to subscribe to. In this example we subscribe to the `APP_UNINSTALLED` topic.\n1. The code to register the `APP_UNINSTALLED` topic after a merchant installs you app. Here `shopifyApp` provides an `afterAuth` hook.\n\n> Note: You can't register mandatory topics using this package, you must [configure those in the Partner Dashboard](/docs/apps/webhooks/configuration/mandatory-webhooks) instead.", + "title": "Configuring webhooks subscriptions", + "sectionContent": "Configure `shopifyApp` and setup webhook subscription with the following steps:\n1. The webhooks you want to subscribe to. In this example we subscribe to the `APP_UNINSTALLED` topic.\n1. The code to register the `APP_UNINSTALLED` topic after a merchant installs you app. Here `shopifyApp` provides an `afterAuth` hook.\n1. Review the required scopes for the webhook topics, and update your [app scopes](/docs/apps/tools/cli/configuration#access_scopes) as necessary.\n\n> Note: You can't register mandatory topics using this package, you must [configure those in the Partner Dashboard](/docs/apps/webhooks/configuration/mandatory-webhooks) instead.", "codeblock": { "title": "/app/shopify.server.ts", "tabs": [ @@ -359,7 +359,7 @@ "type": "Generic", "anchorLink": "endpoints", "title": "Set up your endpoints", - "sectionContent": "Legitimate webhook requests are always `POST`s signed by Shopify, so you must authenticate them before taking any action.\n\nFor each `callbackUrl` in your configuration, you must set up an `action` that uses the `authenticate.webhook` function to authenticate the request.\n\nPlease keep in mind that webhook endpoints should respond as quickly as possible. If you need to run a long-running job, then consider using background tasks.\n\n> Caution: Webhook endpoints **must** respond with an `HTTP 200` code, or Shopify will retry.", + "sectionContent": "Create a route in your app to handle incoming webhook requests for each `callbackUrl` you set in your configuration.Legitimate webhook requests are always `POST` requests signed by Shopify, so you must authenticate them before taking any action. To do this you must set up an `action` that uses the `authenticate.webhook` function to authenticate the request.\n\nPlease keep in mind that webhook endpoints should respond as quickly as possible. If you need to run a long-running job, then consider using background tasks.\n\n> Caution: Webhook endpoints **must** respond with an `HTTP 200` code, or Shopify will retry.", "codeblock": { "title": "/app/routes/webhooks.tsx", "tabs": [ diff --git a/packages/shopify-app-remix/src/server/clients/admin/types.ts b/packages/shopify-app-remix/src/server/clients/admin/types.ts index 01e6c2c1bc..db8571c72c 100644 --- a/packages/shopify-app-remix/src/server/clients/admin/types.ts +++ b/packages/shopify-app-remix/src/server/clients/admin/types.ts @@ -29,7 +29,19 @@ export interface AdminApiContext< * * @example * Using REST resources. - * Getting the number of orders in a store using REST resources. + * Getting the number of orders in a store using REST resources. Visit the [Admin REST API references](/docs/api/admin-rest) for examples on using each resource. + * + * ```ts + * // /app/routes/**\/*.ts + * import { LoaderFunctionArgs, json } from "@remix-run/node"; + * import { authenticate } from "../shopify.server"; + * + * export const loader = async ({ request }: LoaderFunctionArgs) => { + * const { admin, session } = await authenticate.admin(request); + * return json(admin.rest.resources.Order.count({ session })); + * }; + * ``` + * * * ```ts * // /app/shopify.server.ts @@ -44,6 +56,11 @@ export interface AdminApiContext< * export const authenticate = shopify.authenticate; * ``` * + * + * @example + * Performing a GET request to the REST API. + * Use `admin.rest.get` to make custom requests to make a request to to the `customer/count` endpoint + * * ```ts * // /app/routes/**\/*.ts * import { LoaderFunctionArgs, json } from "@remix-run/node"; @@ -51,14 +68,12 @@ export interface AdminApiContext< * * export const loader = async ({ request }: LoaderFunctionArgs) => { * const { admin, session } = await authenticate.admin(request); - * return json(admin.rest.resources.Order.count({ session })); + * const response = await admin.rest.get({ path: "/customers/count.json" }); + * const customers = await response.json(); + * return json({ customers }); * }; * ``` * - * @example - * Performing a GET request to the REST API. - * Use `admin.rest.` to make custom requests to the API. - * * ```ts * // /app/shopify.server.ts * import { shopifyApp } from "@shopify/shopify-app-remix/server"; @@ -71,7 +86,9 @@ export interface AdminApiContext< * export default shopify; * export const authenticate = shopify.authenticate; * ``` - * + * @example + * Performing a POST request to the REST API. + * Use `admin.rest.post` to make custom requests to make a request to to the `customers.json` endpoint to send a welcome email * ```ts * // /app/routes/**\/*.ts * import { LoaderFunctionArgs, json } from "@remix-run/node"; @@ -79,11 +96,35 @@ export interface AdminApiContext< * * export const loader = async ({ request }: LoaderFunctionArgs) => { * const { admin, session } = await authenticate.admin(request); - * const response = await admin.rest.get({ path: "/customers/count.json" }); - * const customers = await response.json(); - * return json({ customers }); + * const response = admin.rest.post({ + * path: "customers/7392136888625/send_invite.json", + * body: { + * customer_invite: { + * to: "new_test_email@shopify.com", + * from: "j.limited@example.com", + * bcc: ["j.limited@example.com"], + * subject: "Welcome to my new shop", + * custom_message: "My awesome new store", + * }, + * }, + * }); + * const customerInvite = await response.json(); + * return json({ customerInvite }); * }; * ``` + * + * ```ts + * // /app/shopify.server.ts + * import { shopifyApp } from "@shopify/shopify-app-remix/server"; + * import { restResources } from "@shopify/shopify-api/rest/admin/2023-04"; + * + * const shopify = shopifyApp({ + * restResources, + * // ...etc + * }); + * export default shopify; + * export const authenticate = shopify.authenticate; + * ``` */ rest: RestClientWithResources;