### Start Email Development Server Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/modules/email-notifications/README.md Command to start the react-email development server for previewing email templates. It runs on http://localhost:3002. ```bash pnpm email:dev ``` -------------------------------- ### Install Algolia Search Client Dependency Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/storefront/README.md This shell command installs the 'algoliasearch' package, which is a dependency for using Algolia with the Medusa project. It is executed using the yarn package manager. This step is necessary before configuring the Algolia search client. ```shell yarn add algoliasearch ``` -------------------------------- ### Example Response: File Upload Confirmation (JSON) Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Example JSON response received after successfully uploading a file using the Medusa Admin API. It contains the URL and key for the uploaded file, provided by the configured file storage provider. ```json { "uploads": [ { "url": "https://minio.example.com/medusa-files/product-image-01JCGK8P9Z5RNXS0JHVN3QBD2T.jpg", "key": "product-image-01JCGK8P9Z5RNXS0JHVN3QBD2T.jpg" } ] } ``` -------------------------------- ### GET /key-exchange Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Retrieve the publishable API key for initializing the storefront SDK. This key is essential for client-side interactions with the Medusa backend. ```APIDOC ## GET /key-exchange ### Description Retrieves the publishable API key for the storefront, used for initializing the Medusa JS SDK. ### Method GET ### Endpoint `/key-exchange` ### Parameters #### Query Parameters None #### Request Body None ### Request Example ```bash curl -X GET http://localhost:9000/key-exchange ``` ### Response #### Success Response (200) - **publishableApiKey** (string) - The publishable API key. #### Response Example ```json { "publishableApiKey": "pk_abc123xyz..." } ``` ``` -------------------------------- ### Example Usage: Upload Product Image via Admin API (cURL) Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Demonstrates how to upload a product image using cURL to the Medusa Admin API, which automatically utilizes the configured file provider (MinIO in this case). Requires an authorization token and the image file. ```bash // Usage example - Upload product image // Admin API automatically uses the file provider curl -X POST http://localhost:9000/admin/uploads \ -H "Authorization: Bearer ADMIN_TOKEN" \ -F "files=@product-image.jpg" ``` -------------------------------- ### GET /store/products Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt List products from the catalog with options for pagination, regional filtering, and field selection. Supports retrieving associated variants and images. ```APIDOC ## GET /store/products ### Description Retrieves a paginated list of products from the store's catalog. Supports filtering by region and includes options for specifying fields, limits, and offsets. ### Method GET ### Endpoint `/store/products` ### Parameters #### Query Parameters - **region_id** (string) - Required - The ID of the region to filter products by. - **limit** (integer) - Optional - The maximum number of products to return. - **offset** (integer) - Optional - The number of products to skip before starting to collect the result set. - **fields** (string) - Optional - Comma-separated list of fields to include in the response (e.g., `*variants,*images`). #### Request Body None ### Request Example ```bash curl -X GET "http://localhost:9000/store/products?region_id=reg_123&limit=10&offset=0&fields=*variants,*images" ``` ### Response #### Success Response (200) - **products** (array) - An array of product objects. - **id** (string) - The product ID. - **title** (string) - The product title. - **handle** (string) - The product handle. - **description** (string) - The product description. - **status** (string) - The product status (e.g., 'published'). - **images** (array) - An array of product image objects. - **url** (string) - The URL of the image. - **variants** (array) - An array of product variant objects. - **id** (string) - The variant ID. - **title** (string) - The variant title. - **sku** (string) - The variant SKU. - **prices** (array) - An array of price objects for the variant. - **amount** (integer) - The price amount. - **currency_code** (string) - The currency code. - **count** (integer) - The total number of products available. #### Response Example ```json { "products": [ { "id": "prod_01JCGK8P9Z5RNXS0JHVN3QBD2T", "title": "Medusa T-Shirt", "handle": "medusa-t-shirt", "description": "High quality cotton t-shirt", "status": "published", "images": [ { "url": "https://storage.example.com/tshirt.jpg" } ], "variants": [ { "id": "variant_01JCGK8P9Z6S...", "title": "S / Black", "sku": "SHIRT-S-BLACK", "prices": [ { "amount": 1000, "currency_code": "eur" } ] } ] } ], "count": 4 } ``` ``` -------------------------------- ### Create a Basic GET API Route Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/api/README.md Defines a simple GET request handler for a custom API route. It uses Medusa's request and response types and returns a JSON message. Ensure this file is placed in the appropriate subdirectory under /src/api. ```typescript import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa"; export async function GET(req: MedusaRequest, res: MedusaResponse) { res.json({ message: "Hello world!", }); } ``` -------------------------------- ### List collections and categories via MeiliSearch API (cURL) Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Provides example cURL commands to retrieve collections, fetch a specific collection with its products, and list product categories from the MeiliSearch store API. Useful for debugging or scripting data retrieval without a client SDK. Adjust the host and query parameters as needed. ```Bash # List all collections\ncurl -X GET \"http://localhost:9000/store/collections?limit=100\"\n\n# Get collection by handle with products\ncurl -X GET \"http://localhost:9000/store/collections?handle=summer-collection&fields=*products\"\n\n# List categories\ncurl -X GET \"http://localhost:9000/store/categories?limit=100\" ``` -------------------------------- ### GET /store/orders Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Retrieves a paginated list of customer orders with detailed information including items, shipping addresses, and pricing. ```APIDOC ## GET /store/orders ### Description Retrieves a paginated list of customer orders with detailed information including items, shipping addresses, and pricing. ### Method GET ### Endpoint /store/orders ### Parameters #### Query Parameters - **limit** (integer) - Optional - The number of orders to retrieve (default: 10) - **offset** (integer) - Optional - The number of orders to skip (default: 0) ### Request Example No request body required ### Response #### Success Response (200) - **orders** (array) - Array of order objects - **count** (integer) - Total number of orders #### Response Example { "orders": [ { "id": "order_01JCGK8P9Z5RNXS0JHVN3QBD2T", "status": "completed", "display_id": 1001, "email": "customer@example.com", "created_at": "2025-11-10T12:00:00.000Z", "total": 3000, "currency_code": "eur", "items": [ { "id": "item_01JCGK8P9Z5RNXS0JHVN3QBD2T", "title": "Medusa T-Shirt", "variant": { "title": "S / Black", "sku": "SHIRT-S-BLACK" }, "quantity": 2, "unit_price": 1000, "total": 2000 } ], "shipping_address": { "first_name": "Jane", "last_name": "Smith", "address_1": "456 Oak Avenue", "city": "Berlin", "country_code": "de", "postal_code": "10115" } } ], "count": 5 } ``` -------------------------------- ### GET /store/collections Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Retrieve product collections from the storefront. Supports filtering by handle and including product details via query parameters. ```APIDOC ## GET /store/collections ### Description Retrieves a list of product collections from the storefront. Collections are used to group products logically (e.g., Summer Collection, New Arrivals). You can optionally filter by handle to retrieve a specific collection. ### Method GET ### Endpoint /store/collections ### Parameters #### Query Parameters - **limit** (integer) - Optional - Maximum number of collections to return. Defaults to system's default limit. - **handle** (string) - Optional - Filter collections by handle (slug). Returns collections matching the specified handle. - **fields** (string) - Optional - Specify which fields to include in the response. Use "*products" to include product details. ### Request Examples #### List all collections ```bash curl -X GET "http://localhost:9000/store/collections?limit=100" ``` #### Get collection by handle with products ```bash curl -X GET "http://localhost:9000/store/collections?handle=summer-collection&fields=*products" ``` ### Response #### Success Response (200) - **collections** (array) - Array of collection objects - **count** (integer) - Total number of collections #### Response Example ```json { "collections": [ { "id": "pcol_01JCGK8P9Z5RNXS0JHVN3QBD2T", "title": "Summer Collection", "handle": "summer-collection", "metadata": {} } ], "count": 1 } ``` ``` -------------------------------- ### Medusa Configuration for MinIO Provider (JavaScript) Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Configures the file module in MedusaJS to use the custom MinIO file provider. It specifies the necessary MinIO connection details via environment variables. This setup is typically done in 'medusa-config.js'. ```javascript // Configuration in medusa-config.js const modules = { file: { resolve: "./src/modules/minio-file", options: { endpoint: process.env.MINIO_ENDPOINT, bucket: process.env.MINIO_BUCKET || "medusa-files", accessKeyId: process.env.MINIO_ACCESS_KEY, secretAccessKey: process.env.MINIO_SECRET_KEY, useSSL: true, }, }, } ``` -------------------------------- ### List customer orders using cURL Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Retrieves paginated list of customer orders via cURL GET request. Supports limit and offset parameters for pagination. ```bash curl -X GET "http://localhost:9000/store/orders?limit=10&offset=0" \ -H "Authorization: Bearer YOUR_TOKEN" ``` -------------------------------- ### Define Custom Workflow in TypeScript Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/workflows/README.md Defines a custom workflow using the MedusaJS workflows SDK. This example demonstrates creating two steps and composing them into a 'hello-world' workflow that accepts a name input and returns a greeting. ```typescript import { createStep, createWorkflow, StepResponse, } from "@medusajs/workflows-sdk" const step1 = createStep("step-1", async () => { return new StepResponse(`Hello from step one!`); }); type WorkflowInput = { name: string; }; const step2 = createStep( "step-2", async ({ name }: WorkflowInput) => { return new StepResponse(`Hello ${name} from step two!`); } ); type WorkflowOutput = { message: string; }; const myWorkflow = createWorkflow("hello-world", function (input) { const str1 = step1(); // to pass input step2(input); return { message: str1, }; }); export default myWorkflow; ``` -------------------------------- ### GET /store/categories Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Retrieve product categories from the storefront. Categories support hierarchical organization and can include products and parent category details. ```APIDOC ## GET /store/categories ### Description Retrieves a list of product categories from the storefront. Categories support hierarchical organization (parent-child relationships) for products. You can filter by handle and include additional fields like products and parent category details. ### Method GET ### Endpoint /store/categories ### Parameters #### Query Parameters - **limit** (integer) - Optional - Maximum number of categories to return. Defaults to system's default limit. - **handle** (string|array) - Optional - Filter categories by handle. Can be a single handle or array of handles. - **fields** (string) - Optional - Specify which fields to include. Use "*products" for products and "*parent_category" for parent category details ``` -------------------------------- ### Retrieve specific order using cURL Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Fetches detailed information for a specific order by its ID using cURL GET request. Requires order ID and authentication token. ```bash curl -X GET http://localhost:9000/store/orders/order_01JCGK8P9Z5RNXS0JHVN3QBD2T \ -H "Authorization: Bearer YOUR_TOKEN" ``` -------------------------------- ### Custom CLI Script with Arguments (TypeScript) Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/scripts/README.md This example shows how a custom CLI script can accept and utilize arguments passed from the command line. Arguments are accessed via the `args` property within the `ExecArgs` object passed to the script's default exported function. The script logs the received arguments to the console. ```typescript import { ExecArgs } from "@medusajs/types" export default async function myScript ({ args }: ExecArgs) { console.log(`The arguments you passed: ${args}`) } ``` ```bash npx medusa exec ./src/scripts/my-script.ts arg1 arg2 ``` -------------------------------- ### Fetch collections with products using Medusa SDK (TypeScript) Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Exports async cached functions to get a single collection by handle and to retrieve all collections with their products for a given country code. Utilizes the Medusa SDK store.collection endpoint and handles region lookup and error cases. Suitable for server‑side data fetching in Next.js. ```TypeScript import { sdk } from \"@lib/config\"\nimport { cache } from \"react\"\nimport { getRegion } from \"./regions\"\n\nexport const getCollectionByHandle = cache(async function (handle: string) {\n return await sdk.store.collection\n .list({ handle, fields: \"*products\" })\n .then(({ collections }) => collections[0])\n})\n\nexport const getCollectionsWithProducts = cache(async function (\n countryCode: string\n) {\n const region = await getRegion(countryCode)\n\n if (!region) {\n return null\n }\n\n return await sdk.store.collection\n .list(\n {\n fields: \"*products\",\n },\n { next: { tags: [\"collections\"] } }\n )\n .then(({ collections }) => collections)\n .catch(() => {\n return null\n })\n}) ``` -------------------------------- ### Seed MedusaJS Database with Demo Data (TypeScript) Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Initializes the MedusaJS store with demo data including regions, products, inventory, and an API key. This script requires the MedusaJS CLI and is executed using a specific command. ```typescript // File: backend/src/scripts/seed.ts import { seed as seedData } from "@medusajs/medusa/cli/seed" import { Modules } from "@medusajs/framework/utils" export async function seedDemoData({ container }) { const logger = container.resolve("logger") // 1. Setup regions with currencies and countries const regionModule = container.resolve(Modules.REGION) const region = await regionModule.createRegions({ name: "Europe", currency_code: "eur", countries: ["gb", "de", "dk", "se", "fr", "es", "it"], automatic_taxes: true, }) // 2. Create stock location const stockLocationModule = container.resolve(Modules.STOCK_LOCATION) const location = await stockLocationModule.createStockLocations({ name: "European Warehouse", address: { city: "Copenhagen", country_code: "DK", }, }) // 3. Setup shipping options const fulfillmentModule = container.resolve(Modules.FULFILLMENT) const shippingProfile = await fulfillmentModule.createShippingProfiles({ name: "Default", type: "default", }) const fulfillmentSet = await fulfillmentModule.createFulfillmentSets({ name: "Europe Fulfillment", type: "shipping", }) const shippingOption = await fulfillmentModule.createShippingOptions({ name: "Standard Shipping", service_zone_id: fulfillmentSet.service_zones[0].id, shipping_profile_id: shippingProfile.id, provider_id: "manual_fulfillment", price_type: "flat", type: { code: "standard", label: "Standard", description: "5-7 business days", }, prices: [ { currency_code: "eur", amount: 1000, // 10 EUR }, ], }) // 4. Create product categories const productModule = container.resolve(Modules.PRODUCT) const category = await productModule.createProductCategories({ name: "Shirts", handle: "shirts", is_active: true, }) // 5. Create products with variants const product = await productModule.createProducts({ title: "Medusa T-Shirt", handle: "medusa-t-shirt", description: "High quality cotton t-shirt with Medusa logo", status: "published", images: [ { url: "https://medusa-public-images.s3.eu-west-1.amazonaws.com/tee-black-front.png", }, ], options: [ { title: "Size", values: ["S", "M", "L", "XL"] }, { title: "Color", values: ["Black", "White"] }, ], variants: [ { title: "S / Black", sku: "SHIRT-S-BLACK", options: { Size: "S", Color: "Black" }, prices: [ { amount: 1000, currency_code: "eur" }, { amount: 1500, currency_code: "usd" }, ], }, // ... more variants ], categories: [{ id: category.id }], }) // 6. Create inventory levels const inventoryModule = container.resolve(Modules.INVENTORY) for (const variant of product.variants) { await inventoryModule.createInventoryItems({ sku: variant.sku, }) await inventoryModule.createInventoryLevels({ inventory_item_id: variant.inventory_items[0].id, location_id: location.id, stocked_quantity: 1000000, }) } // 7. Create publishable API key for storefront const apiKeyModule = container.resolve(Modules.API_KEY) await apiKeyModule.createApiKeys({ title: "Webshop", type: "publishable", created_by: "seed-script", }) logger.info("✅ Database seeded successfully!") } // Run seed command // bash: pnpm medusa db:seed -f ./src/scripts/seed.ts ``` -------------------------------- ### Customer Authentication using cURL (Bash) Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Demonstrates customer authentication operations via cURL commands. Includes registering a new customer, creating a customer profile, logging in to obtain a JWT token, retrieving the customer profile, and logging out. Requires a running Medusa backend. ```bash # 1. Register new customer curl -X POST http://localhost:9000/auth/customer/emailpass/register \ -H "Content-Type: application/json" \ -d '{ "email": "customer@example.com", "password": "SecurePass123!" }' # 2. Create customer profile curl -X POST http://localhost:9000/store/customers \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_TOKEN" \ -d '{ "email": "customer@example.com", "first_name": "Jane", "last_name": "Smith", "phone": "+4512345678" }' # 3. Login curl -X POST http://localhost:9000/auth/customer/emailpass \ -H "Content-Type: application/json" \ -d '{ "email": "customer@example.com", "password": "SecurePass123!" }' # Response # { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } # 4. Get customer profile curl -X GET http://localhost:9000/store/customers/me \ -H "Authorization: Bearer YOUR_TOKEN" # Response # { "customer": { "id": "cus_01JCGK8P9Z5RNXS0JHVN3QBD2T", "email": "customer@example.com", "first_name": "Jane", "last_name": "Smith", "phone": "+4512345678", "has_account": true } } # 5. Logout curl -X DELETE http://localhost:9000/auth/session \ -H "Authorization: Bearer YOUR_TOKEN" ``` -------------------------------- ### GET /store/orders/{id} Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Retrieves detailed information for a specific order by its ID. Requires authentication. ```APIDOC ## GET /store/orders/{id} ### Description Retrieves detailed information for a specific order by its ID. Requires authentication. ### Method GET ### Endpoint /store/orders/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The ID of the order to retrieve ### Request Example No request body required ### Response #### Success Response (200) Returns a single order object with complete details #### Response Example { "id": "order_01JCGK8P9Z5RNXS0JHVN3QBD2T", "status": "completed", "display_id": 1001, "email": "customer@example.com", "created_at": "2025-11-10T12:00:00.000Z", "total": 3000, "currency_code": "eur", "items": [ { "id": "item_01JCGK8P9Z5RNXS0JHVN3QBD2T", "title": "Medusa T-Shirt", "variant": { "title": "S / Black", "sku": "SHIRT-S-BLACK" }, "quantity": 2, "unit_price": 1000, "total": 2000 } ], "shipping_address": { "first_name": "Jane", "last_name": "Smith", "address_1": "456 Oak Avenue", "city": "Berlin", "country_code": "de", "postal_code": "10115" } } ``` -------------------------------- ### Medusa Configuration for MinIO Module Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/modules/minio-file/README.md Configuration snippet for integrating the MinIO File Provider module into Medusa's configuration file (medusa-config.js). This shows how to resolve the module and pass the necessary options, including endpoint, access keys, and bucket name. ```javascript { resolve: './src/modules/minio-file', options: { endPoint: MINIO_ENDPOINT, accessKey: MINIO_ACCESS_KEY, secretKey: MINIO_SECRET_KEY, bucket: MINIO_BUCKET # Optional, defaults to 'medusa-media' } } ``` -------------------------------- ### POST /indexes/products/search Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Searches for products using MeiliSearch based on title, description, or SKU. Supports filtering and pagination. ```APIDOC ## POST /indexes/products/search ### Description Searches for products using MeiliSearch based on title, description, or SKU. Supports filtering and pagination. ### Method POST ### Endpoint /indexes/products/search ### Parameters #### Request Body - **q** (string) - Optional - Search query string - **limit** (integer) - Optional - Maximum number of results to return - **filter** (string) - Optional - Filter expression ### Request Example { "q": "t-shirt", "limit": 20, "filter": "id EXISTS" } ### Response #### Success Response (200) - **hits** (array) - Array of product objects matching the search - **estimatedTotalHits** (integer) - Estimated total number of matching products #### Response Example { "hits": [ { "id": "prod_01JCGK8P9Z5RNXS0JHVN3QBD2T", "title": "Medusa T-Shirt", "description": "High quality cotton t-shirt", "handle": "medusa-t-shirt", "variant_sku": "SHIRT-S-BLACK", "thumbnail": "https://storage.example.com/tshirt.jpg" } ], "estimatedTotalHits": 1 } ``` -------------------------------- ### Configure Algolia Search Client in TypeScript Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/storefront/README.md This TypeScript code configures the Algolia search client by importing the 'algoliasearch/lite' library. It sets up the application ID, API key, and search index name, retrieving them from environment variables or using default test values. This client is then used to interact with Algolia's search service. ```typescript import algoliasearch from "algoliasearch/lite" const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || "test_app_id" // You should add this to your environment variables const apiKey = process.env.NEXT_PUBLIC_SEARCH_API_KEY || "test_key" export const searchClient = algoliasearch(appId, apiKey) export const SEARCH_INDEX_NAME = process.env.NEXT_PUBLIC_INDEX_NAME || "products" ``` -------------------------------- ### Trigger New Email Template (TypeScript) Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/modules/email-notifications/README.md Example of how to trigger the newly added email template. It shows the call to `createNotifications` with the new template key and the corresponding data payload. ```typescript await notificationModuleService.createNotifications({ to: user.email, channel: 'email', template: EmailTemplates.NEW_TEMPLATE, // or 'new-template' data: { emailOptions: { subject: 'Action Required', replyTo: 'support@example.com', }, greeting: 'Hello there!', actionUrl: `${BACKEND_URL}/take-action?token=${user.token}`, preview: 'An important action is awaiting you...', }, }) ``` -------------------------------- ### MinIO Configuration Environment Variables Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/modules/minio-file/README.md Environment variables required to configure the MinIO File Provider module. These variables specify the MinIO endpoint, access credentials, and the bucket name to be used for storage. The bucket name is optional and defaults to 'medusa-media'. ```env MINIO_ENDPOINT=your-minio-endpoint MINIO_ACCESS_KEY=your-access-key MINIO_SECRET_KEY=your-secret-key MINIO_BUCKET=your-bucket-name # Optional, defaults to 'medusa-media' ``` -------------------------------- ### Customer Authentication with Next.js Server Actions (TypeScript) Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Provides Next.js Server Actions for customer authentication, including signup, login, and signout. It integrates with the Medusa SDK and uses server cookies for managing authentication tokens. The signup process includes registering the user and then logging them in to set the authentication token. ```typescript "use server" import { sdk } from "@lib/config" import { getAuthHeaders, setAuthToken, removeAuthToken } from "@lib/util/server-cookies" import { redirect } from "next/navigation" export async function signup(_currentState, formData) { const password = formData.get("password") as string const customerForm = { email: formData.get("email") as string, first_name: formData.get("first_name") as string, last_name: formData.get("last_name") as string, phone: formData.get("phone") as string, } try { const token = await sdk.auth.register("customer", "emailpass", { email: customerForm.email, password: password, }) const authHeaders = { authorization: `Bearer ${token}` } await sdk.store.customer.create(customerForm, {}, authHeaders) const { token: loginToken } = await sdk.auth.login("customer", "emailpass", { email: customerForm.email, password, }) setAuthToken(loginToken) return { success: true } } catch (error: any) { return error.message } } export async function login(_currentState, formData) { const email = formData.get("email") as string const password = formData.get("password") as string try { const { token } = await sdk.auth.login("customer", "emailpass", { email, password, }) setAuthToken(token) } catch (error: any) { return error.message } } export async function signout(countryCode: string) { await sdk.auth.deleteSession(getAuthHeaders()) removeAuthToken() redirect(`/${countryCode}/account`) } ``` -------------------------------- ### Trigger Email Notification (TypeScript) Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/modules/email-notifications/README.md Example of sending an email notification using a predefined template and data. It specifies the recipient, channel, template key, and data payload including email options and dynamic content. ```typescript await notificationModuleService.createNotifications({ to: invite.email, channel: 'email', template: EmailTemplates.INVITE_USER, // Use the enum for the template key data: { emailOptions: { replyTo: 'info@example.com', subject: "You've been invited!", }, inviteLink: `${BACKEND_URL}/app/invite?token=${invite.token}`, preview: 'Get started with your invitation...', }, }) ``` -------------------------------- ### Configure InstantSearch client with MeiliSearch in Next.js Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Sets up a MeiliSearch instant search client for use in a Next.js application. It reads endpoint, API key, and index name from environment variables, providing defaults for local development. The client is exported for consumption by React InstantSearch components. ```TypeScript import { instantMeiliSearch } from \"@meilisearch/instant-meilisearch\"\n\nexport const searchClient = instantMeiliSearch(\n process.env.NEXT_PUBLIC_SEARCH_ENDPOINT || \"http://127.0.0.1:7700\",\n process.env.NEXT_PUBLIC_SEARCH_API_KEY || \"test_key\",\n {\n primaryKey: \"id\",\n placeholderSearch: false,\n keepZeroFacets: true,\n }\n).searchClient\n\nexport const SEARCH_INDEX_NAME = process.env.NEXT_PUBLIC_INDEX_NAME || \"products\" ``` -------------------------------- ### Execute Workflow in MedusaJS API Route Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/workflows/README.md Demonstrates how to execute a previously defined MedusaJS workflow from within an API route. This example shows how to pass input to the workflow and send the result back in the API response. ```typescript import type { MedusaRequest, MedusaResponse, } from "@medusajs/medusa"; import myWorkflow from "../../../workflows/hello-world"; export async function GET( req: MedusaRequest, res: MedusaResponse ) { const { result } = await myWorkflow(req.scope) .run({ input: { name: req.query.name as string, }, }); res.send(result); } ``` -------------------------------- ### Enable Search Feature Flag in store.config.json Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/storefront/README.md This JSON snippet shows how to enable the search feature flag within the store.config.json file. It requires adding or modifying the 'features' object to set 'search' to true. This is a configuration step for enabling search functionality in the Medusa starter. ```json { "features": { // other features... "search": true } } ``` -------------------------------- ### Search products using MeiliSearch API Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Performs product search via MeiliSearch API with cURL POST request. Supports query string, limit, and filtering options. ```bash curl -X POST http://localhost:7700/indexes/products/search \ -H "Authorization: Bearer YOUR_SEARCH_KEY" \ -H "Content-Type: application/json" \ -d '{ "q": "t-shirt", "limit": 20, "filter": "id EXISTS" }' ``` -------------------------------- ### Retrieve Publishable API Key - Shell & TypeScript Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Retrieves the publishable API key for initializing the Medusa SDK in the Next.js storefront. The endpoint returns a key for client-side authentication without exposing secret credentials. The TypeScript snippet demonstrates SDK configuration with environment variables for backend URL, debug mode, and key integration. ```bash # Get publishable API key for storefront curl -X GET http://localhost:9000/key-exchange # Response { "publishableApiKey": "pk_abc123xyz..." } # Usage in Next.js storefront # File: storefront/src/lib/config.ts ``` ```typescript import Medusa from "@medusajs/js-sdk" const sdk = new Medusa({ baseUrl: process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL || "http://localhost:9000", debug: process.env.NODE_ENV === "development", publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY, }) ``` -------------------------------- ### Access Medusa Container Services in API Routes Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/api/README.md Illustrates how to retrieve and use services from the Medusa container within an API route handler. The container is accessible via `req.scope`. This example fetches the product module service to list and count products. ```typescript import type { MedusaRequest, MedusaResponse, } from "@medusajs/medusa"; import { IProductModuleService } from "@medusajs/types"; import { ModuleRegistrationName } from "@medusajs/utils"; export const GET = async ( req: MedusaRequest, res: MedusaResponse ) => { const productModuleService: IProductModuleService = req.scope.resolve(ModuleRegistrationName.PRODUCT); const [, count] = await productModuleService.listAndCount(); res.json({ count, }); } ``` -------------------------------- ### Use Custom Module Service in API Route (TypeScript) Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/modules/README.md Demonstrates how to resolve and use the main service of a custom Medusa module within an API route. It shows how to access the Medusa container via `req.scope` to get the service instance and call its methods. ```typescript import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" import HelloModuleService from "../../../modules/hello/service" import { HELLO_MODULE } from "../../../modules/hello" export async function GET( req: MedusaRequest, res: MedusaResponse ): Promise { const helloModuleService: HelloModuleService = req.scope.resolve( HELLO_MODULE ) res.json({ message: helloModuleService.getMessage(), }) } ``` -------------------------------- ### Implement Search page component using React InstantSearch Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Defines a Next.js page that renders a search interface using InstantSearch components. It utilizes the previously configured searchClient and index name, displaying a search box and product hits via a custom hit component. The component is ready for inclusion in the app's routing. ```TypeScript import { InstantSearch, SearchBox, Hits } from \"react-instantsearch\"\nimport { searchClient, SEARCH_INDEX_NAME } from \"@lib/search-client\"\n\nexport default function SearchPage() {\n return (\n \n \n \n \n )\n} ``` -------------------------------- ### List Products Catalog - Shell & TypeScript Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Fetches paginated product catalog with regional pricing and variant information. Supports filtering by region ID, field selection, and pagination parameters. The TypeScript implementation uses Medusa SDK in a Next.js Server Component with 12-item pagination and dynamic region resolution. ```bash # Get products for a specific region curl -X GET "http://localhost:9000/store/products?region_id=reg_123&limit=10&offset=0&fields=*variants,*images" # Response { "products": [ { "id": "prod_01JCGK8P9Z5RNXS0JHVN3QBD2T", "title": "Medusa T-Shirt", "handle": "medusa-t-shirt", "description": "High quality cotton t-shirt", "status": "published", "images": [ { "url": "https://storage.example.com/tshirt.jpg" } ], "variants": [ { "id": "variant_01JCGK8P9Z6S...", "title": "S / Black", "sku": "SHIRT-S-BLACK", "prices": [ { "amount": 1000, "currency_code": "eur" } ] } ] } ], "count": 4 } # Usage in Next.js (Server Component) # File: storefront/src/lib/data/products.ts ``` ```typescript import { sdk } from "@lib/config" export async function getProductsList({ pageParam = 0, queryParams, countryCode }) { const region = await getRegion(countryCode) const { products, count } = await sdk.store.product.list({ limit: 12, offset: pageParam, region_id: region.id, fields: "*variants.calculated_price,*variants.inventory_quantity", ...queryParams, }) return { response: { products, count }, nextPage: count > pageParam + 12 ? pageParam + 12 : null, } } ``` -------------------------------- ### Define Multiple HTTP Method Handlers for an API Route Source: https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate/blob/master/backend/src/api/README.md Shows how to export functions for different HTTP methods (GET, POST, PUT) within a single API route file. This allows a single endpoint to handle various request types. Each function receives Medusa's request and response objects. ```typescript import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa"; export async function GET(req: MedusaRequest, res: MedusaResponse) { // Handle GET requests } export async function POST(req: MedusaRequest, res: MedusaResponse) { // Handle POST requests } export async function PUT(req: MedusaRequest, res: MedusaResponse) { // Handle PUT requests } ``` -------------------------------- ### MinIO File Provider Implementation (TypeScript) Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Implements a custom file provider service for MedusaJS using the MinIO client. It handles file uploads, deletions, and generates presigned URLs for downloads and uploads. Dependencies include '@medusajs/framework/utils' and 'minio'. ```typescript // File: backend/src/modules/minio-file/service.ts import { AbstractFileProviderService } from "@medusajs/framework/utils" import * as Minio from "minio" export default class MinioFileProviderService extends AbstractFileProviderService { protected client_: Minio.Client protected bucket_: string async upload(file: ProviderUploadFileDTO): Promise { const parsedFilename = path.parse(file.filename) const fileKey = `${parsedFilename.name}-${ulid()}${parsedFilename.ext}` await this.client_.putObject( this.bucket_, fileKey, file.content, file.content.length, { "Content-Type": file.mimeType, } ) return { url: `https://${this.endpoint_}/${this.bucket_}/${fileKey}`, key: fileKey, } } async delete(fileData: ProviderDeleteFileDTO): Promise { await this.client_.removeObject(this.bucket_, fileData.fileKey) } async getPresignedDownloadUrl( fileData: ProviderGetFileDTO ): Promise { return await this.client_.presignedGetObject( this.bucket_, fileData.fileKey, 24 * 60 * 60 // 24 hours ) } async getPresignedUploadUrl( fileData: ProviderGetPresignedUploadUrlDTO ): Promise { const presignedUrl = await this.client_.presignedPutObject( this.bucket_, fileData.fileKey, 15 * 60 // 15 minutes ) return { url: presignedUrl, key: fileData.fileKey, } } } ``` -------------------------------- ### Manage Shopping Cart Lifecycle - Shell Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Complete cart lifecycle management via REST API endpoints. Covers creation, item management, shipping address assignment, method selection, and order completion. Demonstrates sequential e-commerce operations using the store/carts endpoint with JSON payloads and standard HTTP methods. ```bash # 1. Create a new cart curl -X POST http://localhost:9000/store/carts \ -H "Content-Type: application/json" \ -d '{ "region_id": "reg_01JCGK8P9Z5RNXS0JHVN3QBD2T" }' # Response { "cart": { "id": "cart_01JCGK8P9Z5RNXS0JHVN3QBD2T", "region_id": "reg_01JCGK8P9Z5RNXS0JHVN3QBD2T", "items": [], "total": 0 } } # 2. Add item to cart curl -X POST http://localhost:9000/store/carts/cart_01JCGK8P9Z5RNXS0JHVN3QBD2T/line-items \ -H "Content-Type: application/json" \ -d '{ "variant_id": "variant_01JCGK8P9Z6S...", "quantity": 2 }' # 3. Update line item quantity curl -X POST http://localhost:9000/store/carts/cart_01JCGK8P9Z5RNXS0JHVN3QBD2T/line-items/item_123 \ -H "Content-Type: application/json" \ -d '{ "quantity": 3 }' # 4. Add shipping address curl -X POST http://localhost:9000/store/carts/cart_01JCGK8P9Z5RNXS0JHVN3QBD2T \ -H "Content-Type: application/json" \ -d '{ "shipping_address": { "first_name": "John", "last_name": "Doe", "address_1": "123 Main St", "city": "Copenhagen", "country_code": "dk", "postal_code": "1000" } }' # 5. Add shipping method curl -X POST http://localhost:9000/store/carts/cart_01JCGK8P9Z5RNXS0JHVN3QBD2T/shipping-methods \ -H "Content-Type: application/json" \ -d '{ "option_id": "so_standard" }' # 6. Complete cart (place order) curl -X POST http://localhost:9000/store/carts/cart_01JCGK8P9Z5RNXS0JHVN3QBD2T/complete # Response { "type": "order", "data": { "id": "order_01JCGK8P9Z5RNXS0JHVN3QBD2T", "status": "pending", "total": 3000, "items": [...] } } ``` -------------------------------- ### Add customer address with Next.js Server Action Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Creates a new customer address using Next.js Server Actions. Handles form data and communicates with MedusaJS store API. Requires authentication headers. ```typescript "use server" import { sdk } from "@lib/config" import { getAuthHeaders } from "@lib/util/server-cookies" import { revalidateTag } from "next/cache" export async function addCustomerAddress(_currentState, formData) { const address = { first_name: formData.get("first_name") as string, last_name: formData.get("last_name") as string, company: formData.get("company") as string, address_1: formData.get("address_1") as string, address_2: formData.get("address_2") as string, city: formData.get("city") as string, postal_code: formData.get("postal_code") as string, province: formData.get("province") as string, country_code: formData.get("country_code") as string, phone: formData.get("phone") as string, } try { await sdk.store.customer.createAddress(address, {}, getAuthHeaders()) revalidateTag("customer") return { success: true, error: null } } catch (error: any) { return { success: false, error: error.message } } } ``` -------------------------------- ### List and retrieve orders in Next.js Source: https://context7.com/rpuls/medusajs-2.0-for-railway-boilerplate/llms.txt Next.js functions for listing and retrieving customer orders with caching. Uses MedusaJS SDK with authentication headers. ```typescript import { sdk } from "@lib/config" import { cache } from "react" import { getAuthHeaders } from "@lib/util/server-cookies" export const listOrders = cache(async function ( limit: number = 10, offset: number = 0 ) { return await sdk.store.order .list( { limit, offset, fields: "+items.*" }, getAuthHeaders() ) .then(({ orders }) => orders) }) export const retrieveOrder = cache(async function (id: string) { return await sdk.store.order .retrieve( id, { fields: "+items.*,+shipping_address.*" }, getAuthHeaders() ) .then(({ order }) => order) }) ```