@veyralabs/skills 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,13 @@
1
1
  # VeyraSkills
2
2
 
3
- Skills for Claude Code and other AI coding agents. Each skill is a plain text file that teaches your agent a specialized workflow — naming, branding, website cloning, and more.
3
+ ![7 skills](https://img.shields.io/badge/skills-7-blue) ![npm](https://img.shields.io/npm/v/@veyralabs/skills) ![license](https://img.shields.io/badge/license-MIT-green)
4
+
5
+ Skills for Claude Code and other AI coding agents. Each skill is a plain text file that teaches your agent a specialized workflow - naming, branding, website cloning, Shopify development, and more.
4
6
 
5
7
  ```bash
6
8
  npx @veyralabs/skills install naming-suite
7
9
  npx @veyralabs/skills install webcloner
10
+ npx @veyralabs/skills install shopify-suite
8
11
  ```
9
12
 
10
13
  Or install everything at once:
@@ -30,6 +33,15 @@ Four skills for naming products, auditing brands, mapping competitors, and build
30
33
 
31
34
  Works best in sequence: run `competitornames` to understand the landscape, then `domainforge` to generate names that stand out from it.
32
35
 
36
+ ### shopify-suite
37
+
38
+ Two skills covering the full Shopify stack - one for developers building themes and apps, one for merchants auditing and optimizing stores.
39
+
40
+ | Skill | What it does |
41
+ |-------|-------------|
42
+ | [shopify-dev](./skills/shopify-suite/shopify-dev/SKILL.md) | Shopify development across all layers: Liquid themes, JSON templates, app development with Remix, Storefront and Admin API, CLI workflows, checkout extensions, Hydrogen. Fetches live Shopify documentation via Context7 before answering version-sensitive questions |
43
+ | [shopify-store](./skills/shopify-suite/shopify-store/SKILL.md) | Store audit and optimization. Works in two modes: Mode A uses shopify-mcp to read real store data (products, orders, apps, metafields); Mode B uses public extraction when MCP is not available. Audits 6 dimensions: catalog health, collection architecture, navigation, SEO, app stack, conversion signals |
44
+
33
45
  ### webcloner
34
46
 
35
47
  Clone any landing page, marketing site, portfolio, or ecommerce storefront into a pixel-accurate Next.js replica.
@@ -51,6 +63,9 @@ Works for landings, marketing sites, portfolios, and ecommerce product pages. No
51
63
  ```bash
52
64
  npx @veyralabs/skills install naming-suite
53
65
  npx @veyralabs/skills install webcloner
66
+ npx @veyralabs/skills install shopify-suite
67
+ npx @veyralabs/skills install shopify-dev
68
+ npx @veyralabs/skills install shopify-store
54
69
  npx @veyralabs/skills install domainforge
55
70
  ```
56
71
 
@@ -109,14 +124,14 @@ npx @veyralabs/skills install domainforge
109
124
  ## Coming soon
110
125
 
111
126
  **brand-suite**
112
- - `brandvoice` tone of voice guide generator
113
- - `brandpositioning` positioning statement and competitive differentiation
114
- - `taglineforge` tagline generation with scoring
127
+ - `brandvoice` - tone of voice guide generator
128
+ - `brandpositioning` - positioning statement and competitive differentiation
129
+ - `taglineforge` - tagline generation with scoring
115
130
 
116
131
  **gtm-suite**
117
- - `icp` Ideal Customer Profile builder
118
- - `pricingstrategy` pricing model analysis
119
- - `gtmplan` go-to-market plan generator
132
+ - `icp` - Ideal Customer Profile builder
133
+ - `pricingstrategy` - pricing model analysis
134
+ - `gtmplan` - go-to-market plan generator
120
135
 
121
136
  ---
122
137
 
@@ -126,6 +141,9 @@ Each skill is also published as a standalone npm package if you only want one:
126
141
 
127
142
  - `@veyralabs/naming-suite`
128
143
  - `@veyralabs/webcloner`
144
+ - `@veyralabs/shopify-suite`
145
+ - `@veyralabs/shopify-dev`
146
+ - `@veyralabs/shopify-store`
129
147
 
130
148
  ---
131
149
 
package/bin/cli.js CHANGED
@@ -4,10 +4,17 @@
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
6
  const os = require('os');
7
+ const { execFileSync } = require('child_process');
7
8
 
8
9
  const SKILLS_DIR = path.join(__dirname, '..', 'skills');
9
10
  const COMMANDS_DIR = path.join(__dirname, '..', 'commands');
10
11
 
12
+ // pip packages required per skill
13
+ const SKILL_PIP_DEPS = {
14
+ 'shopify-store': ['scrapling'],
15
+ 'webcloner': ['scrapling'],
16
+ };
17
+
11
18
  const AGENT_PATHS = {
12
19
  claude: { local: '.claude/skills', global: '.claude/skills' },
13
20
  cursor: { local: '.cursor/skills', global: '.cursor/skills' },
@@ -78,6 +85,31 @@ function copySkill(name, skillPath, dest) {
78
85
  console.log(` ✓ ${name}`);
79
86
  }
80
87
 
88
+ function installPipDeps(skillNames) {
89
+ const pkgs = [...new Set(skillNames.flatMap(n => SKILL_PIP_DEPS[n] || []))];
90
+ if (pkgs.length === 0) return;
91
+
92
+ let pip = null;
93
+ for (const cmd of ['pip3', 'pip']) {
94
+ try { execFileSync(cmd, ['--version'], { stdio: 'ignore' }); pip = cmd; break; } catch {}
95
+ }
96
+
97
+ if (!pip) {
98
+ console.log(` ⚠ Python pip not found. Install manually: pip install ${pkgs.join(' ')}`);
99
+ return;
100
+ }
101
+
102
+ for (const pkg of pkgs) {
103
+ try {
104
+ console.log(` Installing Python dependency: ${pkg}...`);
105
+ execFileSync(pip, ['install', pkg, '-q'], { stdio: 'inherit' });
106
+ console.log(` ✓ ${pkg}`);
107
+ } catch {
108
+ console.log(` ⚠ Failed to install ${pkg}. Run: ${pip} install ${pkg}`);
109
+ }
110
+ }
111
+ }
112
+
81
113
  // Copy slash commands — Claude Code only (.claude/commands/)
82
114
  function copyCommands(agent, isGlobal) {
83
115
  if (agent !== 'claude') return;
@@ -170,6 +202,7 @@ if (command === 'install') {
170
202
  console.log(`\nInstalling into ${dest} [${agent}/${scope}]\n`);
171
203
  toInstall.forEach(name => copySkill(name, skills[name], dest));
172
204
  copyCommands(agent, isGlobal);
205
+ installPipDeps(toInstall);
173
206
  console.log('\nDone. Restart your agent to activate skills.\n');
174
207
  process.exit(0);
175
208
  }
@@ -0,0 +1,3 @@
1
+ Activate the shopify-dev skill. Task: $ARGUMENTS
2
+
3
+ Start by detecting the mode from context (theme / app / api / cli / hydrogen / debug). Fetch current Shopify documentation via Context7 before writing any code. Use the reference files in skills/shopify-suite/shopify-dev/references/ for patterns, queries, and CLI workflows.
@@ -0,0 +1,3 @@
1
+ Activate the shopify-store skill. Task: $ARGUMENTS
2
+
3
+ Start with mode detection: attempt list_products via shopify-mcp. If MCP responds, run the full Mode A audit pipeline. If not available, switch to Mode B (public extraction via Scrapling). Use reference files in skills/shopify-suite/shopify-store/references/ for checklists, queries, and scoring.
package/install.sh CHANGED
@@ -114,6 +114,37 @@ check_deps() {
114
114
  fi
115
115
  }
116
116
 
117
+ # Skills that require Python packages: skill_name -> pip packages (space-separated)
118
+ declare -A SKILL_PIP_DEPS=(
119
+ ["shopify-store"]="scrapling"
120
+ ["webcloner"]="scrapling"
121
+ )
122
+
123
+ install_pip_deps() {
124
+ local skill="$1"
125
+ local pkgs="${SKILL_PIP_DEPS[$skill]:-}"
126
+ [[ -z "$pkgs" ]] && return
127
+
128
+ local pip=""
129
+ for cmd in pip3 pip; do
130
+ command -v "$cmd" &>/dev/null && pip="$cmd" && break
131
+ done
132
+
133
+ if [[ -z "$pip" ]]; then
134
+ echo " Warning: pip not found. Install manually: pip install $pkgs"
135
+ return
136
+ fi
137
+
138
+ for pkg in $pkgs; do
139
+ echo " Installing Python dependency: $pkg..."
140
+ if "$pip" install "$pkg" -q; then
141
+ echo " ✓ $pkg"
142
+ else
143
+ echo " Warning: failed to install $pkg. Run: $pip install $pkg"
144
+ fi
145
+ done
146
+ }
147
+
117
148
  install_skill() {
118
149
  local skill="$1"
119
150
  local dest_dir="$2"
@@ -236,11 +267,15 @@ main() {
236
267
  if [[ -n "$SKILL_NAME" ]]; then
237
268
  echo "Installing '$SKILL_NAME' → $dest/"
238
269
  install_skill "$SKILL_NAME" "$dest"
270
+ install_pip_deps "$SKILL_NAME"
239
271
  echo ""
240
272
  echo "Done. ${dest}/${SKILL_NAME}/ is ready."
241
273
  else
242
274
  echo "Installing all skills → $dest/"
243
275
  install_all "$dest"
276
+ for skill in "${!SKILL_PIP_DEPS[@]}"; do
277
+ install_pip_deps "$skill"
278
+ done
244
279
  echo ""
245
280
  echo "Done. All skills installed to ${dest}/"
246
281
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veyralabs/skills",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "VeyraSkills — A curated collection of Claude Code skills for founders, developers and AI builders",
5
5
  "bin": {
6
6
  "veyraskills": "bin/cli.js"
@@ -30,7 +30,12 @@
30
30
  "domain-generator",
31
31
  "startup-branding",
32
32
  "brand-strategy",
33
- "developer-tools"
33
+ "developer-tools",
34
+ "shopify",
35
+ "shopify-theme",
36
+ "shopify-app",
37
+ "shopify-audit",
38
+ "ecommerce"
34
39
  ],
35
40
  "author": "VeyraLabs <hello@veyralabs.com>",
36
41
  "license": "MIT",
@@ -0,0 +1,409 @@
1
+ ---
2
+ name: shopify-dev
3
+ description: >
4
+ Shopify Developer. Activate when a user is building or modifying a Shopify theme, app, or integration.
5
+ Triggers on: "add a section to my theme", "create a Shopify app", "Shopify CLI", "Liquid template",
6
+ "Storefront API", "Admin API", "checkout extension", "Hydrogen", "Polaris", "shopify theme dev",
7
+ "metafields", "metaobjects", "app blocks", "Online Store 2.0", "section schema".
8
+ Covers theme development, app development, GraphQL APIs, CLI workflows, and extensions.
9
+ ---
10
+
11
+ # Shopify Developer Skill
12
+
13
+ You are a Shopify development expert. You know the full Shopify stack: Liquid, JSON templates, section schemas, the CLI, GraphQL Storefront and Admin APIs, Remix-based app development, Polaris, checkout extensions, and Hydrogen.
14
+
15
+ Shopify's APIs and Liquid filters change every quarter. Before answering any question involving API versions, GraphQL schema, CLI flags, or new Liquid syntax — fetch current documentation via Context7 first.
16
+
17
+ ```
18
+ Use context7 to get: shopify liquid documentation
19
+ Use context7 to get: shopify storefront api graphql
20
+ Use context7 to get: shopify admin api graphql
21
+ Use context7 to get: shopify cli reference
22
+ ```
23
+
24
+ ---
25
+
26
+ ## Mode Detection
27
+
28
+ Infer the mode from context. Ask only if genuinely ambiguous.
29
+
30
+ | Mode | Triggers |
31
+ |------|----------|
32
+ | `theme` | Liquid, JSON templates, sections, blocks, Dawn, OS 2.0, theme editor |
33
+ | `app` | Remix, Polaris, OAuth, webhooks, app extensions, app bridge |
34
+ | `api` | GraphQL queries, Storefront API, Admin API, metafields |
35
+ | `cli` | `shopify theme`, `shopify app`, deploy, environments, pull/push |
36
+ | `hydrogen` | Headless, Remix routes, cache strategies, Storefront API |
37
+ | `debug` | Error messages, unexpected behavior, breaking changes |
38
+
39
+ ---
40
+
41
+ ## Phase 1 — Context Fetch
42
+
43
+ Before writing code, fetch current docs for the relevant area:
44
+
45
+ ```
46
+ shopify liquid → for Liquid filters, tags, objects
47
+ shopify sections → for section schema, blocks, settings
48
+ shopify storefront api → for cart, products, collections queries
49
+ shopify admin api → for mutations, webhooks, metafields
50
+ shopify cli → for theme/app commands and flags
51
+ shopify checkout extensions → for UI extensions, checkout UI
52
+ shopify hydrogen → for headless setup, routes, caching
53
+ ```
54
+
55
+ Cross-reference with `references/` files for patterns and decisions not covered by docs.
56
+
57
+ ---
58
+
59
+ ## Mode: Theme Development
60
+
61
+ ### JSON Template Structure (OS 2.0)
62
+
63
+ ```json
64
+ {
65
+ "sections": {
66
+ "hero": {
67
+ "type": "hero-banner",
68
+ "settings": {}
69
+ }
70
+ },
71
+ "order": ["hero"]
72
+ }
73
+ ```
74
+
75
+ ### Section Schema Pattern
76
+
77
+ ```liquid
78
+ {% schema %}
79
+ {
80
+ "name": "Section Name",
81
+ "tag": "section",
82
+ "class": "section-name",
83
+ "settings": [
84
+ {
85
+ "type": "text",
86
+ "id": "heading",
87
+ "label": "Heading",
88
+ "default": "Default heading"
89
+ },
90
+ {
91
+ "type": "image_picker",
92
+ "id": "image",
93
+ "label": "Image"
94
+ },
95
+ {
96
+ "type": "select",
97
+ "id": "layout",
98
+ "label": "Layout",
99
+ "options": [
100
+ { "value": "left", "label": "Left" },
101
+ { "value": "right", "label": "Right" }
102
+ ],
103
+ "default": "left"
104
+ }
105
+ ],
106
+ "blocks": [
107
+ {
108
+ "type": "feature",
109
+ "name": "Feature",
110
+ "settings": [
111
+ { "type": "text", "id": "title", "label": "Title" }
112
+ ]
113
+ }
114
+ ],
115
+ "max_blocks": 6,
116
+ "presets": [
117
+ {
118
+ "name": "Section Name"
119
+ }
120
+ ]
121
+ }
122
+ {% endschema %}
123
+ ```
124
+
125
+ ### Key Decision Points
126
+
127
+ **Sections vs Blocks:**
128
+ - Section: top-level structural element, configurable in theme editor
129
+ - Block: repeatable element within a section (cards, features, tabs)
130
+ - Rule: if it repeats, it's a block; if it's a layout region, it's a section
131
+
132
+ **Metafields vs Metaobjects:**
133
+ - Metafield: extra data attached to existing resource (product, collection, page)
134
+ - Metaobject: standalone structured content type (team members, testimonials, FAQs)
135
+ - Rule: if it belongs TO something → metafield; if it IS something on its own → metaobject
136
+
137
+ **Section Rendering API:**
138
+ Use for partial updates without full page reload:
139
+ ```javascript
140
+ fetch(`?section_id=cart-items`)
141
+ .then(r => r.text())
142
+ .then(html => {
143
+ document.querySelector('#cart-items').innerHTML =
144
+ new DOMParser()
145
+ .parseFromString(html, 'text/html')
146
+ .querySelector('#cart-items').innerHTML;
147
+ });
148
+ ```
149
+
150
+ ### AJAX Cart Pattern
151
+
152
+ ```javascript
153
+ async function addToCart(variantId, quantity = 1) {
154
+ const res = await fetch('/cart/add.js', {
155
+ method: 'POST',
156
+ headers: { 'Content-Type': 'application/json' },
157
+ body: JSON.stringify({ id: variantId, quantity }),
158
+ });
159
+ if (!res.ok) throw new Error('Add to cart failed');
160
+ return res.json();
161
+ }
162
+
163
+ async function getCart() {
164
+ return fetch('/cart.js').then(r => r.json());
165
+ }
166
+
167
+ async function updateCart(updates) {
168
+ return fetch('/cart/update.js', {
169
+ method: 'POST',
170
+ headers: { 'Content-Type': 'application/json' },
171
+ body: JSON.stringify({ updates }),
172
+ }).then(r => r.json());
173
+ }
174
+ ```
175
+
176
+ ---
177
+
178
+ ## Mode: App Development
179
+
180
+ ### Stack (2025+)
181
+
182
+ New Shopify apps use the **Dev Dashboard** (not Partner Dashboard). All new apps use OAuth client credentials, not static access tokens.
183
+
184
+ ```bash
185
+ npm init @shopify/app@latest
186
+ # Choose: Remix template
187
+ ```
188
+
189
+ ### App Structure
190
+
191
+ ```
192
+ app/
193
+ routes/
194
+ app._index.tsx ← main app page
195
+ app.products.tsx ← products page
196
+ webhooks.tsx ← webhook handler
197
+ shopify.server.ts ← Shopify auth + API client
198
+ db.server.ts ← Prisma DB
199
+ ```
200
+
201
+ ### Admin API Call in Remix
202
+
203
+ ```typescript
204
+ // app/routes/app._index.tsx
205
+ import { json } from "@remix-run/node";
206
+ import { useLoaderData } from "@remix-run/react";
207
+ import { authenticate } from "../shopify.server";
208
+
209
+ export const loader = async ({ request }) => {
210
+ const { admin } = await authenticate.admin(request);
211
+
212
+ const response = await admin.graphql(`
213
+ query {
214
+ products(first: 10) {
215
+ nodes {
216
+ id
217
+ title
218
+ status
219
+ }
220
+ }
221
+ }
222
+ `);
223
+
224
+ const { data } = await response.json();
225
+ return json({ products: data.products.nodes });
226
+ };
227
+ ```
228
+
229
+ ### Webhook Handler
230
+
231
+ ```typescript
232
+ // app/routes/webhooks.tsx
233
+ import { authenticate } from "../shopify.server";
234
+ import db from "../db.server";
235
+
236
+ export const action = async ({ request }) => {
237
+ const { topic, shop, session, payload } = await authenticate.webhook(request);
238
+
239
+ switch (topic) {
240
+ case "PRODUCTS_UPDATE":
241
+ await db.product.upsert({
242
+ where: { shopifyId: payload.id.toString() },
243
+ update: { title: payload.title },
244
+ create: { shopifyId: payload.id.toString(), title: payload.title, shop },
245
+ });
246
+ break;
247
+
248
+ case "APP_UNINSTALLED":
249
+ if (session) await db.session.deleteMany({ where: { shop } });
250
+ break;
251
+ }
252
+
253
+ return new Response();
254
+ };
255
+ ```
256
+
257
+ ### Polaris Component Rules
258
+
259
+ - Always import from `@shopify/polaris`
260
+ - Wrap app in `<AppProvider i18n={translations}>` at root
261
+ - Use `Page` + `Layout` + `Card` structure for all pages
262
+ - `ResourceList` for lists of items, `DataTable` for tabular data
263
+ - `useAppBridge` for redirect and toast
264
+
265
+ ---
266
+
267
+ ## Mode: Extensions
268
+
269
+ ### Checkout UI Extension
270
+
271
+ ```typescript
272
+ // extensions/checkout-ui/src/Checkout.tsx
273
+ import {
274
+ reactExtension,
275
+ useDeliveryGroups,
276
+ Banner,
277
+ BlockStack,
278
+ Text,
279
+ } from "@shopify/ui-extensions-react/checkout";
280
+
281
+ export default reactExtension("purchase.checkout.block.render", () => (
282
+ <Extension />
283
+ ));
284
+
285
+ function Extension() {
286
+ const deliveryGroups = useDeliveryGroups();
287
+
288
+ return (
289
+ <BlockStack>
290
+ <Banner title="Delivery info">
291
+ <Text>Your order ships in 2-3 business days.</Text>
292
+ </Banner>
293
+ </BlockStack>
294
+ );
295
+ }
296
+ ```
297
+
298
+ Extension targets — common ones:
299
+ - `purchase.checkout.block.render` — block anywhere in checkout
300
+ - `purchase.checkout.shipping-option-list.render-after` — after shipping options
301
+ - `purchase.checkout.payment-method-list.render-after` — after payment methods
302
+ - `purchase.thank-you.block.render` — thank you page
303
+
304
+ ---
305
+
306
+ ## Mode: Hydrogen (Headless)
307
+
308
+ ### Route Pattern
309
+
310
+ ```typescript
311
+ // app/routes/products.$handle.tsx
312
+ import { LoaderFunctionArgs } from "@remix-run/node";
313
+ import { useLoaderData } from "@remix-run/react";
314
+ import { getPaginationVariables } from "@shopify/hydrogen";
315
+
316
+ export async function loader({ params, context, request }: LoaderFunctionArgs) {
317
+ const { handle } = params;
318
+
319
+ const { product } = await context.storefront.query(PRODUCT_QUERY, {
320
+ variables: { handle },
321
+ cache: context.storefront.CacheLong(), // cache strategy
322
+ });
323
+
324
+ if (!product) throw new Response(null, { status: 404 });
325
+ return { product };
326
+ }
327
+
328
+ const PRODUCT_QUERY = `#graphql
329
+ query Product($handle: String!) {
330
+ product(handle: $handle) {
331
+ id
332
+ title
333
+ handle
334
+ description
335
+ priceRange {
336
+ minVariantPrice { amount currencyCode }
337
+ }
338
+ images(first: 10) {
339
+ nodes { id url altText width height }
340
+ }
341
+ variants(first: 100) {
342
+ nodes {
343
+ id
344
+ title
345
+ availableForSale
346
+ price { amount currencyCode }
347
+ selectedOptions { name value }
348
+ }
349
+ }
350
+ }
351
+ }
352
+ ` as const;
353
+ ```
354
+
355
+ ### Cache Strategies
356
+
357
+ ```typescript
358
+ context.storefront.CacheNone() // no cache — dynamic, personalized
359
+ context.storefront.CacheShort() // 1min — semi-dynamic (cart, recently viewed)
360
+ context.storefront.CacheLong() // 1hr — mostly static (product pages)
361
+ context.storefront.CacheCustom({ maxAge: 3600, staleWhileRevalidate: 82800 })
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Debug Mode
367
+
368
+ When debugging Shopify issues, always:
369
+
370
+ 1. Check the API version in `shopify.server.ts` — Shopify deprecates quarterly
371
+ 2. Verify scopes match what the operation requires
372
+ 3. Check if the feature requires a specific Shopify plan
373
+ 4. Look for `userErrors` in mutations — GraphQL returns 200 even on business errors:
374
+
375
+ ```graphql
376
+ mutation {
377
+ productUpdate(input: { id: $id, title: $title }) {
378
+ product { id }
379
+ userErrors { # ← always check this
380
+ field
381
+ message
382
+ }
383
+ }
384
+ }
385
+ ```
386
+
387
+ 5. Theme errors: check the Shopify admin → Themes → Edit code → inspect the error output
388
+
389
+ ---
390
+
391
+ ## Anti-Patterns
392
+
393
+ **Don't hardcode API versions.** Read from `shopify.server.ts` config and update quarterly.
394
+
395
+ **Don't use `accessToken` directly in frontend.** Storefront API token is public-safe; Admin API token never goes to client.
396
+
397
+ **Don't skip `userErrors` in mutations.** GraphQL Admin API returns HTTP 200 even when the operation fails at the business logic level.
398
+
399
+ **Don't use `window.location` in app routes.** Use `redirect()` from Remix or `useNavigate()`.
400
+
401
+ **Don't create sections without `presets`.** Without presets, the section won't appear in the theme editor's "Add section" menu.
402
+
403
+ ---
404
+
405
+ Reference files:
406
+ - `references/liquid-patterns.md` — Liquid syntax, filters, objects, gotchas
407
+ - `references/graphql-queries.md` — ready-to-use Storefront + Admin API queries
408
+ - `references/cli-workflows.md` — CLI commands, environments, deploy flows
409
+ - `references/app-architecture.md` — app structure decisions, auth, billing