SLO API

Connect your tools to your shop. Update products, manage drops, handle orders — from your own scripts, ChatGPT, or any tool you already use.

What can you do with it?

The SLO API gives you a single connection to everything in your shop. Instead of clicking through the dashboard, you can let a script or assistant do the work for you.

Products

Create, update, and remove products. Set prices, descriptions, and inventory — all at once or one at a time.

Drops

Set up new drops with dates, channels, and products. Open and close them when you're ready.

Orders

See incoming orders, confirm or cancel them, update fulfillment status as you pack and deliver.

Inventory

Update stock levels globally or per channel. Keep availability in sync without manual entry.

Channels

List your sales channels — delivery, pickup, wholesale — and manage which ones are active.

Everything works through one endpoint. Send a tool name and parameters, get structured data back. That's it.

Quick start

1

Get an API key

Shop admin → Apps → Create Key. Copy it — shown once.

2

Call a tool

curl -X POST https://slo.earth/api/agent \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"tool": "listProducts"}'
3

Get structured data back

{
  "ok": true,
  "result": {
    "products": [...],
    "total": 12
  }
}

Endpoint

POST https://slo.earth/api/agent
Content-Type: application/json
Authorization: Bearer sk_live_...

Request

{
  "tool": "toolName",
  "params": { ... }
}

Success

{
  "ok": true,
  "result": { ... }
}

Error

{
  "ok": false,
  "error": {
    "code": "not_found",
    "message": "Product with id 'abc' not found"
  }
}

Authentication

Bearer token in the Authorization header. Each key is scoped to one shop and can be revoked any time.

Authorization: Bearer sk_live_your_key_here

Tools

products

listProducts

List all products for your shop

Params

limitnumberMax products to return
offsetnumberNumber of products to skip
searchstringFilter by title (case-insensitive)
{
  "tool": "listProducts",
  "params": {}
}

{ products: Product[], total: number }

getProduct

Get a single product by ID

Params

productIdstringrequiredThe product _id
{
  "tool": "getProduct",
  "params": {
    "productId": "product_abc123"
  }
}

{ product: Product }

createProduct

Create a new product

Params

titlestringrequiredProduct title
descriptionstringProduct description
pricenumberPrice per unit (SEK)
inventoryTypestring"weight", "unit", or "volume" (default: weight)
unitTypestring"weight", "item", or "volume"
unitnumberSelling unit size in g/ml (default: 1000)
unitStepnumberIncrement size (default: 0.1 for bulk, 1 for piece)
hideFromStorefrontbooleanHide from public storefront
taxnumberTax rate as decimal (e.g. 0.12 for 12%)
hideFromCalendarbooleanHide from harvest calendar
{
  "tool": "createProduct",
  "params": {
    "title": "Organic Tomatoes"
  }
}

{ product: Product }

updateProduct

Update an existing product. Only send fields you want to change.

Params

productIdstringrequiredThe product _id
titlestringProduct title
descriptionstringProduct description
pricenumberPrice per unit (SEK)
inventoryTypestring"weight", "unit", or "volume"
unitTypestring"weight", "item", or "volume"
unitnumberSelling unit size in g/ml
unitStepnumberIncrement size
hideFromStorefrontbooleanHide from public storefront
taxnumberTax rate as decimal (e.g. 0.12 for 12%)
hideFromCalendarbooleanHide from harvest calendar
channelPricesstringJSON array of channel price overrides, e.g. [{"channelId":"abc","price":50}]
harvestStartstringHarvest start date (YYYY-MM-DD)
harvestEndstringHarvest end date (YYYY-MM-DD)
{
  "tool": "updateProduct",
  "params": {
    "productId": "product_abc123"
  }
}

{ product: Product }

batchUpdateProducts

Update multiple products at once. Send a JSON array of updates as a string.

Params

updatesstringrequiredJSON array of objects, each with productId and fields to update. Example: [{"productId":"abc","price":200},{"productId":"def","title":"New name"}]
{
  "tool": "batchUpdateProducts",
  "params": {
    "updates": "..."
  }
}

{ results: { productId, ok, title?, error? }[] }

deleteProduct

Delete a product

Params

productIdstringrequiredThe product _id
{
  "tool": "deleteProduct",
  "params": {
    "productId": "product_abc123"
  }
}

{ deleted: true }

uploadProductImage

Upload an image and set it as the product's primary image. Provide either imageUrl (public HTTPS link) or imageBase64 (base64-encoded image data). Use imageBase64 when the user uploads a file directly.

Params

productIdstringrequiredThe product _id
imageUrlstringPublic HTTPS URL of the image
imageBase64stringBase64-encoded image data (e.g. from a user-uploaded file)
mimeTypestringMIME type when using imageBase64 (e.g. "image/png", "image/jpeg"). Defaults to image/png.
{
  "tool": "uploadProductImage",
  "params": {
    "productId": "product_abc123"
  }
}

