Black Friday starts Fri, Nov 27 — 30% off
filagora.
FOR SELLERS

Seller API

Add and update your shop's listings from your own tools — printed pieces, digital 3D files, or both. Everything the listing form in Shop Manager does, in one request.

1. Your API key

In Shop Manager → Settings → API keys, write what the key is for and press Create key. The key starts with fgk_live_ and is shown once — copy it then. It belongs to the shop that is selected when you make it; if you run several shops, make one key in each. A shop can have five keys; Revoke stops one at once.

Send the key with every request, and keep it on a server — anyone who has it can list in your shop:

Authorization: Bearer fgk_live_…
Base address:  https://www.filagora.com/api/v1

2. Quick start

A printed piece

curl
curl https://www.filagora.com/api/v1/listings \
  -H "Authorization: Bearer $FILAGORA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "vase-001",
    "title": "Spiral Bud Vase, 15 cm",
    "description": "A twisted bud vase printed in matte PLA.\n\nWatertight with the glass insert.",
    "category": "vases-planters",
    "tags": ["vase", "spiral", "minimal"],
    "images": ["https://example.com/vase-front.jpg", "https://example.com/vase-side.jpg"],
    "physical": { "price": 24, "colors": ["White", "Sage"], "materials": ["PLA"], "leadDays": 3 },
    "designSource": "own",
    "madeBy": "shop",
    "standardsOk": true
  }'
Response
{
  "slug": "spiral-bud-vase-15-cm",
  "status": "active",
  "created": true,
  "publishAt": null,
  "url": "https://www.filagora.com/product/spiral-bud-vase-15-cm"
}

A digital file

The same listing with digital instead of physical. Buyers download the files right after they pay.

Body
{
  "externalId": "vase-001-file",
  "title": "Spiral Bud Vase — STL file",
  "description": "Print it yourself: 15 cm tall, no supports, about 3 hours.",
  "category": "vases-planters",
  "tags": ["vase", "stl", "vase mode"],
  "images": ["https://example.com/vase-front.jpg"],
  "digital": {
    "price": 4.5,
    "license": "personal",
    "files": [
      { "url": "https://example.com/files/spiral-vase.stl" },
      { "url": "https://example.com/files/print-guide.pdf" }
    ]
  },
  "designSource": "own",
  "madeBy": "shop",
  "standardsOk": true
}
Response
{
  "slug": "spiral-bud-vase-stl-file",
  "status": "active",
  "created": true,
  "url": "https://www.filagora.com/product/spiral-bud-vase-stl-file",
  "files": [
    { "name": "spiral-vase-1a2b3c4d.stl", "format": "stl", "size": 1840584, "status": "new" },
    { "name": "print-guide-9f8e7d6c.pdf", "format": "pdf", "size": 210233, "status": "new" }
  ]
}

Send physical and digital together and buyers choose: the printed piece, or the file.

3. Listing fields

