Command Palette

Search for a command to run...

Reading Options

After a store admin configures an integration, a consumer reads its options at runtime. The consumer is often the same package that declared the integration, such as a payment provider reading its own credentials, but it can be any other code, like an API route, a subscriber, or a scheduled job.

What you get back is resolved: the options are decrypted, validated, and have their defaults applied. See What resolved means for the details.

Two ways to read

The API you use depends on where your code runs.

Where your code runsHow to read
A provider in an isolated module container, or a module service
Code with the app or request container (API routes, subscribers, scheduled jobs, loaders)
A step inside a workflow you compose

A payment or fulfillment provider runs inside its own module's isolated container, so it cannot resolve the Integration Module directly. It uses , which runs a workflow that reaches the app container. Code that already holds the container resolves the module and calls directly, without a workflow.

The helper

Use the helper from a provider that cannot reach the Integration Module directly.

Basic usage

Pass the identifier your integration declares, and a type parameter for typed options. For example:

providers/payment-acme/services/acme-payment.ts
1import { resolveIntegrationOptions } from "@gorgo/medusa-integration"
2import type { AcmeOptions } from "../../../integration-acme/service"
3
4// inside any provider method
5const options = await resolveIntegrationOptions<AcmeOptions>({
6 identifier: "acme"
7})

The returned is typed as , already decrypted and validated.

Targeting a specific instance

For a provider that supports multiple instances, pass . It is usually your provider's own registration id. Omit it, or pass , for the default instance:

providers/payment-acme/services/acme-payment.ts
1import { resolveIntegrationOptions } from "@gorgo/medusa-integration"
2import type { AcmeOptions } from "../../../integration-acme/service"
3
4// inside any provider method
5const options = await resolveIntegrationOptions<AcmeOptions>({
6 identifier: "acme",
7 instance_id: this.instanceId_,
8})

When it isn't configured

By default, the helper throws a when the integration is not configured, disabled, or incomplete:

1// throws if the integration isn't usable yet
2const options = await resolveIntegrationOptions<AcmeOptions>({
3 identifier: "acme"
4})

Pass to receive instead, so you can handle the missing case yourself:

1const options = await resolveIntegrationOptions<AcmeOptions>(
2 { identifier: "acme" },
3 { optional: true }
4)
5
6if (!options) {
7 // not configured yet: skip, fall back, or return a friendly error
8}

The service method

When your code already has the container, resolve the module and call directly. This suits API routes, subscribers, scheduled jobs, and loaders, and no workflow is involved. For example, in an API route:

api/admin/acme-payment/route.ts
1import { INTEGRATION_MODULE, IntegrationModuleService } from "@gorgo/medusa-integration"
2import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
3
4export async function GET(req: MedusaRequest, res: MedusaResponse) {
5 const integration: IntegrationModuleService = req.scope.resolve(INTEGRATION_MODULE)
6
7 const resolved = await integration.getResolvedOptions("acme")
8 if (!resolved) {
9 return res.status(503).send("Acme is not configured")
10 }
11
12 const options = resolved.options as AcmeOptions
13 const { provider_id, category, is_enabled } = resolved.meta
14}

returns . A value is , where holds , , and . A result means the integration is not configured, disabled, or incomplete.

Resolving inside a workflow

When you compose your own workflow, use the exported step instead of the helper:

workflows/create-acme.ts
1import { createWorkflow, WorkflowResponse } from "@medusajs/framework/workflows-sdk"
2import { getResolvedIntegrationOptionsStep } from "@gorgo/medusa-integration"
3
4export const createAcmeWorkflow = createWorkflow("create-acme", () => {
5 const resolved = getResolvedIntegrationOptionsStep({
6 identifier: "acme"
7 })
8 return new WorkflowResponse(resolved)
9})

The standalone is also exported. It is what the helper runs internally.

What resolved means

Resolved options are not the raw stored values. On every resolve, the module does three things:

  • decrypts secret fields,
  • confirms the integration is enabled and complete, meaning it passes full validation,
  • applies descriptor defaults for options the admin never set.

If the integration is not configured, disabled, or incomplete, it resolves to . The helper throws in that case, or returns with . Partial drafts never reach runtime.

Caching and freshness

Resolved options are cached in memory for a short time, so hot paths do not re-read and decrypt on every call. The cache is invalidated whenever the integration changes, whether it is saved, enabled, disabled, or deleted, so consumers pick up new configuration without a redeploy.

References

Edited Jul 31, 2026·Edit this page