JeterDev Tools

Getting Started

Introduction

JeterDev Tools is a managed bridge over the Etsy API v3. Send requests with your API key and we handle Etsy authentication, rate limiting, and errors — you just consume the JSON.

Public endpoints work with your API key alone. Private endpoints (create listings, manage orders, upload images) require connecting your Etsy shop via OAuth from the dashboard.

Base URL

https://jeterdev.tools/api/v1
Free
$0
100 req/day
1 req/s · 6 endpoints
Starter
$25/mo
2,000 req/day
3 req/s · Read endpoints
Pro
$50/mo
50,000 req/day
10 req/s · All endpoints

Quick start

bash
curl "https://jeterdev.tools/api/v1/listings/search?query=handmade+art&limit=10" \
  -H "x-api-key: jt_YOUR_KEY_HERE"

Getting Started

Authentication

All requests require an API key via the x-api-key header. Generate your key from the Dashboard.

Never expose your API key in client-side code or public repositories. If compromised, rotate it immediately from your dashboard.
bash
curl "https://jeterdev.tools/api/v1/listings/search?query=art" \
  -H "x-api-key: jt_a3f4b5c6d7e8f9..."

Key format

text
jt_a3f4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6

Check your key

bash
curl "https://jeterdev.tools/api/usage" \
  -H "x-api-key: jt_YOUR_KEY"
json
{"plan":"pro","dailyLimit":50000,"used":142,"remaining":49858,"resetsAt":"2026-05-09T00:00:00.000Z"}

Getting Started

Rate Limits

Two independent limits: per-second and daily. Daily limits reset at midnight UTC.

Free
1 req/s
100/day
Starter
3 req/s
2,000/day
Pro
10 req/s
50,000/day

Response headers

http
X-RateLimit-Limit-Day:        50000
X-RateLimit-Remaining-Day:   49858
X-RateLimit-Reset-Day:       1746835200
X-RateLimit-Limit-Second:    10
X-RateLimit-Remaining-Second:9
X-Plan:                      pro

When rate limited — 429

json
{
  "error": {
    "code": "RATE_LIMIT_DAILY",
    "status": 429,
    "message": "Daily request limit reached (50000/day).",
    "hint": "Limit resets at midnight UTC.",
    "docs": "https://jeterdev.tools/docs#rate-limits"
  }
}

Getting Started

Store Connection

Endpoints that access your own shop data require a connected Etsy store. Each user authenticates independently — your data is completely isolated from other users. Store connection uses OAuth 2.0 with PKCE and must be done through the dashboard.

Once connected, JeterDev Tools manages credential refresh automatically. There is no API endpoint for connecting a store.

Access token

1 hour

Auto-refreshed transparently. You never notice this.

Refresh token

90 days

Only when this expires do you need to reconnect. Dashboard shows a red indicator.

✓ API key only