FieldWhat to send
externalIdRequired. Your own id for the listing, up to 120 characters. Sending the same externalId again updates that listing.
titleRequired. 3–120 characters.
descriptionRequired. Up to 8,000 characters. The first line is the short summary; a blank line starts a new paragraph.
categoryRequired. One of the category slugs.
tagsUp to 13 words or short phrases buyers search for.
imagesRequired. 1–10 photos, the first is the cover. See Photos.
physicalThe printed piece: price in US dollars (1–100,000), colors (up to 12), materials, leadDays (days to make it, 1–60).
digitalThe file: price in US dollars (0–100,000), license "personal" or "commercial", includesProfile (true if print profiles are included), files. See Digital files.
designSourceRequired. "own" you designed it · "open" a credited remix of an openly licensed model · "licensed" you hold a licence to sell prints (printed only — files can't be resold).
designCreditRequired for open and licensed: the designer and the licence.
madeBy"shop" you print it · "partner" a production partner prints it (then productionPartner: who and where).
printShare · printTechprintShare "all" (default) or "most" of the piece is printed · printTech any of fdm resin powder metal other.
standardsOkRequired on a new listing: true confirms it meets the Maker Standards.
personalizationPrinted only: { "prompt": "Name to print", "max": 20, "required": true } with "personalizable": true.
status"paused" saves the listing without showing it yet.
publishAtA date and time (ISO 8601) to publish later, up to a year ahead.
videoA public mp4 or webm link, up to 50 MB — shown after the first photo.
printMinutes · filamentGramsShown on the listing when you send them.

Shipping prices and delivery times come from your shop's settings, not from each listing.

4. Photos

Each item in images can be any of these — mix them freely:

WayWrite it like
Link"https://…/front.jpg" or { "url": "https://…/front.jpg" }
Base64"data:image/jpeg;base64,/9j/4AAQ…" or { "name": "front.jpg", "base64": "/9j/4AAQ…" }
Multiparta file part named images (see multipart)
Upload{ "upload": "front-1a2b3c4d.jpg" } from a direct upload

JPG, PNG, WebP, GIF or AVIF, up to 15 MB each. We store a 2000 px copy and an 800 px copy for cards. A photo you send again — the same link, the same bytes or the same upload — isn't copied again.

5. Digital files

FormatForWe check
STLthe model (binary or ASCII)a real STL structure
3MFthe model, or a Bambu / Prusa projecta 3MF package with a model inside
OBJthe modelvertex data
STEP / STPCAD modelsthe ISO 10303-21 header
ZIPseveral parts in one downloadat least one STL, 3MF, OBJ or STEP inside, and no programs or scripts
PDFan assembly or print guidea real PDF — sent with a 3D file
TXTa readme, print settings, licenceplain UTF-8 text up to 2 MB — sent with a 3D file

Five ways to send a file

Each item in digital.files can be any of these:

WayWrite it likeBest for
Link"https://…/model.stl" or { "url": "…", "name": "model.stl" }files already online. Google Drive ("Anyone with the link"), Dropbox and GitHub share links work as they are.
Base64{ "name": "model.stl", "base64": "…" }small files your code already holds
Plain text{ "name": "model.stl", "text": "solid model…" }ASCII STL, OBJ, STEP and TXT
Multipartfile parts named filessending files from disk, e.g. curl -F
Upload{ "upload": "model-1a2b3c4d.stl" }files over ~3 MB — see direct upload

A link must return the file itself, not a web page about it. If a name has no extension, add "format": "stl".

Plain text: an ASCII STL and its print settings
"digital": {
  "price": 2,
  "files": [
    { "name": "tetra.stl", "text": "solid tetra\n facet normal 0 0 1\n  outer loop\n   vertex 0 0 0\n   vertex 10 0 0\n   vertex 0 10 0\n  endloop\n endfacet\nendsolid tetra\n" },
    { "name": "print-settings.txt", "text": "0.2 mm layers, 15% infill, no supports." }
  ]
}
Multipart: the listing in a field called “listing”, photos and files as parts
curl https://www.filagora.com/api/v1/listings \
  -H "Authorization: Bearer $FILAGORA_KEY" \
  -F 'listing={"externalId":"planter-01","title":"Hex Planter — 3MF and STL","description":"Two sizes in one project.","category":"vases-planters","digital":{"price":5},"designSource":"own","madeBy":"shop","standardsOk":true}' \
  -F "images=@planter.jpg" \
  -F "files=@planter.3mf" \
  -F "files=@planter.stl" \
  -F "files=@assembly.pdf"

6. Big files: direct upload

One request to /listings carries about 4 MB in total, and base64 makes a file a third bigger. For anything larger, use a link — or put the file straight into storage in three steps:

1 · Ask for an upload link
curl https://www.filagora.com/api/v1/files \
  -H "Authorization: Bearer $FILAGORA_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "dragon.stl", "size": 38200000 }'

{
  "upload": "dragon-1a2b3c4d.stl",
  "uploadUrl": "https://…",
  "method": "PUT",
  "headers": { "content-type": "application/octet-stream" },
  "maxBytes": 52428800,
  "expiresInSeconds": 7200
}
2 · PUT the file to uploadUrl
curl -X PUT "$UPLOAD_URL" -H "Content-Type: application/octet-stream" --data-binary @dragon.stl
3 · Name it in the listing
"digital": { "price": 12, "files": [ { "upload": "dragon-1a2b3c4d.stl" } ] }

GET /api/v1/files?upload=dragon-1a2b3c4d.stl tells you whether the file arrived and its size. Upload links last two hours. If the listing is refused — a brand name in the title, say — fix it and send it again with the same upload id. Photos work the same way: ask forcover.jpg and put { "upload": "cover-…jpg" } in images.

7. Updating a listing

8. Read, pause, remove

RequestDoes
GET /listings?externalId=…The listing: slug, status, title, images, physical (price, colors, materials), digital (price, formats, license, files).
PATCH /listings{ "externalId": "vase-001", "status": "paused" } — or "active" to show it again.
DELETE /listings?externalId=…Removes the listing. Past orders keep working; the same externalId sent later makes a new listing.
GET /shopWhich shop the key belongs to: name, slug, logo, status.
GET /categoriesThe category slugs. No key needed.
/giftsA free gift with a listing: POST { "productExternalId", "giftExternalId" }, GET lists them, DELETE ?productExternalId=… removes one. The gift must be one of your printed listings.

9. Errors and limits

Errors come back as { "error": "…" } with a message that says what to fix, and nothing from a refused request is kept:

StatusMeans
400Something in the request — the message names it.
401The key is missing, mistyped or revoked.
403The shop is suspended, the listing isn't one of this shop's, or the key can't do this.
404GET found no listing with that externalId, or the upload hasn't arrived yet.
413The request is over about 4 MB and was stopped before it reached us (the reply isn't JSON) — send big files as a link or a direct upload.
500Our side. Wait a moment and send it again; nothing half-saved is left behind.

10. Categories

categoryName
vases-plantersVases & Planters
lightingLamps & Lighting
desk-organizationDesk & Organization
home-decorHome Decor
gadgets-standsGadgets & Stands
toys-figurinesToys & Figurines
jewelry-wearablesJewelry & Wearables
kitchen-bathKitchen & Bath
miniatures-tabletopMiniatures & Tabletop
cosplay-propsCosplay & Props
parts-repairsParts & Repairs
printer-upgradesPrinter Upgrades
garden-outdoorGarden & Outdoor
petsPets
otherOther

11. Code samples

JavaScript (Node 18+): a file from disk, as base64
import { readFile } from "node:fs/promises";

const stl = await readFile("spiral-vase.stl");
const res = await fetch("https://www.filagora.com/api/v1/listings", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.FILAGORA_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    externalId: "vase-001-file",
    title: "Spiral Bud Vase — STL file",
    description: "Print it yourself: 15 cm tall, no supports.",
    category: "vases-planters",
    tags: ["vase", "stl"],
    images: ["https://example.com/vase-front.jpg"],
    digital: { price: 4.5, files: [{ name: "spiral-vase.stl", base64: stl.toString("base64") }] },
    designSource: "own", madeBy: "shop", standardsOk: true,
  }),
});
console.log(res.status, await res.json());
Python: multipart, a printed piece and its file in one listing
import json, os, requests

