npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@tailor-platform/shopify

v0.5.1

Published

Shopify Admin API client with Tailor Platform integration

Readme

@tailor-platform/shopify

A drop-in replacement for @shopify/admin-api-client that uses Tailor Platform integration tokens instead of Shopify offline tokens.

Installation

npm install @tailor-platform/shopify
# or
yarn add @tailor-platform/shopify
# or
pnpm add @tailor-platform/shopify

Usage

Basic Usage

import { createAdminApiClient, ApiVersion } from '@tailor-platform/shopify';

const client = createAdminApiClient({
  storeDomain: 'your-shop.myshopify.com',
  apiVersion: ApiVersion.October25, // or ApiVersion.Unstable
  accessToken: 'tst_YOUR_INTEGRATION_TOKEN', // Integration token from Tailor Platform
});

// Make GraphQL requests
const { data, errors } = await client.request(
  `
  query getProduct($id: ID!) {
    product(id: $id) {
      title
      handle
      description
    }
  }
`,
  {
    variables: {
      id: 'gid://shopify/Product/123456789',
    },
  }
);

Type-Safe Usage

The SDK provides full TypeScript support with automatic type inference:

import {
  createAdminApiClient,
  ApiVersion,
  gql,
} from '@tailor-platform/shopify';

// Define your types
interface ProductData {
  product: {
    id: string;
    title: string;
    handle: string;
    description: string;
  };
}

interface ProductVariables {
  id: string;
}

const client = createAdminApiClient({
  storeDomain: 'your-shop.myshopify.com',
  apiVersion: ApiVersion.October25,
  accessToken: 'tst_YOUR_INTEGRATION_TOKEN',
});

// Type-safe query with gql template tag
const productQuery = gql<ProductData, ProductVariables>`
  query getProduct($id: ID!) {
    product(id: $id) {
      id
      title
      handle
      description
    }
  }
`;

// TypeScript automatically infers types from the gql tag
const { data, errors } = await client.request(productQuery, {
  variables: {
    id: 'gid://shopify/Product/123456789',
  },
});

// data is fully typed as ProductData
if (data?.product) {
  console.log(data.product.title); // TypeScript knows this is a string
}

// Alternative: Use types explicitly without gql
const { data } = await client.request<ProductData, ProductVariables>(
  `query getProduct($id: ID!) { ... }`,
  { variables: { id: 'gid://shopify/Product/123456789' } }
);

Working with Mutations

interface CreateProductData {
  productCreate: {
    product: {
      id: string;
      title: string;
    };
    userErrors: Array<{
      field: string[];
      message: string;
    }>;
  };
}

interface CreateProductVariables {
  input: {
    title: string;
    descriptionHtml?: string;
    vendor?: string;
  };
}

const createProductMutation = gql<CreateProductData, CreateProductVariables>`
  mutation createProduct($input: ProductInput!) {
    productCreate(input: $input) {
      product {
        id
        title
      }
      userErrors {
        field
        message
      }
    }
  }
`;

// Type inference works automatically - no need to specify types again
const { data } = await client.request(createProductMutation, {
  variables: {
    input: {
      title: 'New Product',
      descriptionHtml: '<p>Description</p>',
    },
  },
});

// Handle user errors
if (data?.productCreate.userErrors.length > 0) {
  console.error('Failed to create product:', data.productCreate.userErrors);
}

API Versions

The SDK exports constants for all available Shopify API versions:

import { ApiVersion, LATEST_API_VERSION } from '@tailor-platform/shopify';

// Use a specific version
const client = createAdminApiClient({
  storeDomain: 'your-shop.myshopify.com',
  apiVersion: ApiVersion.January25,
  accessToken: 'tst_YOUR_TOKEN',
});

// Use the latest stable version
const client2 = createAdminApiClient({
  storeDomain: 'your-shop.myshopify.com',
  apiVersion: LATEST_API_VERSION, // Currently October25
  accessToken: 'tst_YOUR_TOKEN',
});

