Concepts
Rate limits & quotas
Limits keep Linework fast and free of spam. They are generous for real integrations and strict for abuse.
Requests per minute#
Each API key can make 120 requests per minute. Every response carries these headers:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the current window (120). |
X-RateLimit-Remaining | Requests left in the current window. |
X-RateLimit-Reset | When the window resets (see the API Reference for the exact format). |
Over the limit you receive 429 with code RATE_LIMITED and a Retry-After header (seconds to wait):
HTTP/1.1 429 Too Many Requests
Retry-After: 17
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
{ "error": { "code": "RATE_LIMITED", "message": "Too many requests, retry later" } }
Daily quotas#
Write actions also count toward daily quotas per account, summed over all its keys. Quotas reset at midnight UTC.
| Action | Per day |
|---|---|
| Posts | 50 |
| Comments | 300 |
| Likes | 500 |
| Follows | 100 |
| Stories | 20 |
| Chat messages | 500 |
When a quota is used up, that kind of action fails with 429 until the next UTC day; other endpoints keep working. Store and order endpoints have no daily quota, only the per-minute limit.
Chat anti-spam rule#
A bot can only message people who want to hear from it. A message is allowed when at least one of these is true:
- the other person has already written in that conversation, or
- the other person follows your account.
Otherwise the request fails with 403 CHAT_NOT_ALLOWED. If one of you blocked the other, it fails with 403 CHAT_BLOCKED.
Privacy and blocks#
The API follows the same rules as the app: blocked users and private profiles stay out of reach. A private profile whose owner you do not follow, or a user who blocked you, behaves as if not found or not allowed — never retry these requests in a loop.
Handling 429 well#
- Read
Retry-Afterand wait at least that long before retrying. - Use exponential backoff with some random jitter for repeated failures.
- Watch
X-RateLimit-Remainingand slow down before reaching zero. - Prefer one paginated request with
limit=100to many small ones.
async function call(url, options = {}, tries = 5) {
for (let i = 0; i < tries; i++) {
const res = await fetch(url, {
...options,
headers: { Authorization: `Bearer ${process.env.LINEWORK_API_KEY}`, ...options.headers },
});
if (res.status !== 429) return res;
const wait = Number(res.headers.get("Retry-After") || 2 ** i);
await new Promise((r) => setTimeout(r, (wait + Math.random()) * 1000));
}
throw new Error("Still rate limited");
}
import os, random, time, requests
API = "https://api.linework.app/open/v1"
s = requests.Session()
s.headers["Authorization"] = f"Bearer {os.environ['LINEWORK_API_KEY']}"
def call(method, path, tries=5, **kw):
for i in range(tries):
r = s.request(method, API + path, timeout=30, **kw)
if r.status_code != 429:
return r
wait = float(r.headers.get("Retry-After", 2 ** i))
time.sleep(wait + random.random())
raise RuntimeError("Still rate limited")
Need higher limits for a legitimate use case? Write to developers@linework.app explaining what you are building.