listing = {
    "externalId": "planter-01",
    "title": "Hex Planter",
    "description": "Printed in matte PLA, or print it yourself from the 3MF.",
    "category": "vases-planters",
    "tags": ["planter", "hexagon"],
    "physical": {"price": 22, "colors": ["Sage", "White"]},
    "digital": {"price": 5},
    "designSource": "own", "madeBy": "shop", "standardsOk": True,
}
with open("planter.jpg", "rb") as photo, open("planter.3mf", "rb") as model:
    r = requests.post(
        "https://www.filagora.com/api/v1/listings",
        headers={"Authorization": f"Bearer {os.environ['FILAGORA_KEY']}"},
        data={"listing": json.dumps(listing)},
        files=[("images", ("planter.jpg", photo)), ("files", ("planter.3mf", model))],
    )
print(r.status_code, r.json())
Python: a big file through a direct upload
import os, requests

H = {"Authorization": f"Bearer {os.environ['FILAGORA_KEY']}"}
up = requests.post("https://www.filagora.com/api/v1/files", headers=H, json={"name": "dragon.stl"}).json()
with open("dragon.stl", "rb") as f:
    requests.put(up["uploadUrl"], data=f, headers=up["headers"]).raise_for_status()

r = requests.post("https://www.filagora.com/api/v1/listings", headers=H, json={
    "externalId": "dragon-01",
    "title": "Articulated Dragon — print-in-place STL",
    "description": "Prints in one piece, no supports.",
    "category": "toys-figurines",
    "images": ["https://example.com/dragon.jpg"],
    "digital": {"price": 6, "files": [{"upload": up["upload"]}]},
    "designSource": "own", "madeBy": "shop", "standardsOk": True,
})
print(r.status_code, r.json())

Stuck on something? Use Live support at the bottom of any page, or write to us at support@filagora.com — send the request you made and the error you got.