Rate Limits
The Xometry Developer API limits how many requests each partner can send per second. Limits keep the API responsive for everyone and protect against accidental request loops.
Most integrations that send requests one after another will never reach these limits. Integrations that send several requests simultaneously, such as fetching every job returned by a list call at once, are the most likely to be affected.
Current limits
| Request type | Methods | Limit |
|---|---|---|
| Read | GET | 2 requests per second |
| Write | POST, PATCH, DELETE | 2 requests per second |
Reads and writes are tracked in separate allowances. Read requests do not consume your write allowance, and writes do not consume your read allowance. This means an integration can read and write at the same time, as long as each type stays within its own limit.
Limits apply per partner, not per API key. If your organization uses multiple API keys, all of them draw from the same allowance.
Rate limit headers
Every response includes your current rate limit status, whether or not the request was throttled:
RateLimit-Policy: 2;w=1
RateLimit: limit=2, remaining=1, reset=1
| Header | Meaning |
|---|---|
RateLimit-Policy | The limit and its window in seconds. 2;w=1 means 2 requests per 1 second. |
RateLimit | limit is the maximum allowed, remaining is how many you have left in the current window, and reset is the seconds until the window resets. |
You can read remaining on successful responses to pace your requests before you ever receive a rejection.
When you exceed a limit
Requests over the limit are rejected with 429 Too Many Requests. The rejected request is not processed, so no data is read or changed.
HTTP/1.1 429 Too Many Requests
Content-Type: application/json; charset=utf-8
RateLimit-Policy: 2;w=1
RateLimit: limit=2, remaining=0, reset=1
Retry-After: 1{
"error": "Too many requests in 1 second. Please try again later",
"status": 429
}The Retry-After header tells you how many seconds to wait before sending the request again. This is the value your integration should use, rather than a fixed delay of your own.
Handling a 429 response
Treat 429 as a temporary condition rather than a failure. Wait for the duration in Retry-After, then send the request again.
async function requestWithRetry(url, options = {}, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
const retryAfter = Number(response.headers.get('Retry-After')) || 1;
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
}
throw new Error(`Request failed after ${maxAttempts} attempts: ${url}`);
}Avoid retrying immediately without a delay. Immediate retries will be rejected again and add load without making progress.
Tips for higher volume integrations
If your integration does run into rejections, these adjustments tend to help the most. You may already be doing some of them.
Avoid parallel fetches after a list call. If you call GET /v0/jobs and then request details or files for every job in the response at the same time, that burst is the most common cause of rejections. Queueing those requests so no more than 2 are in flight usually resolves it.
Space requests roughly 500 ms apart. Two requests per second works out to about one every half second. For simpler integrations, a small delay between calls avoids most rejections without any queue logic.
Re-fetch only what changed. If you poll a job list on a schedule and then re-request the same job IDs each cycle, many of those reads are redundant. Poll the list, then fetch details only for jobs whose status or timestamp has changed.
Request files one at a time. Thumbnails, drawings, part files, and STLs are each a separate read request. Pulling all of them for a line item at once can exceed the limit even when your overall volume is low.
Space out writes as well. Accepting offers, rejecting offers, advancing milestones, and updating line item statuses all draw from the write allowance. Sending them in a tight loop will reach the limit.
Reduce polling with webhooks
If you poll the API to detect changes, webhooks are usually a better fit. Webhooks notify your server when events occur in Workcenter, which removes the need for frequent polling and keeps your request volume well below the limits.
Updated 7 days ago
