home.social

#api — Public Fediverse posts

Live and recent posts from across the Fediverse tagged #api, aggregated by home.social.

  1. One run, two inputs, the same amount of speech. Fetching audio out of a social video page was 82% of the bill and transcription was 16% — plus what a recognition segment does to your caption file once the speaker stops talking in bursts.#python #api #video #webscraping #software #coding #development #engineering #inclusive #community
    Subtitling a 65-Second TikTok Cost $0.11. The Same Minute as a File Cost $0.011
  2. Introducing OpenFeed 🇪🇺

    An EU-run social network with an open JSON API. Our own app is live, and anyone can build theirs on the same network.

    • Public feed, open spaces, invite-only private spaces
    • EU company, EU hosting, no ads, no profiling
    • One account for every app built on it

    Public beta is live. Claim your handle:

    openfeed.eu

    Building apps? The API is open, come build with us.

    #OpenFeed #DigitalSovereignty #BuyEuropean #EUTech #Privacy #SocialMedia #API

  3. Introducing OpenFeed 🇪🇺

    An EU-run social network with an open JSON API. Our own app is live, and anyone can build theirs on the same network.

    • Public feed, open spaces, invite-only private spaces
    • EU company, EU hosting, no ads, no profiling
    • One account for every app built on it

    Public beta is live. Claim your handle:

    openfeed.eu

    Building apps? The API is open, come build with us.

    #OpenFeed #DigitalSovereignty #BuyEuropean #EUTech #Privacy #SocialMedia #API

  4. Why does a truncated model answer look exactly like a finished one when the only thing you check is the HTTP status code?

    That question cost me most of a weekend. I had wired a small summarizer to a streaming endpoint, watched it print a paragraph, and shipped it. Two days of field notes later, I had learned that "HTTP 200" tells you nothing about whether the answer actually completed, and that my parser was happily reporting success on streams that never sent a terminator.

    Here is what I tried, what broke, and the probe harness I now run before trusting any streaming endpoint.

    The symptom: a paragraph that stopped mid-thought


    In my run, the response body ended cleanly at the socket level, the status line said 200, and my client wrote whatever it had buffered. Nothing raised. The output simply stopped mid-sentence, which readers interpret as a model being terse rather than a transport being over. Because I was printing tokens as they arrived, I never compared what I received against what the protocol promised me.

    That is the trap with streaming: the happy path and the failure path share the same first N bytes. If you only assert on status codes and on the existence of output, both paths pass.

    What I instrumented instead of what I assumed


    I stopped eyeballing output and wrote a probe that records protocol facts rather than vibes. It reads the response line by line, assembles SSE frames, and records four things per request: time to first byte, whether a finish_reason appeared in any JSON payload, whether the [DONE] sentinel arrived, and how the socket ended.

    # stream_probe.py — stdlib only, so it runs anywhere
    import json, sys, time, urllib.request

    def parse_frame(lines):
    """SSE frames are newline-delimited; data may span several lines."""
    payload =
    [] for line in lines:
    if line.startswith(":"):
    continue # comment / keep-alive
    if line.startswith("data:"):
    payload.append(line[5:].lstrip(" "))
    if not payload:
    return None, False
    joined = "\n".join(payload).strip()
    if joined == "[DONE]":
    return None, True
    try:
    return json.loads(joined), False
    except json.JSONDecodeError:
    return {"_unparsed": joined}, False

    def find_finish_reason(obj):
    if isinstance(obj, dict):
    if obj.get("finish_reason"):
    return obj["finish_reason"]
    for v in obj.values():
    hit = find_finish_reason(v)
    if hit:
    return hit
    elif isinstance(obj, list):
    for v in obj:
    hit = find_finish_reason(v)
    if hit:
    return hit
    return None

    def probe(url, payload, headers, read_timeout):
    rec = {"ttfb_s": None, "frames": 0, "finish_reason": None,
    "done_sentinel": False, "unparsed_frames": 0, "error": None}
    req = urllib.request.Request(
    url, data=json.dumps(payload).encode(), headers=headers, method="POST")
    started = time.monotonic()
    frame_lines =
    [] try:
    with urllib.request.urlopen(req, timeout=read_timeout) as resp:
    for raw in resp:
    if rec["ttfb_s"] is None:
    rec["ttfb_s"] = round(time.monotonic() - started, 3)
    line = raw.decode("utf-8", "replace").rstrip("\r\n")
    if line:
    frame_lines.append(line)
    continue
    obj, done = parse_frame(frame_lines)
    frame_lines =
    [] if done:
    rec["done_sentinel"] = True
    if obj is not None:
    rec["frames"] += 1
    if "_unparsed" in obj:
    rec["unparsed_frames"] += 1
    else:
    rec["finish_reason"] = rec["finish_reason"] or find_finish_reason(obj)
    except Exception as exc: # read timeouts land here on purpose
    rec["error"] = f"{type(exc).__name__}: {exc}"
    rec["elapsed_s"] = round(time.monotonic() - started, 3)
    return rec

    if __name__ == "__main__":
    url = sys.argv
    [1] body = json.loads(sys.argv[2])
    hdrs = json.loads(sys.argv[3])
    print(json.dumps(probe(url, body, hdrs, read_timeout=20.0), indent=2))

    Then a soak loop, because one clean request proves almost nothing:

    for i in $(seq 1 20); do
    python stream_probe.py "$URL" "$BODY" "$HEADERS" | jq -c '{ttfb_s,frames,finish_reason,done_sentinel,unparsed_frames,error}'
    done | tee soak.jsonl
    jq -s 'group_by(.finish_reason) | map({reason: .[0].finish_reason, n: length})' soak.jsonl

    The four endings the harness separates


    Once I classified results instead of staring at them, the ambiguity collapsed into a small set of observable outcomes:

    1. Clean finish. A finish_reason arrived and [DONE] followed it, so the answer is complete and my parser can trust the buffer.
    2. Reason without sentinel. The payload carried a finish_reason but the stream closed before [DONE], which suggests a proxy that buffers or cuts the tail frame.
    3. Sentinel without reason. [DONE] arrived early, which usually means the server truncated generation server-side and reported nothing useful about why.
    4. Neither. The socket closed with a partial sentence and no metadata, which is the case that burned me, and the only honest response is to mark the answer as incomplete and retry or surface it to the caller.

    Only case one deserves a green check. Everything else should set an incomplete flag on the record you store, because a truncated summary that silently enters your database is worse than a visible error.

    Where a free server and free models actually fit


    I run this probe from a throwaway box precisely because I want the transport to be the boring part. MonkeyCode offers free model access and a free server option, which makes it a reasonable place to park a short soak loop like the one above while you are still deciding whether an endpoint deserves production traffic.

    Disclosure: This article was prepared as part of MonkeyCode's product outreach.

    The important discipline is not to treat "free" as "verified". Whatever endpoint you point the probe at, read that provider's current limits and terms yourself on the day you run it, because quotas, model availability, and server lifetimes change and any number I copied here would be stale by the time you read it.

    A decision table I now keep in the repo

    Signal from the probeWhat I do nextfinish_reason plus [DONE] on 20/20 runsWire it into the pipeline and keep the probe as a canaryOccasional missing [DONE], reason presentParse per frame, tolerate the tail, log a counterFrequent missing finish_reasonTreat every response as untrusted text, never as finalRead timeouts clustered at a fixed secondSuspect an idle proxy timeout, not model slownessunparsed_frames above zeroFix framing first; never debug content on a broken parser

    What I would repeat and what I would skip


    I would repeat the soak loop and the classification, because those two together turned a spooky intermittent bug into a checklist. I would skip the hours I spent reading model output for clues about whether the generation was "good", since the transport was broken the whole time and no amount of reading prose would have revealed that.

    I would also repeat running the probe from a machine I do not care about. Wrapping the read in a hard timeout and letting exceptions land in the record, rather than crashing the loop, is what made the soak results readable.

    Limitations and who should not bother


    This workflow is for streaming text responses over SSE; if your SDK already exposes a completion flag you trust, a hand-rolled probe is mostly redundant. It also cannot tell you why a provider cut a stream, only that the frames disagree with each other, so pair it with the provider's own logs when you escalate. And if your workload is batch and non-streaming, a single content-length check will beat all of this.

    If you keep one habit from these field notes, make it this: assert on the terminator, not on the status code. A stream that never says goodbye is not a finished answer, no matter how confident the first paragraph looks.#python #api #debugging #testing #software #coding #development #engineering #inclusive #community
    48-Hour Field Notes: My Stream Ended Without [DONE] and the Client Called It Success

  5. RT @cheatyyyy: DeepSeek hat seine eigene Suchmaschine mit umfangreicher Filterung entwickelt, um modernes SEO/GEO-Spam zu vermeiden, und speist damit seine neuen Such- und Fetch-APIs! Jede API kostet $0,75 pro 1.000 erfolgreiche Anfragen, kostenlos wenn Sie DeepSeek in Claude Code, Codex oder DeepSeek Harness nutzen bis November 1.

    mehr auf Arint.info

    #API #DeepSeek #KünstlicheIntelligenz #SEO #Suchmaschine #Technologie #arint_info

    https://x.com/cheatyyyy/status/2111372051110125614

  6. Found in my Snaps: MoroccoAPI. From the GitHub page: “MoroccoAPI is a community-driven, open-source project that turns reusable Moroccan public datasets into consistent, documented, and versioned APIs. Public information is often distributed across spreadsheets, documents, portals, and incompatible schemas. MoroccoAPI aims to make approved open datasets easier to discover and use while […]

    https://rbfirehose.com/2026/10/18/informational-datasets-gathered-in-one-place-moroccoapi/
  7. Many desktop AI tools ship provider keys to the client. Here's why Cernalo keeps them server-side, how requests are routed with fallbacks, and what that costs.#ai #security #architecture #api #software #coding #development #engineering #inclusive #community
    Why Our AI Desktop Assistant Never Stores Model API Keys on Your Computer
  8. 🌐 Want to build a killer social wall? With the Walls.io API, pull posts from EVERY platform and style 'em your way! 💻✨ Are you ready to take your feed to the next level? 👉 blog.walls.io/product/how-to-b

  9. MCP vs API explained with real tests: same service as REST and MCP, 76 µs vs 424 µs per call, 14x throughput gap, and what tool definitions cost in tokens.#mcp #ai #api #webdev #software #coding #development #engineering #inclusive #community
    MCP vs API: When You Need Which, With Real Benchmarks
  10. A beginner-friendly guide to fetch(), async/await, response.ok, timeouts, and JSON parsing, with working examples and the mistakes that trip people up.#javascript #webdev #beginners #api #software #coding #development #engineering #inclusive #community
    How to Call an API with JavaScript fetch() and Handle Errors Properly
  11. We probed 68 live x402 endpoints on Base to answer one question: can a stock buyer client actually pay this? Results, failure classes, and a runnable checklist for your own endpoint.#ai #api #crypto #webdev #software #coding #development #engineering #inclusive #community
    What 68 x402 endpoints taught us about agent-payability
  12. Stop Blaming the Model: A Failure-Taxonomy Probe for Agent Runs on Free Tiers


    Your agent died at 2 a.m. Was the model bad? Probably not.

    Most failed runs I see are misattributed. The model gets blamed for transport, quota, or a bad contract check.

    Here is a short myth-busting FAQ. It ends with one probe that sorts failures into five layers.

    Myth 1: A 200 response means the request worked


    A status code describes transport only. It says nothing about usable output.

    You can get 200 with finish_reason: "length". You can get 200 with a refusal. You can get 200 with JSON that parses but misses a required field.

    Is that a successful unit of work? No. It is a received but rejected artifact.

    So define acceptance in code. Parse it, validate it, hash it. Otherwise you are counting receipts, not results.

    Myth 2: Retries are free


    Retries are cheap on the network side. They are expensive on the side-effect side.

    Retry a read and nothing changes. Retry a tool call that writes a row and now you have two rows.

    That is not a model problem. That is a missing idempotency key.

    My rule: every attempt carries a stable Idempotency-Key. Derive it from the task id, never from the attempt counter.

    Myth 3: Latency numbers tell you which model to pick


    Median latency answers one narrow question. How fast is a warm path?

    That is rarely your user's path. Free-tier hosts often show two clusters: warm and cold.

    Measure time-to-accepted-artifact instead. That number includes your retries and your validator.

    Two models with identical token speed can land far apart here. One simply fails validation more often.

    Myth 4: A bad run means a bad model


    Attribute before you switch vendors. Ask which layer failed, not which model.

    • Transport: timeout, DNS failure, connection reset.
    • Quota: 429, 402, or an explicit rate-limit body.
    • Contract: schema mismatch, truncation, refusal, empty content.
    • Tool: your function raised, or returned junk.
    • Task: the prompt asked for something impossible.

    Only the last two are usually your prompt's fault. The contract layer is often your own validator.

    The probe: one script, five layers


    This script uses the Python standard library only. It records enough to classify every attempt.

    I have not run it against your endpoint. Treat any output as illustrative, not as a benchmark.

    # probe.py - failure-taxonomy probe (illustrative, unexecuted here)
    import json, os, time, urllib.request, urllib.error, hashlib

    BASE = os.environ["BASE_URL"] # OpenAI-compatible base, e.g. https://host/v1
    MODEL = os.environ["MODEL"]
    KEY = os.environ.get("API_KEY", "")
    RUNS = int(os.environ.get("RUNS", "8"))
    PROMPT = os.environ.get("PROMPT", 'Return JSON: {"ok": true}')

    def call(idem):
    body = json.dumps({
    "model": MODEL,
    "messages": [{"role": "user", "content": PROMPT}],
    "temperature": 0,
    "max_tokens": 256,
    }).encode()
    url = BASE.rstrip("/") + "/chat/completions"
    req = urllib.request.Request(url, data=body, method="POST")
    req.add_header("Content-Type", "application/json")
    req.add_header("Idempotency-Key", idem)
    if KEY:
    req.add_header("Authorization", "Bearer " + KEY)
    t0 = time.monotonic()
    try:
    with urllib.request.urlopen(req, timeout=120) as r:
    return r.status, r.read(), (time.monotonic() - t0) * 1000, ""
    except urllib.error.HTTPError as e:
    return e.code, e.read(), (time.monotonic() - t0) * 1000, "http_error"
    except Exception as e:
    return None, b"", (time.monotonic() - t0) * 1000, type(e).__name__

    def classify(status, schema_ok):
    if status is None: return "transport"
    if status == 429: return "quota"
    if status in (401, 403): return "auth"
    if status and status >= 500: return "upstream"
    if status != 200: return "contract"
    if not schema_ok: return "contract"
    return "ok"

    task_id = os.environ.get("TASK_ID", "probe-1")
    ledger =

    []for attempt in range(1, RUNS + 1):
    idem = task_id # stable across retries, on purpose
    status, raw, ms, err = call(idem)
    schema_ok, reason = False, ""
    try:
    payload = json.loads(raw.decode() or "{}")
    choice = payload["choices"]
    [0] reason = choice.get("finish_reason", "")
    json.loads(choice["message"]["content"]) # your real contract check goes here
    schema_ok = True
    except Exception as e:
    reason = reason or type(e).__name__
    ledger.append({
    "attempt": attempt, "idem": idem, "status": status,
    "ms": round(ms), "bytes": len(raw), "finish": reason,
    "err": err,
    "sha256": hashlib.sha256(raw).hexdigest()[:12],
    "layer": classify(status, schema_ok),
    })

    for row in ledger:
    print(json.dumps(row))

    print("--- layer histogram ---")
    for layer in sorted({r["layer"] for r in ledger}):
    print(layer, sum(1 for r in ledger if r["layer"] == layer))

    Run it with three environment variables and a repeat count:

    BASE_URL=https://your-endpoint/v1 MODEL=your-model RUNS=12 python3 probe.py

    The ledger is the whole point. One row equals one attempt with one label.

    How to read the ledger


    • Many contract rows with finish: "length"? Raise the output budget, or shrink the ask.
    • transport rows at fixed intervals? Suspect an idle timeout, not the model.
    • quota mixed with ok? You need pacing, not a new vendor.
    • Identical sha256 values at temperature: 0? Cache them, do not re-run.
    • Zero ok rows and clean transport? Your contract check is probably wrong.

    Does reading the labels change your conclusion? It usually changes mine.

    A decision table you can argue with

    Dominant layerFirst fixDo not dotransporttimeout plus backoffprompt tuningquotaconcurrency cap, queuea second accountcontractschema, budget, validatorvendor switchingtoolidempotency, typed errorsa longer prompttaskrewrite the askmore retries


    Keep this table next to the script. It ends the "which model is best" debate quickly.

    The debugging workflow, in order


    1. Reproduce with RUNS=1 and a fixed prompt.
    2. Read the response body, not just the status.
    3. Log finish_reason and output byte count.
    4. Replace my contract check with your real one.
    5. Re-run with RUNS=12 and read the histogram.
    6. Fix only the top layer. Then measure again.
    7. Keep the ledger as a regression fixture.

    Steps five and six get skipped all the time. That is where the time is saved.

    Where a free tier actually fits


    I would run this probe before trusting any free endpoint with a batch job.

    That is the useful part of free model access plus a free server option. You get a place to run the probe before provisioning anything.

    Disclosure: This article was prepared as part of MonkeyCode's product outreach.

    MonkeyCode lists free model access and a free server option. Those two claims are operator-supplied, and I am not extending them.

    I will not guess at model names, quota, hardware, or duration. Measure those with the script above, then decide.

    Use the free tier for the probe and the small jobs. Keep the layer table honest either way.

    Limitations, and who should skip this


    • The script assumes an OpenAI-compatible chat endpoint. Yours may not be.
    • It does not test concurrency. Add a parallel runner if that is your risk.
    • It cannot prove a tier stays free. Re-run it on a schedule instead.
    • It says nothing about output quality. That needs a separate eval.
    • The Idempotency-Key header only helps if your server honors it.

    Skip this if you already trace each attempt with layer labels. Skip it for a single one-off call.

    Also skip it if you need throughput guarantees today. A probe measures, it does not promise.

    The question I would ask first


    Next time an agent run fails, ask: which layer failed? Not: which model should I try?

    Write the layer into your logs and your error messages. The argument gets shorter every time.#ai #testing #python #api #software #coding #development #engineering #inclusive #community
    Stop Blaming the Model: A Failure-Taxonomy Probe for Agent Runs on Free Tiers

  13. A 402 response is not just a price. In the extensions.bazaar block it can also carry an input example and an output example — a sample request and a sample answer. Directory crawlers index them, and agents use them to decide whether an endpoint does what they need before they pay.

    That makes an example a claim. If the sample answer disagrees with what the handler actually returns, the agent has three bad options: conclude the endpoint is broken, conclude the platform is lying, or spend money to find out. None of those are good, and all of them are avoidable if the example is true.

    We replayed ours to see how many were.

    Method


    For every service with a published output example (1,602 of them — one endpoint's correct answer is an empty set and was excluded from this population), we took the published input, sent it to the handler that serves it over loopback, and compared the real response against the advertised example with a recursive key-subset check. Arrays are compared strictly; nested objects allow the response to carry extra keys but not to drop an advertised one.

    Comparing once is not enough, because a large share of endpoints are supposed to vary: prices, block heights, AI text, random values. A disagreement there is not a defect. So every mismatch was replayed two more times with the same input. If the three real responses were byte-identical and still disagreed with the example, that is a stable difference — the kind a user would hit every single time.

    Results

    BucketCountMeaningMATCH1,444example equals the responseVARYING141the response itself changes run to runSTABLE-DIFF17same response every time, still disagreesEXEMPT8a field that is a timestamp by definition


    The 17 stable differences broke down cleanly:

    • 9 time-derived. "Days since 2026-01-01" was 284 when the example was captured and 289 when it was replayed. "Days remaining" on a certificate only moves one way. These examples are snapshots and will drift every day.
    • 7 upstream data that changes daily or hourly. FX rates, funding-rate windows, news feeds, prediction-market volumes, a live bounty list.
    • 1 real defect. An endpoint that returns DNS record sets was advertising one ordering of the A records and, half the time, serving the other.


    The defect: the DNS resolver round-robins


    Ask a resolver the same question twice and you get the same set of records in a different order. That is normal DNS behaviour. It becomes a bug the moment a handler passes the array through unchanged while the 402 advertises a fixed ordering: an agent that calls twice and diffs the answers sees a change that never happened, and an agent that pattern-matches against the example is told its correct answer is wrong.

    The fix is small — sort at the boundary, one shared helper, no field added:

    const { sortDns } = require('../lib/dnssort');
    // ...
    result[tt] = sortDns(records.map(format));

    Same record set, one deterministic answer. We verified it by calling the same endpoint four times and comparing response bytes: identical.

    The more interesting mistake was ours


    That was not the first pass. An earlier sweep had already found the ordering problem in 18 other handlers and fixed them. This one was missed — and the reason is worth writing down, because it is a mistake that looks like success.

    The fix population had been drawn from that day's mismatch report: whichever endpoints happened to disagree with their example were inspected, and the ones with the same signature were fixed. But the ordering cycles. On the day of the sweep, the resolver happened to return the A records in the same order the example advertised. So the endpoint did not appear in the mismatch report, was not in the fix population, and kept the defect — while every guard printed clean.

    A defect population drawn from the sample that happened to fail is not the population. The population is every object that can have the defect.


    The correct population is source-derived: every deployed handler that requires DNS and calls .resolve*() or .reverse(). That is 21 files here, not 18, and it is derived mechanically instead of from a bucket of symptoms. The same pass also caught a handler that joined TXT records before anyone looked at their order.

    We now run that census daily against the deployed bytes. It enforces three things: every DNS-serving handler must sort, self-sort, or reduce the array to a scalar; a handler not on the table is a failure; and a table row with no matching handler is also a failure, because a policy row that nothing enforces is worse than no row at all.

    What this does and does not fix


    The 17 stable differences were not all bugs, and we did not "fix" them by deleting the examples. Volatile endpoints still advertise a snapshot — that is the honest thing to publish, and the directory expects a sample. What changed is that we now know exactly which examples are snapshots and which are claims, and a replayed sample that contradicts its handler is a red light rather than a shrug.

    The one real defect is fixed. The population it hid in is now enumerated from source and checked every day.

    All numbers in this post are from a single replay run on 2026-10-17 against the deployed handler bytes; the method and per-endpoint buckets are in the repository's artifacts directory.#ai #webdev #crypto #api #software #coding #development #engineering #inclusive #community
    Your Discovery Example Is a Promise — We Replayed 1,602 of Ours to Check

  14. Every Shopify store publishes its catalogue as JSON, and the obvious freshness field in it is the wrong one. Four stores measured on 17 October 2026 show published_at inflating a dead catalogue into 404 fresh products.#webscraping #ecommerce #api #node #software #coding #development #engineering #inclusive #community
    398 of 692 Products Were Published in One Afternoon. Zero Were Created in 90 Days
  15. Data from a daily scan of 50,000 paid x402 and MPP endpoints - 93% payable, one seller holds 41%, Base carries 97%, the median price is $0.01, and the most common seller mistakes with their fixes.#x402 #ai #api #webdev #software #coding #development #engineering #inclusive #community
    We check 50,000 paid x402 endpoints every day. Here's what works and what breaks.
  16. When you answer someone's question on a forum, the date of the post tells you less than you think.

    A founder told me their replies stopped working after day 5 to 7. By then the person has picked a tool or moved on, and your answer lands in an empty room.

    A better signal: did the author reply to anyone in their own thread in the last 24 hours? If yes, they're still reading. Your answer gets seen today.

    Three platforms give you that for free, without a key: DEV, Hacker News and Discourse forums. Here's the whole thing, about 40 lines of Node 18+.

    The shared part
    Every platform returns replies as a tree. Normalize each one to { author, at, children }, then walk it:

    // Latest reply written by author anywhere in the tree (ms), or null.
    function lastReplyBy(nodes, author) {
    let last = null;
    const walk = (items) => {
    for (const n of items) {
    if (n.author?.toLowerCase() === author.toLowerCase() && n.at > (last ?? 0)) last = n.at;
    walk(n.children);
    }
    };
    walk(nodes);
    return last;
    }

    const isAlive = (at, hours = 24) => at !== null && Date.now() - at <= hours * 3_600_000;
    DEV
    The article endpoint gives you the id, the comments endpoint gives you the full tree:

    async function devto(user, slug) {
    const article = await (await fetch(https://dev.to/api/articles/${user}/${slug})).json();
    const raw = await (await fetch(https://dev.to/api/comments?a_id=${article.id})).json();
    const map = (cs) =>
    cs.map((c) => ({ author: c.user?.username, at: Date.parse(c.created_at), children: map(c.children ?? []) }));
    return lastReplyBy(map(raw), user);
    }
    Hacker News
    The Algolia API returns the whole thread in one call. Times are in seconds, and deleted comments have no author (the ?. above handles that):

    async function hn(id) {
    const item = await (await fetch(https://hn.algolia.com/api/v1/items/${id})).json();
    const map = (cs) =>
    cs.map((c) => ({ author: c.author, at: c.created_at_i * 1000, children: map(c.children ?? []) }));
    return lastReplyBy(map(item.children ?? []), item.author);
    }
    Discourse forums
    A lot of product communities run on Discourse. Add .json to a topic URL and you get a flat list where the first post is the question itself:

    async function discourse(host, topicId) {
    const t = await (await fetch(https://${host}/t/${topicId}.json)).json();
    const posts = t.post_stream.posts;
    const replies = posts.slice(1).map((p) => ({ author: p.username, at: Date.parse(p.created_at), children: [] }));
    return lastReplyBy(replies, posts[0].username);
    }
    One limit: on long topics, that JSON only includes the first batch of posts (20 by default).

    Using it
    const at = await hn(50131997);
    console.log(isAlive(at) ? "author still replying" : "probably moved on");
    Reddit has the same kind of tree in .json, but it often blocks requests coming from servers, so I left it out.

    Why I built this
    I'm building FounderPulse, which finds people who just posted about the problem your product solves. A post asking for exactly what you sell is worth a lot more when its author is still in the thread, so live threads now move to the top of the list. If you want to see what it finds for your product, there's a free test at founder-pulse.com, no signup.

    What signal do you use to decide a thread is still worth answering?#javascript #webdev #api #showdev #software #coding #development #engineering #inclusive #community
    Is anyone still reading that thread? Check the author's last reply with 3 free APIs

  17. Your retry loop is maybe eight lines. Why does it double your bill and duplicate side effects?

    I keep seeing the same pattern in reviews. The retry logic looks correct, and everyone stops reading there.

    That is the problem. Retries are where cost, correctness, and latency quietly disagree.

    Below are five claims I hear often, the evidence that breaks them, and a small drill you can run in an afternoon.

    Label: the code here is a template, not a benchmark. I have not run it against your stack. Run the drill yourself and trust your own numbers, not mine.

    Myth 1: "A retry is basically free"


    A retry is not a repeat. It is a second request with the same input.

    You pay to send the prompt again, on every attempt. Long system prompts make this expensive fast.

    Corrected model: retry cost scales with input_tokens × attempts × concurrent_callers. Measure attempts, not errors.

    Ask yourself: does your dashboard count attempts, or only final outcomes? Most count outcomes.

    Myth 2: "HTTP 200 means the model finished"


    A 200 means the transport succeeded. It says nothing about the answer.

    Truncated completions, empty content, and stream cuts all arrive as 200. Your retry loop never fires.

    Corrected model: treat finish_reason, content length, and schema validity as part of the success check. A response is not a result.

    How many of your retries are actually triggered by business-level incompleteness? Usually zero.

    Myth 3: "Exponential backoff with jitter is enough"


    Backoff controls timing. It does not control volume.

    If every caller retries four times, a partial outage becomes a full one. Jitter spreads the pain, not the load.

    Corrected model: add a retry budget per request and per minute. Cap total attempts across the fleet.

    Rules that survive contact with production:

    1. Retry 429 and 5xx only. Never retry 400 or 401.
    2. Honor Retry-After when present. It beats your formula.
    3. Stop after a fixed attempt count. Then fail over or fail closed.
    4. Emit one metric per attempt, tagged by error class.


    Myth 4: "Retrying is idempotent because the call is stateless"


    The model call is stateless. Your handler is not.

    If the tool call wrote a ticket, charged a card, or sent mail, a retry repeats the side effect.

    Corrected model: retries are only safe behind an idempotency key or a commit barrier. The barrier is a local check: did the side effect already happen?

    Rhetorical but useful: what would your retry loop do to a payment webhook twice in a row?

    Myth 5: "You can resume a stream where it stopped"


    You cannot resume mid-token. The connection is gone, and so is the partial state.

    What you can do is checkpoint at message boundaries. Re-request with the completed prefix as context.

    Corrected model: streams are not resumable transports. They are progress signals. Persist what you received, then decide.

    The drill: inject faults, count attempts


    This is the part that changes minds. Ten minutes of setup, one table of evidence.

    The stub server uses only the standard library. No dependencies, no keys.

    # stub_server.py - deterministic fault injection, Python 3.9+
    import json, threading
    from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

    FAULTS = ["ok", "truncate", "500", "429", "slow"]
    state = {"n": 0}
    lock = threading.Lock()

    class H(BaseHTTPRequestHandler):
    def do_POST(self):
    self.rfile.read(int(self.headers.get("Content-Length", 0)))
    with lock:
    fault = FAULTS[state["n"] % len(FAULTS)]
    state["n"] += 1
    if fault == "500":
    self.send_response(500); self.end_headers()
    self.wfile.write(b'{"error":"boom"}'); return
    if fault == "429":
    self.send_response(429)
    self.send_header("Retry-After", "1"); self.end_headers(); return
    body = {"choices": [{
    "message": {"role": "assistant", "content": "ok"},
    "finish_reason": "length" if fault == "truncate" else "stop",
    }]}
    raw = json.dumps(body).encode()
    self.send_response(200)
    self.send_header("Content-Type", "application/json")
    self.send_header("Content-Length", str(len(raw)))
    self.end_headers()
    self.wfile.write(raw)
    def log_message(self, *args):
    pass

    if __name__ == "__main__":
    ThreadingHTTPServer(("127.0.0.1", 8787), H).serve_forever()

    Now the client. It records every attempt in a ledger.

    # drill.py - counts attempts and re-sent input per call
    import json, random, time, urllib.error, urllib.request

    URL = "http://127.0.0.1:8787/v1/chat"
    PROMPT = "summarise this ticket in one line" # swap for a real payload

    def classify(code, body):
    if code == 429:
    return "throttle"
    if code >= 500 or code == 0:
    return "transient"
    if code == 200 and body["choices"][0]["finish_reason"] == "length":
    return "truncated"
    return "ok"

    def call_once():
    req = urllib.request.Request(
    URL,
    data=json.dumps({"prompt": PROMPT}).encode(),
    headers={"Content-Type": "application/json"},
    )
    try:
    with urllib.request.urlopen(req, timeout=5) as r:
    return r.status, json.loads(r.read())
    except urllib.error.HTTPError as e:
    return e.code, {}
    except Exception:
    return 0, {}

    def drill(cases=10, budget=4):
    ledger =
    [] for _ in range(cases):
    input_tokens = len(PROMPT.split()) # crude proxy, use real usage
    for attempt in range(1, budget + 1):
    code, body = call_once()
    cls = classify(code, body)
    ledger.append({"attempt": attempt, "code": code,
    "class": cls, "input_resent": input_tokens})
    if cls in ("ok", "truncated"):
    break
    delay = min(2 ** attempt * 0.1, 1.0)
    time.sleep(delay * random.uniform(0.5, 1.5))
    return ledger

    if __name__ == "__main__":
    rows = drill()
    print(json.dumps(rows, indent=2))
    print("attempts:", len(rows))
    print("input tokens re-sent:", sum(r["input_resent"] for r in rows))

    Run it:

    python stub_server.py &
    python drill.py | tail -n 2

    Then read the ledger. Do you see attempts your old loop would have skipped? Do you see truncated responses marked as success?

    The decision table I actually use

    SignalRetry?Action429 with Retry-AfterOnceSleep the header value, then one attempt5xxYes, budgetedBackoff with jitter, cap at 3Timeout, no responseYes, budgetedSame route first, then failover400 / 401NeverFix the request or the credentialfinish_reason = lengthNoRaise the limit or chunk the inputEmpty contentOnceRetry, then fail closed

    Where MonkeyCode fits in this drill


    A fault drill needs two things: a stub server and a second route to fail over to.

    MonkeyCode's free model access gives me that second route without a card. The operator-supplied free server option can host the stub, so the drill does not touch production networking.

    I would not run the whole harness blindly there. Check the current quotas and limits yourself first.

    Disclosure: This article was prepared as part of MonkeyCode's product outreach.

    Use it as the failover target you test against, not as the reason the drill exists. The drill works with any second endpoint.

    Limitations, and who should skip this


    • The stub returns fixed shapes. It tests your control flow, not model quality.
    • Token counts in the script are a proxy. Swap in real usage numbers.
    • Retry budgets need tuning per route. One global number hides the problem.

    Skip this if you have a single caller and no side effects. You have bigger wins elsewhere.

    Skip it too if your platform already enforces retry budgets and idempotency keys. Audit those settings instead.

    What changes after the drill


    You stop treating retries as error handling. You start treating them as load, cost, and duplicate-work decisions.

    That reframing is the whole payoff. The eight-line loop stays short, but now it has a reason for every line.

    What would your ledger show tomorrow?#ai #testing #python #api #software #coding #development #engineering #inclusive #community
    Five Myths About Retrying an LLM Call, and the Fault-Injection Drill That Tests Them

  18. 📢 New #updates · 17 Oct #14

    · Wallos v5.10.0 — Bulk toolbar improvements and fixes
    · TrailBase v0.35.0 — Faster inserts, transactional file writes, and batch insert behavior change
    · mirrord 3.275.0 — Added Helm chart support and Kafka branch isolation
    · UniFi-Poller v5.6.0 — Improved station counts and SSD cache exports

    All updates live on selfhost.directory

    #selfhosted #api #performance #opensource

  19. Security Tip: Stop hardcoding API keys in your source code! 🛡️ Hardcoded secrets in version control are a primary vector for account takeovers. Use environment variables or secrets management vaults like HashiCorp Vault or AWS Secrets Manager. Implement a regular rotation policy—automated if possible—to reduce the blast radius of a leaked credential. Stay ahead of vulnerabilities at cvedatabase.com #InfoSec #CyberSecurity #API #DevSecOps #AppSec

  20. Kwetter heet vanaf nu OpenFeed 🎉

    OpenFeed wordt één Europees sociaal netwerk met een volledig open API, vastgelegd in een openbare OpenAPI 3.1-spec. Apps bouwen hun eigen interface, OpenFeed draait het netwerk. Eén account werkt in elke app.

    Op openfeed.eu komt onze eigen app, op precies dezelfde API.

    ✅ EU-bedrijf, EU-hosting
    ✅ Geen advertenties, geen profilering
    ✅ Geen tracking tussen apps

    #OpenFeed #DigitaleSoevereiniteit #API

    openfeed.eu

  21. 私は APIGOTO チームで働いています。APIGOTO は独立したサービスで、OpenAI・Anthropic・Google とは提携関係にありません。

    APIGOTO は OpenAI 互換の LLM API ゲートウェイです。
    ・base_url は https://api.china-aiapi.com/v1 の1つだけで Claude / GPT / Gemini を呼び出せます
    ・上流エラー時は自動フェイルオーバー(リトライは最大3回まで)
    ・リクエストごとのログ
    ・BYOK(自分のプロバイダーキーを持ち込み可)
    ・従量課金

    質問です:リトライ上限3回は既定値として妥当でしょうか?それともリクエストごとに変えられた方がいいですか?

    www.china-aiapi.com
    #LLM #API #プログラミング
  22. 私は APIGOTO チームで働いています。APIGOTO は独立したサービスで、OpenAI・Anthropic・Google とは提携関係にありません。

    APIGOTO は OpenAI 互換の LLM API ゲートウェイです。
    ・base_url は https://api.china-aiapi.com/v1 の1つだけで Claude / GPT / Gemini を呼び出せます
    ・上流エラー時は自動フェイルオーバー(リトライは最大3回まで)
    ・リクエストごとのログ
    ・BYOK(自分のプロバイダーキーを持ち込み可)
    ・従量課金

    質問です:LLM 呼び出しのデバッグで、ログのどの項目(レイテンシ、トークン数、応答した上流、リトライ履歴など)を実際に見ていますか?

    www.china-aiapi.com
    #LLM #API #プログラミング
  23. 私は APIGOTO チームで働いています。APIGOTO は独立したサービスで、OpenAI・Anthropic・Google とは提携関係にありません。

    APIGOTO は OpenAI 互換の LLM API ゲートウェイです。
    ・base_url は https://api.china-aiapi.com/v1 の1つだけで Claude / GPT / Gemini を呼び出せます
    ・上流エラー時は自動フェイルオーバー(リトライは最大3回まで)
    ・リクエストごとのログ
    ・BYOK(自分のプロバイダーキーを持ち込み可)
    ・従量課金

    質問です:BYOK で自分のキーが上限に達したとき、黙って別経路に切り替えるのと、明示的にエラーにするのと、どちらが良いですか?

    www.china-aiapi.com
    #LLM #API #プログラミング
  24. 私は APIGOTO チームで働いています。APIGOTO は独立したサービスで、OpenAI・Anthropic・Google とは提携関係にありません。

    APIGOTO は OpenAI 互換の LLM API ゲートウェイです。
    ・base_url は https://api.china-aiapi.com/v1 の1つだけで Claude / GPT / Gemini を呼び出せます
    ・上流エラー時は自動フェイルオーバー(リトライは最大3回まで)
    ・リクエストごとのログ
    ・BYOK(自分のプロバイダーキーを持ち込み可)
    ・従量課金

    質問です:リトライ上限3回は既定値として妥当でしょうか?それともリクエストごとに変えられた方がいいですか?

    www.china-aiapi.com
    #LLM #API #プログラミング
  25. 私は APIGOTO チームで働いています。APIGOTO は独立したサービスで、OpenAI・Anthropic・Google とは提携関係にありません。

    APIGOTO は OpenAI 互換の LLM API ゲートウェイです。
    ・base_url は https://api.china-aiapi.com/v1 の1つだけで Claude / GPT / Gemini を呼び出せます
    ・上流エラー時は自動フェイルオーバー(リトライは最大3回まで)
    ・リクエストごとのログ
    ・BYOK(自分のプロバイダーキーを持ち込み可)
    ・従量課金

    質問です:LLM 呼び出しのデバッグで、ログのどの項目(レイテンシ、トークン数、応答した上流、リトライ履歴など)を実際に見ていますか?

    www.china-aiapi.com
    #LLM #API #プログラミング
  26. 📢 New #updates · 17 Oct #10

    · Pi-hole v6.5 — Security fixes for command execution and root privilege escalation
    · Firefly III develop-20261017.3 — Latest fixes translations and features
    · Dawarich 1.16.0 — Added supporter badge and address support for visits
    · lightdash 2.602.0 — Tool titles now visible in annotations

    More self-hosted updates → selfhost.directory

    #homelab #api #mobile #docker

  27. 🚀 New #release · cState v7-r1

    - cState v7-r1 prerelease for testing, v6.0.2 remains stable.
    - Modern default skin, classic skin retained.
    - Experiments, releases, changelog, roadmap, evals, decisions, research with JSON/RSS/Atom feeds.
    - Reporting web component with Markdown export and GitHub/GitLab handoff.

    Check and self-host it → selfhost.directory/project/cst

    #devops #cstate #api #markdown #opensource

  28. 📢 New #updates · 17 Oct #8

    · Ghostfolio 3.87.0 — Added investment chart story and improved performance timeline chart
    · Ever Gauzy v111.108.0 — Inbox email handling now more reliable
    · lightdash 2.601.0 — Claude plugin integration added
    · SWAG (Secure Web Application Gateway) 5.8.0-ls490

    Browse everything at selfhost.directory

    #homelab #api #ui #email

  29. 私は APIGOTO チームで働いています。APIGOTO は独立したサービスで、OpenAI・Anthropic・Google とは提携関係にありません。

    APIGOTO は OpenAI 互換の LLM API ゲートウェイです。
    ・base_url は https://api.apigoto.com/v1 の1つだけで Claude / GPT / Gemini を呼び出せます
    ・上流エラー時は自動フェイルオーバー(リトライは最大3回まで)
    ・リクエストごとのログ
    ・BYOK(自分のプロバイダーキーを持ち込み可)
    ・従量課金

    質問です:429(レート制限)のときも 5xx と同じようにフェイルオーバーすべきでしょうか?それとも同じプロバイダーでバックオフすべきでしょうか?

    www.china-aiapi.com
    #LLM #API #プログラミング
  30. I work on the APIGOTO team. APIGOTO is independent and not affiliated with OpenAI, Anthropic or Google.

    APIGOTO is an OpenAI-compatible LLM gateway: one base_url
    https://api.apigoto.com/v1 for Claude, GPT and Gemini, automatic failover capped at 3 retries, per-request logs, BYOK, pay-per-use.

    Question: is a fixed cap of 3 retries a sensible default, or should it be configurable per request?

    www.china-aiapi.com
    #LLM #API #DevTools

Share on Mastodon

Enter the server where you have an account.