{ product: Product }

inventory

updateInventory

Update inventory for a product (global or per-channel)

Params

productIdstringrequiredThe product _id
availablenumberAvailable stock (grams for weight, count for piece)
channelIdstringOptional: update channel-specific inventory instead of global
{
  "tool": "updateInventory",
  "params": {
    "productId": "product_abc123"
  }
}

{ product: Product }

drops

listDrops

List drops for your shop

Params

statusstringFilter by status: "draft", "active", or "closed"
limitnumberMax drops to return
{
  "tool": "listDrops",
  "params": {}
}

{ drops: Drop[] }

getDrop

Get a single drop by ID

Params

dropIdstringrequiredThe drop _id
{
  "tool": "getDrop",
  "params": {
    "dropId": "drop_abc123"
  }
}

{ drop: Drop }

createDrop

Create a new drop (scheduled product release). Creates as draft with defaults, then applies any optional fields.

Params

channelIdsarrayrequiredArray of channel _ids to publish to
primaryChannelIdstringOptional primary channel _id
titlestringDrop title
descriptionstringDrop description
statusstring"draft", "active", or "closed" (default: draft)
startDatestringDrop start — ISO 8601 date string
endDatestringDrop end — ISO 8601 date string
deliveryDatestringDelivery date — ISO 8601 date string
quotanumberMaximum total orders for this drop
productsarrayArray of { productId, quota? } to add to the drop
{
  "tool": "createDrop",
  "params": {
    "channelIds": [
      "channel_abc123"
    ]
  }
}

{ drop: Drop }

updateDrop

Update an existing drop. Only send fields you want to change.

Params

dropIdstringrequiredThe drop _id
titlestringDrop title
descriptionstringDrop description
statusstring"draft", "active", or "closed"
startDatestringDrop start — ISO 8601 date string
endDatestringDrop end — ISO 8601 date string
deliveryDatestringDelivery date — ISO 8601 date string
quotanumberMaximum total orders for this drop
productsarrayReplace all products: array of { productId, quota? }
{
  "tool": "updateDrop",
  "params": {
    "dropId": "drop_abc123"
  }
}

{ drop: Drop }

deleteDrop

Delete a drop. Fails if the drop has associated orders.

Params

dropIdstringrequiredThe drop _id
{
  "tool": "deleteDrop",
  "params": {
    "dropId": "drop_abc123"
  }
}

{ deleted: true }

addProductsToDrop

Add products to an existing drop (appends, does not replace)

Params

dropIdstringrequiredThe drop _id
productsarrayrequiredArray of { productId, quota? } to add
{
  "tool": "addProductsToDrop",
  "params": {
    "dropId": "drop_abc123",
    "products": []
  }
}

{ drop: Drop }

removeProductFromDrop

Remove a product from a drop by its _key

Params

dropIdstringrequiredThe drop _id
productKeystringrequiredThe _key of the product entry in the drop
{
  "tool": "removeProductFromDrop",
  "params": {
    "dropId": "drop_abc123",
    "productKey": "..."
  }
}

{ drop: Drop }

orders

listOrders

List orders for your shop

Params

dropIdstringFilter by drop _id
statusstringFilter by status
limitnumberMax orders to return (default: 50)
offsetnumberNumber of orders to skip
{
  "tool": "listOrders",
  "params": {}
}

{ orders: Order[], total: number }

getOrder

Get a single order by ID

Params

orderIdstringrequiredThe order _id
{
  "tool": "getOrder",
  "params": {
    "orderId": "order_abc123"
  }
}

{ order: Order }

updateOrderStatus

Update the status of an order

Params

orderIdstringrequiredThe order _id
statusstringrequiredNew status (e.g. "confirmed", "delivered", "cancelled")
{
  "tool": "updateOrderStatus",
  "params": {
    "orderId": "order_abc123",
    "status": "active"
  }
}

{ order: Order }

channels

listChannels

List all channels for your shop

{
  "tool": "listChannels"
}

{ channels: Channel[] }

shop

getShop

Get your shop details

{
  "tool": "getShop"
}

{ shop: Shop }

meta

listTools

List all available API tools and their parameters

{
  "tool": "listTools"
}

{ tools: ToolDefinition[] }

Errors

unauthorized

Invalid or revoked API key

forbidden

Key doesn't have permission for this tool

not_found

Resource doesn't exist, or unknown tool name

validation

Missing or invalid params

rate_limit

Too many requests — 60/min per key

internal

Something went wrong on our end

Rate limits

60 requests per minute per key. Check the response headers:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1708617600

For agents

If you're an AI agent: call listTools first to discover every available operation and its parameter schema.

{ "tool": "listTools" }

The response includes name, description, category, params, and return shape — everything you need.