Developers6 min readPro plan

The ResaleOS Developer API

ResaleOS gives you a clean REST API to read and manage your inventory, read your sales, and get notified the moment things change. Push products in from another system, keep an external catalog in sync, or build your own dashboard on top of your store. Here is everything you need to make your first call.

The Developer API is a Pro plan feature. On other plans the API key and webhook settings are visible but locked — upgrade from Settings → Plan to switch it on.

At a glance

What you can build with it

Manage products

List, create, update, and delete inventory — the same catalog you see in the app.

Read sales

Pull orders and line items from every channel and your POS, filtered by date, status, or customer.

Real-time webhooks

Get a signed HTTP callback the instant a product is created, updated, or deleted.

AI on create

Send just a photo URL and ResaleOS writes the title, brand, category, and attributes for you.

Per-item shipping policy

Pick the eBay policy or Etsy profile for one specific item at create time, overriding the channel default.

Step 1

Create an API key

Head to Settings → Integrations → Developer API and click Create API key. Your full key is shown once — copy it somewhere safe. After that ResaleOS only stores a hashed copy and shows the last four characters, so it can never be recovered. Keys look like this:

your API key
ros_live_a1b2c3d4e5f6.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
└── key id ──┘└──────────── secret ────────────┘

Each key is scoped to a single workspace. Lost a key, or someone left the team? Revoke it from the same screen — revoked keys stop working immediately, and you can issue as many as you like.

Step 2

Authenticate every request

The base URL is https://app.resaleos.co/api/v1. Send your key on every request — either as a bearer token or in the X-Api-Key header:

a first request
# List your two most recent active products
curl -s \
  -H "Authorization: Bearer ros_live_abc123..." \
  "https://app.resaleos.co/api/v1/products?status=active&limit=2"

# The X-Api-Key header works too
curl -s \
  -H "X-Api-Key: ros_live_abc123..." \
  "https://app.resaleos.co/api/v1/products"
Reference

Endpoints

Products support full read/write; sales are read-only. Every list endpoint is paginated and accepts filters like status, search, date ranges, and more. The full parameter list for each endpoint lives in-app under Settings → Integrations → Developer API.

Products

GET
/api/v1/productsList & filter products (paginated)
POST
/api/v1/productsCreate a product — AI fills in the rest from a photo
GET
/api/v1/products/{id}Fetch one product by its resaleosId
PATCH
/api/v1/products/{id}Update one or more fields
DELETE
/api/v1/products/{id}Permanently delete a product

Sales (read-only)

GET
/api/v1/salesList & filter sales / orders (paginated)
GET
/api/v1/sales/{id}Fetch one sale by its saleNumber

Shipping policies (read-only)

GET
/api/v1/shipping-policies?channel=ebayList your eBay shipping policies or Etsy shipping profiles, with their ids
Example

Create a product from a photo

Send an image URL and a price, and ResaleOS generates the title, brand, category, and attributes for you. Anything you include by hand takes precedence over the AI.

POST /api/v1/products
curl -s -X POST \
  -H "Authorization: Bearer ros_live_abc123..." \
  -H "Content-Type: application/json" \
  "https://app.resaleos.co/api/v1/products" \
  -d '{
    "price": 120,
    "cost": 35,
    "condition": "like_new",
    "status": "active",
    "images": ["https://cdn.example.com/item-front.jpg"],
    "inventory": [{ "location": "YOUR_LOCATION_ID", "quantity": { "available": 1 } }]
  }'
201 Created
{
  "product": {
    "resaleosId": "ROS-00451",
    "title": "Nike Air Max 90 White/Black Low-Top Sneaker",
    "brand": "Nike",
    "status": "active",
    "price": 120,
    "cost": 35,
    "condition": "like_new",
    "attributes": { "color": "White", "size": "10", "material": "Leather" },
    "createdAt": "2026-04-13T14:22:00.000Z"
  },
  "message": "Product created successfully"
}

Grab your location IDs from the same Developer API settings screen — they populate the inventory field.

Example

Set the shipping policy per item

Each sales channel has a default shipping policy, and you can add category rules on top of it. When you already know the right policy for a specific item — a heavier variant of an otherwise identical product, say — send shippingPolicyId on the channel. It applies to that item only and takes priority over both the channel default and any category rule. Supported on eBay (fulfillment policies) and Etsy (shipping profiles).

GET /api/v1/shipping-policies?channel=ebay
curl -s \
  -H "Authorization: Bearer ros_live_abc123..." \
  "https://app.resaleos.co/api/v1/shipping-policies?channel=ebay"

{
  "channel": "ebay",
  "marketplaceId": "EBAY_US",
  "policies": [
    { "id": "376434832022", "name": "Light-Magazine", "isDefault": true },
    { "id": "376434833022", "name": "Heavy-Magazine", "isDefault": false }
  ]
}
POST /api/v1/products
curl -s -X POST \
  -H "Authorization: Bearer ros_live_abc123..." \
  -H "Content-Type: application/json" \
  "https://app.resaleos.co/api/v1/products" \
  -d '{
    "title": "Motor Trend, May 1967",
    "sku": "MAG-1967-05",
    "price": 24.99,
    "status": "active",
    "channels": [
      { "platform": "storefront" },
      { "platform": "ebay", "shippingPolicyId": "376434833022" }
    ]
  }'

The same block works on PATCH /api/v1/products/{id} to change the policy later — the live listing is updated for you. Send "shippingPolicyId": null to clear the override and go back to the channel default. Every product response echoes the channel back with its current shippingPolicyId.

Sending channels replaces the product's channel selection, so include every channel the item should stay listed on.

Webhooks

Get notified in real time

Instead of polling, register one HTTPS endpoint under Settings → Integrations → Developer API and ResaleOS will POST to it whenever inventory changes. Failed deliveries are retried with backoff, and a persistently unreachable endpoint is auto-disabled so it never becomes a silent hole.

product.createdFires whenever a new product is added to your workspace.
product.updatedFires when any field on a product changes.
product.deletedFires when a product is permanently deleted.

Verify every payload

Each request carries an X-Resaleos-Signature header — an HMAC-SHA256 of the raw body, keyed with your endpoint signing secret. Recompute it and compare before trusting the event:

verify a webhook (Node.js)
import crypto from 'crypto';

function isValid(rawBody, signatureHeader, signingSecret) {
  const expected =
    'sha256=' +
    crypto.createHmac('sha256', signingSecret).update(rawBody).digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader),
  );
}

Requests also include X-Resaleos-Event and X-Resaleos-Timestamp. Rotate your signing secret any time from the settings screen.

Good to know

A few things worth knowing

Keys are hashed

We store only a hashed copy plus the last four characters. A lost key must be revoked and replaced — it can never be shown again.

Workspace-scoped

A key only ever touches the one workspace it was created in. Run multiple stores? Each needs its own key.

Writes sync everywhere

Update a product over the API and it re-syncs to your connected marketplaces and fires the matching webhook, just like an edit in the app.

Deletes are permanent

DELETE removes a product for good — there is no undo. Use status if you only want to archive it.

The complete reference — every query parameter, request field, and a live example response for each endpoint — is built into the app under Settings → Integrations → Developer API, right next to where you create your keys.

Ready to build on ResaleOS?

The Developer API is included on the Pro plan. Start your 3-day free trial on Pro — $1 for your first month — and create your first API key in minutes. Building something specific? We're happy to help on a quick call.