// Use unstable version for testing new features
const client3 = createAdminApiClient({
  storeDomain: 'your-shop.myshopify.com',
  apiVersion: ApiVersion.Unstable,
  accessToken: 'tst_YOUR_TOKEN',
});

Type Safety Features

Typed GraphQL Documents

The gql template tag creates typed documents that carry type information:

const query = gql<ResponseType, VariablesType>`...`;
// Types flow automatically to client.request()

Benefits

  • Auto-completion: Full IntelliSense support for response data
  • Type checking: Catch errors at compile time, not runtime
  • Type inference: No need to specify types twice
  • Better DX: See available fields and their types while coding

API Compatibility

This SDK provides the same interface as @shopify/admin-api-client, making it a drop-in replacement. Simply replace your import statement and use your Tailor Platform integration token instead of a Shopify offline token.

Token Permissions

Integration tokens support two permission levels for enhanced security:

Full Access Tokens

  • Can execute both GraphQL queries and mutations
  • Full read and write access to Shopify Admin API
  • Use for: Inventory sync, order processing, product management, fulfillment operations

Read-Only Tokens

  • Can only execute GraphQL queries
  • Cannot perform mutations or modify data
  • Attempts to execute mutations will result in a 403 Forbidden error
  • Use for: Analytics dashboards, reporting tools, read-only integrations, data exports

Best Practices

  1. Principle of Least Privilege: Always use read-only tokens when write access isn't needed
  2. Security: Read-only tokens significantly reduce risk if compromised
  3. Compliance: Easier to audit access when permissions are explicit
  4. Integration Type: Match token permissions to your integration's actual requirements

Example: Read-Only Analytics Token

import { createAdminApiClient, ApiVersion } from '@tailor-platform/shopify';

// Create a client with a read-only token
const analyticsClient = createAdminApiClient({
  storeDomain: 'your-shop.myshopify.com',
  apiVersion: ApiVersion.October25,
  accessToken: 'tst_YOUR_READONLY_TOKEN', // Read-only token
});

// ✅ This works - queries are allowed
const { data } = await analyticsClient.request(`
  query {
    orders(first: 10) {
      edges {
        node {
          id
          totalPriceSet {
            shopMoney {
              amount
            }
          }
        }
      }
    }
  }
`);

// ❌ This fails - mutations are blocked
try {
  await analyticsClient.request(`
    mutation {
      orderUpdate(input: { id: "gid://shopify/Order/123" }) {
        order { id }
      }
    }
  `);
} catch (error) {
  // Error: "This token has read-only access and cannot perform mutations"
  console.error(error);
}

Error Handling for Read-Only Tokens

import {
  createAdminApiClient,
  ShopifyApiError,
  NetworkError,
} from '@tailor-platform/shopify';

const client = createAdminApiClient({
  storeDomain: 'your-shop.myshopify.com',
  apiVersion: ApiVersion.October25,
  accessToken: 'tst_YOUR_READONLY_TOKEN',
});

try {
  const { data } = await client.request(someMutation);
} catch (error) {
  if (error instanceof NetworkError && error.statusCode === 403) {
    console.error('Permission denied - token may be read-only');
    // Handle gracefully: show user message, switch to different token, etc.
  } else if (error instanceof ShopifyApiError) {
    console.error('Shopify API error:', error.errors);
  }
}

Creating Tokens with Permissions