search/listings
listings/search
listings/get
listings/active
listings/featured
listings/images
listings/inventory
listings/shipping
shops/get
shops/listings
shops/sections
shops/reviews
categories/*
images/listing
images/get
media/video
media/files
users/get

⚡ Requires store connection

listings/create
listings/update
listings/delete
listings/property/*
shops/orders
shops/transactions
shops/update
store/receipt/update
store/section/*
images/upload
images/delete
media/file/*
media/video/upload
users/me
users/addresses
policies/*
shipping/create
shipping/update
shipping/delete

How to connect

1

Log in to JeterDev Tools

Go to jeterdev.tools/dashboard

2

Click "Connect Etsy Shop"

You will be redirected to Etsy to authorize your account

3

Review and authorize permissions

Etsy shows the list of permissions being requested

4

You are connected

Your shop name appears in the dashboard. Private endpoints are now available.

Error if not connected

json
{
  "error": {
    "code": "STORE_NOT_CONNECTED",
    "status": 403,
    "message": "Shop 61004439 is not connected.",
    "hint": "Connect the shop at jeterdev.tools/dashboard."
  }
}

Error if token expired

When Etsy revokes a refresh token (user revoked access, token aged out, etc.), the bridge marks the shop connection_expired: true in Firestore and all subsequent calls for that shop return this error immediately without retrying the upstream.

json
{
  "error": {
    "code": "STORE_TOKEN_EXPIRED",
    "status": 403,
    "message": "Shop 61004439 OAuth token has expired and could not be refreshed. Re-link the shop to restore access.",
    "connection_expired": true,
    "hint": "Re-connect the shop at jeterdev.tools/dashboard."
  }
}

How to detect proactively

Poll GET /api/v1/stores and check each store entry for connection_expired: true. When set, prompt your user to re-link before they attempt a publish — rather than letting the publish fail.

typescript
const stores = await getStores();
for (const store of stores) {
  if (store.connection_expired) {
    // surface reconnect CTA to your user
    promptReconnect(store.shopId, store.shopName);
  }
}

OAuth scopes requested

listings_rlistings_wlistings_dshops_rshops_wtransactions_rprofile_remail_rfavorites_rfeedback_r

Getting Started

Errors

All errors follow a consistent shape with a machine-readable code, HTTP status, message, and actionable hint.

json
{
  "error": {
    "code": "ENDPOINT_NOT_IN_PLAN",
    "status": 403,
    "message": "Endpoint 'listings/create' is not available on the Starter plan.",
    "hint": "Upgrade your plan at jeterdev.tools/pricing.",
    "docs": "https://jeterdev.tools/docs#rate-limits"
  }
}
HTTP
Code
Description
Hint
401
INVALID_API_KEY
API key missing, invalid, or revoked.
Generate a new key at jeterdev.tools/dashboard.
401
MISSING_API_KEY
No x-api-key header provided.
Pass your key via the x-api-key header.
403
API_KEY_DISABLED
This API key has been disabled.
Generate a new key at jeterdev.tools/dashboard.
403
ENDPOINT_NOT_IN_PLAN
Endpoint not available on your current plan.
Upgrade at jeterdev.tools/pricing.
403
STORE_NOT_CONNECTED
No Firestore doc for this shop — it was never linked or was deleted.
Connect at jeterdev.tools/dashboard.
403
STORE_NOT_OWNED
shop_id belongs to a different user account.
Use a shop_id returned by GET /stores.
403
STORE_TOKEN_EXPIRED
Refresh failed — token revoked or expired. connection_expired:true is set on the store entry.
Re-link the shop at jeterdev.tools/dashboard. Poll GET /stores and check connection_expired.
404
ENDPOINT_NOT_FOUND
This endpoint does not exist.
Check the path against the docs.
429
RATE_LIMIT_DAILY
Daily request limit reached.
Limit resets at midnight UTC. Retry-After header included.
429
RATE_LIMIT_SECOND
Per-second rate limit exceeded.
Wait the Retry-After seconds before retrying.
400
VALIDATION_FAILED
Request validation failed. See fields object.
Fix the fields indicated in the fields object.
400
TAXONOMY_INVALID
taxonomy_id is not a valid Etsy category.
Use GET /categories/list or /categories/{id}/listing-schema.
404
JOB_NOT_FOUND
Listing job not found or expired.
Jobs expire after 24 hours. Re-submit the create request.
200
ACTIVATION_COST_WARNING
state=active costs $0.20 per listing per shop.
Check activation_cost_usd in the response.
502
UPSTREAM_ERROR
The Etsy API returned an error.
Check the details field for the upstream response.
500
INTERNAL_ERROR
Something went wrong on our end.
Try again or contact support.

Listing Builder

Overview

Create Etsy listings with a single atomic API call. Pass your full payload — title, images, variations, category attributes, personalization — and the bridge handles all Etsy API orchestration internally.

state="draft"

Saves payload internally. Zero Etsy calls. Returns instantly.

state="publish"

Creates listing on Etsy as a draft. Uploads images and sets inventory. Returns listing_id.

state="active"

Same as publish + activates on Etsy. Costs $0.20 USD per listing per shop.

Recommended flow

1

GET /stores

Confirm connected shops and get their shop_ids

2

POST /stores/{shopId}/sync

Get shipping profiles, return policies, processing profiles, and sections in one call

3

GET /categories/{id}/listing-schema

Discover required attributes and variation properties for your category

4

POST /listings/create

Submit with state="draft" first, then re-submit with state="publish" or "active"

5

GET /listings/create/{job_id}

Poll for results — available for 24 hours

state="active"costs $0.20 USD per listing per shop — this is Etsy's listing fee. Always use state="draft" first to verify before activating.

Listing Builder

Uploads

Upload images, videos, or digital files before a listing exists. Uses a presigned URL flow — the file goes directly to storage, bypassing the 4.5MB function limit. Supports up to 100MB per file. Files cached 24 hours.

The presigned flow avoids all server-side size limits. Your client uploads directly to storage — JeterDev Tools never touches the binary.

3-step flow

1

POST /uploads/presign

Get upload_id + a signed Firebase Storage URL

2

PUT file → upload_url

PUT directly to Firebase Storage — no size limit, file never touches Vercel

3

POST /uploads/confirm

Confirm upload and get your jt-upload:// URL

Step 1 — POST /api/v1/uploads/presign

bash
curl -X POST "https://jeterdev.tools/api/v1/uploads/presign"   -H "x-api-key: jt_YOUR_KEY"   -H "Content-Type: application/json"   -d '{"filename":"product-photo.jpg","content_type":"image/jpeg","size":15728640,"type":"image"}'
json
{
  "upload_id":    "jt_a1b2c3d4...",
  "upload_url":   "https://storage.googleapis.com/...?Signature=...",
  "method":       "PUT",
  "content_type": "image/jpeg",
  "expires_in":   "30min",
  "note":         "PUT your file binary to upload_url with Content-Type header"
}

Step 2 — PUT file directly to upload_url (Firebase Storage)

The file goes directly to Firebase Storage — never through Vercel. No size limit.

bash
# curl — empty response body on success (HTTP 200)
curl -X PUT "https://storage.googleapis.com/...?Signature=..."   -H "Content-Type: image/jpeg"   --data-binary "@/path/to/photo.jpg"

# fetch (browser / Node.js)
await fetch(upload_url, {
  method:  "PUT",
  headers: { "Content-Type": "image/jpeg" },
  body:    fileBlob,   // File, Buffer, or ReadableStream — up to 5GB
});
// Empty response body = success

Step 3 — POST /api/v1/uploads/confirm

bash
curl -X POST "https://jeterdev.tools/api/v1/uploads/confirm"   -H "x-api-key: jt_YOUR_KEY"   -H "Content-Type: application/json"   -d '{"upload_id":"jt_a1b2c3d4..."}'
json
{
  "url":          "jt-upload://jt_a1b2c3d4...",
  "upload_id":    "jt_a1b2c3d4...",
  "filename":     "product-photo.jpg",
  "size":         15728640,
  "content_type": "image/jpeg",
  "type":         "image",
  "expires_in":   "24h"
}

Full example — Node.js

bash
const fs = require("fs");
const JT_KEY = "jt_YOUR_KEY";
const BASE   = "https://jeterdev.tools/api/v1";

async function uploadImage(filePath, filename) {
  const size = fs.statSync(filePath).size;

  // 1. Presign
  const { upload_id, upload_url } = await fetch(`${BASE}/uploads/presign`, {
    method:  "POST",
    headers: { "x-api-key": JT_KEY, "Content-Type": "application/json" },
    body:    JSON.stringify({ filename, content_type: "image/jpeg", size }),
  }).then(r => r.json());

  // 2. PUT directly to Firebase Storage
  await fetch(upload_url, {
    method:  "PUT",
    headers: { "Content-Type": "image/jpeg" },
    body:    fs.readFileSync(filePath),
  });
  // Empty response = success

  // 3. Confirm
  const { url } = await fetch(`${BASE}/uploads/confirm`, {
    method:  "POST",
    headers: { "x-api-key": JT_KEY, "Content-Type": "application/json" },
    body:    JSON.stringify({ upload_id }),
  }).then(r => r.json());

  return url; // "jt-upload://jt_..."
}

// Use in listings/create
const imageUrl = await uploadImage("./ai-product-15mb.jpg", "product.jpg");

await fetch(`${BASE}/listings/create`, {
  method:  "POST",
  headers: { "x-api-key": JT_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    state:   "draft",
    shops:   [{ shop_id: 61004439, shipping_profile_id: 289094606827, return_policy_id: 1396555302092 }],
    listing: { title: "AI Product", description: "...", taxonomy_id: 482, price: 29.99, quantity: 10, who_made: "i_did", when_made: "2020_2026" },
    images:  [{ url: imageUrl, rank: 1 }],
  }),
});

Use jt-upload:// in POST /listings/create

json
{
  "state": "publish",
  "shops": [...],
  "listing": { "title": "AI Generated Mug", ... },
  "images": [
    { "url": "jt-upload://jt_a1b2c3d4...", "rank": 1 },
    { "url": "jt-upload://jt_b2c3d4e5...", "rank": 2 }
  ]
}

Supported formats and limits

image
JPG, PNG, GIF, WebP
Max 100MB · No per-listing limit
video
MP4, MOV, MPEG
Max 100MB · Max 1 per listing
digital
PDF, ZIP, SVG, PNG
Max 100MB · Max 10 per listing
Upload URLs expire after 24 hours. If /listings/create fails and you retry after 24h, repeat the presign flow.

Listing Builder

Create Listing

POST /api/v1/listings/create

Single atomic call to create a listing across one or more shops.

Pro plan required.

Request body

json
{
  "state": "draft",
  "shops": [{
    "shop_id": 61004439,
    "shipping_profile_id": 289094606827,
    "return_policy_id":    1396555302092,
    "processing_profile_id": 1456101932490,
    "shop_section_id":     55308357,
    "price": 34.99
  }],
  "listing": {
    "title": "Vintage Band Tee", "description": "Premium cotton...",
    "listing_type": "physical", "taxonomy_id": 482,
    "price": 29.99, "quantity": 100,
    "who_made": "i_did", "when_made": "2020_2026",
    "tags": ["vintage tee", "band shirt"],
    "processing_min": 1, "processing_max": 3
  },
  "images": [
    { "url": "https://example.com/black-tee.jpg", "rank": 1 },
    { "url": "https://example.com/white-tee.jpg", "rank": 2 }
  ],
  "personalization": {
    "enabled": true, "is_required": false,
    "instructions": "Enter name (max 15 chars)", "max_chars": 15
  },
  "category_attributes": {
    "200":          { "value_ids": [1],    "values": ["Black"] },
    "325502675244": { "value_ids": [2668], "values": ["Short sleeve"] }
  },
  "variations": {
    "properties": [
      { "property_id": 200,         "name": "Color", "values": ["Black","White"] },
      { "property_id": 62809790533, "name": "Size", "scale_id": 17, "values": ["S","M","L"] }
    ],
    "offerings": [
      { "color": "Black", "size": "S", "price": 29.99, "quantity": 20, "sku": "BLK-S" },
      { "color": "Black", "size": "L", "price": 34.99, "quantity": 15, "sku": "BLK-L" },
      { "color": "White", "size": "M", "price": 29.99, "quantity": 25, "sku": "WHT-M" }
    ],
    "variation_images": { "property": "color", "mapping": { "Black": 0, "White": 1 } }
  }
}

Draft response

json
{
  "listing_pk":    1234567,
  "job_id":        "jt_aBcDeFgH...",
  "status":        "draft",
  "dashboard_url": "/dashboard#drafts/jt_..."
}

Publish/Active response

json
{
  "job_id":      "jt_aBcDeFgH...",
  "listing_pk":  1234567,
  "status":      "completed",
  "shops_count": 1,
  "poll_url":    "/api/v1/listings/create/jt_...",
  "results": [{
    "shop_id":    "61004439",
    "status":     "ok",
    "listing_id": 4501295417,
    "listing_url":"https://www.etsy.com/listing/4501295417",
    "currency_code": "USD", "price": 29.99,
    "images": [{"listing_image_id":5523110099001,"url_fullxfull":"...","rank":1}],
    "videos": [], "activated": false,
    "activation_cost_usd": 0, "warnings": []
  }]
}

processing_profile_id resolution

shops[0].processing_profile_id must be a real Etsy readiness state ID obtained from GET /stores/{shopId}/processing-profiles/live. The create endpoint resolves it in this order:

1
processing_profile_id supplied
Large integer (> 1000) from /processing-profiles/live. Used directly — no network call.
fast path
2
processing_profile_id absent
Calls GET /readiness-state-definitions. If processing_min/max are set, picks the matching profile. Otherwise takes the first.
one API call
3
No profiles on shop
Hard error — returns 400 with a descriptive message. Does not fall back to a hardcoded ID.
error

Breaking change from previous behavior

The previous implementation silently fell back to a hardcoded ID table when no active listings were found, producing IDs like 3 that are not valid for most shops. This is now a hard error. Always pass a real ID from /processing-profiles/live.

Validation error (400)

json
{
  "error": {
    "code": "VALIDATION_FAILED", "status": 400,
    "message": "Request validation failed.",
    "fields": {
      "listing.title": "Title is required",
      "shops[0].shipping_profile_id": "Required for physical listings"
    }
  }
}

Shop not connected (403)

json
{
  "error": {
    "code": "STORE_NOT_OWNED", "status": 403,
    "message": "The following shop IDs are not connected: 61004439",
    "hint": "Connect shops at jeterdev.tools/dashboard."
  }
}

Listing Builder

Job Poll

GET /api/v1/listings/create/{job_id}

Retrieve a listing creation job result. Jobs are retained for 24 hours — useful for retry logic or restoring queue state after a page reload.

bash
curl "https://jeterdev.tools/api/v1/listings/create/jt_aBcDeFgHiJkL..." \
  -H "x-api-key: jt_YOUR_KEY"

Response — same shape as create

json
{ "job_id": "jt_...", "listing_pk": 1234567, "status": "completed", "results": [...] }

Job expired or not found

json
{ "error": { "code": "JOB_NOT_FOUND", "status": 404, "message": "Job 'jt_...' not found. Jobs expire after 24 hours." } }

Notifications

Pushover Sale Notifications

Get instant push notifications on your phone every time a sale comes in. Uses Pushover — $5 one-time purchase. Works across all your connected shops automatically.

The Etsy webhook (https://www.jeterdev.tools/api/webhooks/etsy) is already registered. Just connect Pushover and sales flow through automatically for all shops.

Setup — 2 steps

1

Get Pushover credentials

Buy the app at pushover.net ($5 one-time). Copy your User Key. Create an Application and copy the App Token.

2

Connect to JeterDev Tools

POST /notifications/pushover with your keys. A test notification fires immediately on your phone.

POST /api/v1/notifications/pushover

bash
curl -X POST "https://jeterdev.tools/api/v1/notifications/pushover" \
  -H "x-api-key: jt_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "user_key":  "YOUR_PUSHOVER_USER_KEY",
    "app_token": "YOUR_PUSHOVER_APP_TOKEN"
  }'
json
{ "success": true, "message": "Pushover connected. A test notification was sent to your device." }

What the notification looks like

💰 New sale — BambiCraftCo

Order #3456789012

$31.99 USD · 2 items · New York

View order on Etsy →

GET — check status

bash
curl "https://jeterdev.tools/api/v1/notifications/pushover" -H "x-api-key: jt_YOUR_KEY"
json
{ "configured": true, "app_token": "abcd..." }

DELETE — disconnect

bash
curl -X DELETE "https://jeterdev.tools/api/v1/notifications/pushover" -H "x-api-key: jt_YOUR_KEY"

Stores

List Stores

GET /api/v1/stores

Returns all Etsy shops connected to your API key with their shop_id, connection status, and token validity.

bash
curl "https://jeterdev.tools/api/v1/stores" -H "x-api-key: jt_YOUR_KEY"
json
{
  "plan": "Pro",
  "remaining": 4892,
  "stores": [
    {
      "shopId": "61004439",
      "shopName": "MyCeramicsShop",
      "etsyUserId": "288401054",
      "connectedAt": "2026-05-09T12:00:00.000Z",
      "token_valid": true,
      "connection_expired": false
    },
    {
      "shopId": "72005550",
      "shopName": "MyVintageShop",
      "etsyUserId": "301882914",
      "connectedAt": "2026-05-10T08:30:00.000Z",
      "token_valid": false,
      "connection_expired": true
    }
  ]
}

⚠ Detecting expired connections

When connection_expired is true, the OAuth refresh token has failed — auto-refresh will not recover the shop. Show a reconnect CTA to your user. Attempting any authenticated call for that shop returns STORE_TOKEN_EXPIRED (403) until the shop is re-linked.

Stores

Sync

POST /api/v1/stores/{shopId}/sync

One-shot full shop data refresh. Returns shipping profiles, return policies, processing profiles, shop sections, and production partners in a single response.

Always hits Etsy fresh — no cache. Use this before listing creation to get all required IDs.
bash
curl -X POST "https://jeterdev.tools/api/v1/stores/61004439/sync" -H "x-api-key: jt_YOUR_KEY"
json
{
  "shop_id": "61004439", "synced_at": "2026-05-09T14:22:00.000Z",
  "shipping_profiles":   [{ "shipping_profile_id": 289094606827, "title": "US Standard" }],
  "return_policies":     [{ "return_policy_id": 1396555302092, "accepts_returns": true }],
  "processing_profiles": [
    {
      "readiness_state_id": 1456101932490,
      "readiness_state": "made_to_order",
      "min_processing_days": 1,
      "max_processing_days": 3,
      "processing_days_display_label": "1-3 days",
      "shop_id": 61004439
    }
  ],
  "shop_sections":       [{ "shop_section_id": 55308357, "title": "Mugs & Cups" }],
  "production_partners": []   // separate from processing_profiles
}

Stores

Live Profiles

Four endpoints that always hit Etsy fresh — never cached. Use them individually when you only need one data type. For all four at once use POST /stores/{shopId}/sync.

All /live endpoints require the shop to be connected and count against your daily rate limit.
GET/stores/{shopId}/shipping-profiles/live

All shipping profiles for the shop. Use shipping_profile_id when creating listings.

bash
curl "https://jeterdev.tools/api/v1/stores/61004439/shipping-profiles/live" -H "x-api-key: jt_YOUR_KEY"
GET/stores/{shopId}/return-policies/live

Shop return policies. Use return_policy_id when creating listings.

bash
curl "https://jeterdev.tools/api/v1/stores/61004439/return-policies/live" -H "x-api-key: jt_YOUR_KEY"
GET/stores/{shopId}/processing-profiles/liveupdated

Processing time profiles configured for the shop. Fetched directly from GET /v3/application/shops/{shop_id}/readiness-state-definitions — the official Etsy endpoint. Results exist independently of active listings.

Key field

Use readiness_state_id as shops[0].processing_profile_id when publishing listings. This is the real Etsy ID — not a derived value.

bash
curl "https://jeterdev.tools/api/v1/stores/61004439/processing-profiles/live" -H "x-api-key: jt_YOUR_KEY"
json
{
  "shop_id": "61004439",
  "fetched_at": "2026-05-20T18:00:00.000Z",
  "count": 2,
  "source": "readiness_state_definitions",
  "note": "readiness_state_id is the real Etsy ID. Pass it as shops[0].processing_profile_id when creating listings.",
  "processing_profiles": [
    {
      "readiness_state_id": 1456101932490,
      "readiness_state": "made_to_order",
      "min_processing_days": 1,
      "max_processing_days": 3,
      "processing_days_display_label": "1-3 days",
      "shop_id": 61004439
    },
    {
      "readiness_state_id": 1456101932491,
      "readiness_state": "ready_to_ship",
      "min_processing_days": 0,
      "max_processing_days": 0,
      "processing_days_display_label": "Ready to ship",
      "shop_id": 61004439
    }
  ]
}
Field
Type
Description
readiness_state_id
integer
Etsy's numeric ID for this profile. Use as processing_profile_id when creating a listing.
readiness_state
string
ready_to_ship or made_to_order
min_processing_days
integer
Minimum processing days (0 = same day / ready to ship)
max_processing_days
integer
Maximum processing days
processing_days_display_label
string
Etsy's translated display label, e.g. "1-3 days"
shop_id
integer
The owning shop
GET/stores/{shopId}/shop-sections/live

Shop sections (categories). Use shop_section_id when creating listings.

bash
curl "https://jeterdev.tools/api/v1/stores/61004439/shop-sections/live" -H "x-api-key: jt_YOUR_KEY"

Etsy Marketplace

listings

Read, create, update, and delete Etsy listings. Write endpoints require Pro plan and store connection.

Etsy Marketplace

shops

Shop info, listings, sections, reviews, orders, and transactions.

Etsy Marketplace

store-mgmt

Manage individual orders, shop sections, and store-level operations.

Etsy Marketplace

images

Listing images, digital files, and videos. Upload/delete require Pro plan and store connection.

Etsy Marketplace

properties

Listing-level and category-level variation properties and attributes.

Etsy Marketplace

shipping

Manage shipping profiles, destinations, and expedited options.

Etsy Marketplace

categories

Etsy seller taxonomy. Cache /categories/list — it rarely changes.

Etsy Marketplace

users

Etsy user profiles and saved addresses.

Etsy Marketplace

policies

Full CRUD for all shop policies — general, privacy, refund, shipping, and payment.