FarmLoop Processing API
The Processing API lets your own software do what the FarmLoop web app does: send a sliced file plus your settings to our server and receive the FarmLoop-modified file back, ready to print with the detachment sequences injected. Your farm management software, a watch folder script or your own tools can run FarmLoop without anyone opening the app.
The Processing API is part of the FarmLoop Business plan. Upgrade under Subscription; the annual plan can also be paid by invoice.
What you need
Section titled “What you need”- A FarmLoop Business plan on the account you use at app.3d-farmers.com.
- An API key (
fl_…). Create one in the app under API Keys. Treat it like a password: it acts as your account. If it leaks, revoke it on the same page and create a new one.
The endpoint
Section titled “The endpoint”POST https://api.3d-farmers.com/api/v1/processAuthentication is a single header on every request:
X-API-Key: fl_your_key_hereA quick way to check your key works before sending files:
curl -sS https://api.3d-farmers.com/api/v1/process \ -H "X-API-Key: fl_your_key_here"GET on the same URL returns a machine-readable description of the API. If
you get JSON back (not a 401/403), you’re in.
Sending files
Section titled “Sending files”Send the sliced file as the multipart field file. To combine several plates
into one print job, send up to 10 files as the field files instead: each
is processed with the same settings and they are merged into one file, like
Download All in the app. All files must be sliced for the same printer
model.
- Accepted:
.gcode.3mf,.3mf(must be sliced, i.e. contain gcode),.gcode - Not accepted: binary G-code (
.bgcode), project files without gcode - Max size: 200 MB per request
Settings
Section titled “Settings”All settings are optional multipart fields:
| Field | Values | Default |
|---|---|---|
preset | name of a saved preset (see below) | none |
detachmentMode | push / lift | push |
stage | 1 / 2 | 1 |
cooldownType | temperature / time | temperature |
cooldownTemperature | °C, 20-100 | 30 |
cooldownTime | seconds, 0-86400 | 300 |
heatedBedTemperature | °C, 0-120 | taken from your slicer file |
zOffset | mm, -5 to 5 | taken from your slicer file |
pushHeight | mm, 0-300 | 5 |
useFanUpgrade | true / false | false |
copies | 1-99 | 1 |
copiesPerFile | one count per file, e.g. 2,1,3 | copies for every file |
naturalCooldownMinutes | 0-120 | 0 (off) |
triggerCalibrationMm | 0-3 | 0 (off) |
sweepRoutine | JSON, see below | the standard sweep |
copies repeats the print inside one gcode file with the ejection sequence
between loops, so the printer runs all copies unattended in a single job.
With several files, copiesPerFile sets the count per file in upload order.
Output size grows with each copy; requests whose expanded output would exceed
400 MB are rejected with 413.
The beta tools
Section titled “The beta tools”The three beta tools from the app’s Detachment Mode and Cooldown Settings are available over the API too:
naturalCooldownMinutesholds the part in the closed chamber with the fans off for this many minutes before the Stage 2 door opens. Stage 2, enclosed printers.triggerCalibrationMmpresses the Stage 2 kit switch this many mm deeper, for kits that do not trigger reliably. Stage 2.sweepRoutinereplaces the fixed push with your own routine: a list of pushes (each with its own height, speed and lanes) followed by up to five clearing passes.clearingscan be an empty list: the routine then ends after the pushes, and anything they miss stays on the plate. Push mode only. Between stages the head always goes up and back to its safe position, so a lower pass never runs into a part.
{ "pushes": [ { "xPositions": [], "speed": "slow", "heightMm": 60 }, { "xPositions": [128, 128], "speed": "medium", "heightMm": 20 } ], "clearings": [{ "xPositions": [], "speed": "fast" }]}xPositions lists the lanes in mm; an empty list means the whole plate, and
repeating a lane repeats the pass. speed is slow, medium or fast.
heightMm is optional and falls back to pushHeight.
Settings the chosen stage or mode ignores (for example trigger calibration on
Stage 1) are reported in X-FarmLoop-Warning, and the file is still
processed.
Presets
Section titled “Presets”A preset is a named set of settings. Save it once, then send only the file and
preset=<name>; any field you send as well overrides the preset for that
request. Changing a preset changes every farm script that uses it.
The quickest way to make one: tune a file in the app, then choose Save as API preset in the Ready to Process panel. The app saves the choices on screen (mode, stage, cooldown, fan upgrade, beta tools). Bed temperature and Z offset are read from each file, and push height is saved only if you set it yourself.
Your presets are listed on the API Keys page. Over the API:
# listcurl -sS https://api.3d-farmers.com/api/v1/presets -H "X-API-Key: $FARMLOOP_API_KEY"
# create or replacecurl -sS -X PUT https://api.3d-farmers.com/api/v1/presets/p1s-petg-stage2 \ -H "X-API-Key: $FARMLOOP_API_KEY" -H "Content-Type: application/json" \ -d '{"description": "PETG on the P1S row", "params": {"stage": 2, "cooldownTemperature": 28, "naturalCooldownMinutes": 5}}'
# deletecurl -sS -X DELETE https://api.3d-farmers.com/api/v1/presets/p1s-petg-stage2 -H "X-API-Key: $FARMLOOP_API_KEY"Preset names are 1-50 letters, numbers, spaces, dots, dashes and underscores, and are matched without regard to case. You can keep up to 50.
Examples
Section titled “Examples”# one file, with a presetcurl -sS https://api.3d-farmers.com/api/v1/process \ -H "X-API-Key: fl_your_key_here" \ -F "file=@benchy.gcode.3mf" \ -F "preset=p1s-petg-stage2" \ -OJ
# three plates merged into one job, 2 + 1 + 3 copiescurl -sS https://api.3d-farmers.com/api/v1/process \ -H "X-API-Key: fl_your_key_here" \ -F "files=@plate1.gcode.3mf" -F "files=@plate2.gcode.3mf" -F "files=@plate3.gcode.3mf" \ -F "copiesPerFile=2,1,3" -F "stage=2" \ -OJ-OJ saves the response using the server-suggested filename.
Python
Section titled “Python”import requestsfrom urllib.parse import unquote
resp = requests.post( "https://api.3d-farmers.com/api/v1/process", headers={"X-API-Key": "fl_your_key_here"}, files={"file": open("benchy.gcode.3mf", "rb")}, data={"preset": "p1s-petg-stage2"}, timeout=300,)resp.raise_for_status()
if resp.headers.get("X-FarmLoop-Warning"): print("Warning:", resp.headers["X-FarmLoop-Warning"])
out_name = unquote(resp.headers["X-FarmLoop-Output-Name"])with open(out_name, "wb") as f: f.write(resp.content)print("Saved", out_name, "| printer:", resp.headers["X-FarmLoop-Printer"])Node.js
Section titled “Node.js”const fs = require("node:fs");
const form = new FormData();form.append("file", new Blob([fs.readFileSync("benchy.gcode.3mf")]), "benchy.gcode.3mf");form.append("preset", "p1s-petg-stage2");
const resp = await fetch("https://api.3d-farmers.com/api/v1/process", { method: "POST", headers: { "X-API-Key": "fl_your_key_here" }, body: form,});if (!resp.ok) throw new Error(await resp.text());
const outName = decodeURIComponent(resp.headers.get("x-farmloop-output-name"));fs.writeFileSync(outName, Buffer.from(await resp.arrayBuffer()));The response
Section titled “The response”On success (200) the body is the modified file, plus these headers:
| Header | Meaning |
|---|---|
X-FarmLoop-Printer | Detected printer model (e.g. P1S, X1E, H2D) |
X-FarmLoop-Stage | Stage that was processed (1 or 2) |
X-FarmLoop-Files | Number of files in the job |
X-FarmLoop-Copies | Total copies baked into the returned file |
X-FarmLoop-Preset | The preset used, if any |
X-FarmLoop-Output-Name | Suggested filename, URL-encoded |
X-FarmLoop-Warning | Only present when something needs your attention - see below |
Stage 2 output filenames start with FL_S2_. Do not rename this away -
FarmLoop kits running Digital Mode (Full MQTT) arm themselves off that prefix.
If your software renames files before sending them to the printer, preserve
the prefix.
Warnings
Section titled “Warnings”Processing still succeeds, but X-FarmLoop-Warning is set when:
- the file was sliced with OrcaSlicer (not supported - re-slice with Bambu Studio v02.04+),
- the file carries an outdated Bambu Studio printer profile (pre-v02.04 - update Bambu Studio and re-slice with the stock profile),
- the filename suggests the file was already processed by FarmLoop (re-processing duplicates the injected sequences), or
- a setting does not apply to this stage, mode or printer and was ignored.
Surface these warnings to your users - a warned file may print without the detachment sequence working.
Errors and limits
Section titled “Errors and limits”| Status | Meaning |
|---|---|
400 | Invalid settings or unsupported file type - the message names each problem |
401 | Missing/invalid API key |
403 | No Business plan on the account, or no active subscription |
404 | Unknown preset name |
413 | File over 200 MB, or expanded output (files × copies) over 400 MB |
422 | Unreadable 3MF, no gcode inside, unknown printer type, model too tall for Stage 1, or files for different printers |
429 | Rate limit: max 10 requests per 5 minutes per key. Retry-After header tells you when to retry |
503 | Server at capacity (max 2 concurrent jobs). Retry after a few seconds |
Recommended client behavior: honor Retry-After on 429/503, and treat
4xx responses as permanent for that file/request (don’t blind-retry). A
merged request counts once against the rate limit, so batching plates with
files is the efficient way to send many.
Building with an AI agent?
Section titled “Building with an AI agent?”If you’re writing your integration with an AI coding assistant (Claude, Cursor, Copilot, ChatGPT, …), we maintain a machine-readable spec written specifically for agents - the complete API contract, validation ranges, required retry behavior, and reference implementations, with no marketing prose to wade through:
processing-api-for-ai-agents.md
How to use it:
-
Claude Code / CLI agents - save it into your project (e.g.
docs/farmloop-api.md) and reference it, or paste the URL into the chat:Terminal window curl -sSo docs/farmloop-api.md \https://help.3d-farmers.com/integrations/processing-api-for-ai-agents.md -
Chat assistants - paste the URL (or the file’s contents) into the conversation and ask the assistant to build against it.
The file instructs the agent to read your API key from the
FARMLOOP_API_KEY environment variable - set that before running generated
code, and never let the key be committed or logged.
Support
Section titled “Support”API questions, key rotation, or limit increases: contact FarmLoop support and mention “Processing API”.