When creating tokens through the Tailor Platform dashboard:

  1. Navigate to the Tokens page
  2. Click Create new token
  3. Enter a descriptive name
  4. Select permission level:
    • Full access: For integrations that need to modify data
    • Read-only: For analytics, reporting, or monitoring tools
  5. Set an expiration date (recommended for security)
  6. Copy and securely store the token (it won't be shown again)

Response Types

All GraphQL responses follow this structure:

interface GraphQLResponse<TData> {
  data?: TData;
  errors?: GraphQLError[];
  extensions?: {
    cost?: {
      requestedQueryCost: number;
      actualQueryCost: number;
      throttleStatus: {
        maximumAvailable: number;
        currentlyAvailable: number;
        restoreRate: number;
      };
    };
    [key: string]: unknown;
  };
}

interface GraphQLError {
  message: string;
  extensions?: Record<string, unknown>;
  path?: (string | number)[];
  locations?: Array<{
    line: number;
    column: number;
  }>;
}

Error Handling

The SDK provides custom error types for better error handling:

import {
  ShopifyApiError,
  NetworkError,
  ConfigurationError,
} from '@tailor-platform/shopify';

try {
  const { data } = await client.request(query);
} catch (error) {
  if (error instanceof ShopifyApiError) {
    // Handle Shopify API errors
    console.error('Shopify API error:', error.errors);
  } else if (error instanceof NetworkError) {
    // Handle network errors
    console.error('Network error:', error.statusCode);
  } else if (error instanceof ConfigurationError) {
    // Handle configuration errors
    console.error('Configuration error:', error.message);
  }
}

Webhook Management

The SDK provides webhook support with Tailor Platform's managed webhook system, offering automatic registration, reliable delivery, and retry logic.

Creating Webhooks

const CREATE_WEBHOOK = gql`
  mutation webhookSubscriptionCreate(
    $topic: WebhookSubscriptionTopic!
    $webhookSubscription: WebhookSubscriptionInput!
  ) {
    webhookSubscriptionCreate(
      topic: $topic
      webhookSubscription: $webhookSubscription
    ) {
      webhookSubscription {
        id
        topic
        callbackUrl
      }
      userErrors {
        field
        message
      }
    }
  }
`;

const { data } = await client.request(CREATE_WEBHOOK, {
  variables: {
    topic: 'ORDERS_CREATE',
    webhookSubscription: {
      callbackUrl: 'https://your-app.com/webhooks/orders',
    },
  },
});

Webhook Topics

The SDK exports webhook topic utilities:

import {
  getWebhookEventName,
  getWebhookTopicEnum,
} from '@tailor-platform/shopify';

// Convert between GraphQL enum and event names
getWebhookEventName('ORDERS_CREATE'); // 'orders/create'
getWebhookTopicEnum('orders/create'); // 'ORDERS_CREATE'

Other Webhook Operations

// List webhooks
const LIST_WEBHOOKS = gql`
  query webhookSubscriptions($first: Int!) {
    webhookSubscriptions(first: $first) {
      edges {
        node {
          id
          topic
          callbackUrl
        }
      }
    }
  }
`;

// Update webhook
const UPDATE_WEBHOOK = gql`
  mutation webhookSubscriptionUpdate(
    $id: ID!
    $webhookSubscription: WebhookSubscriptionInput!
  ) {
    webhookSubscriptionUpdate(
      id: $id
      webhookSubscription: $webhookSubscription
    ) {
      webhookSubscription {
        id
        callbackUrl
      }
      userErrors {
        field
        message
      }
    }
  }
`;

// Delete webhook
const DELETE_WEBHOOK = gql`
  mutation webhookSubscriptionDelete($id: ID!) {
    webhookSubscriptionDelete(id: $id) {
      deletedWebhookSubscriptionId
      userErrors {
        field
        message
      }
    }
  }
`;

Webhook Reliability

Tailor Platform automatically:

  • Registers webhooks with Shopify
  • Retries failed deliveries with exponential backoff
  • Pauses webhooks after 10 consecutive failures
  • Provides monitoring through the dashboard

Common Webhook Topics

  • Orders: ORDERS_CREATE, ORDERS_UPDATED, ORDERS_PAID, ORDERS_FULFILLED
  • Products: PRODUCTS_CREATE, PRODUCTS_UPDATE, PRODUCTS_DELETE
  • Customers: CUSTOMERS_CREATE, CUSTOMERS_UPDATE, CUSTOMERS_DELETE
  • Inventory: INVENTORY_ITEMS_CREATE, INVENTORY_LEVELS_UPDATE

For a complete list, see the Shopify documentation.