Writing

The provider was never broken

16 October 2026 · figures measured 16 October 2026

For about a fortnight, one of the providers compared here refused every single request. The same refusal every time, to the byte:

HTTP 401
{"code":"501","msg":"Not have permission","data":null}

It was investigated properly, which is the part worth dwelling on. The same request was sent across five pairs and a dozen amounts, and the answer never changed. It was sent with no credentials at all, and with deliberately invalid ones, and all three cases came back identical — which meant the response could not distinguish a rejected signature from an unrecognised key from a key without permission. Two emails went to that provider’s support desk, each carrying the exact request body, the signing method, the headers and the full response.

Both were wrong. The account had been fine the entire time.

What was actually happening

The environment file on the machine doing the testing contained this:

FIXEDFLOAT_API_KEY=your_key_here
FIXEDFLOAT_API_SECRET=your_secret_here

Copied from the example file months earlier and never replaced. Thirteen characters of template text where a forty-character key belongs. Every request that looked like a permissions problem was a request sent with the words your_key_here in the header, and the provider was refusing it exactly as it should have.

Why nothing caught it

This is the part that generalises, and it is more interesting than the mistake.

The code that asks providers for prices reports four different outcomes, deliberately and separately: a provider that quoted, a provider that failed, a provider that was never asked because no credentials exist, and a provider kept off that pair on purpose. The distinction is not decoration. A list of seven quotes where there should be ten does not explain itself, and the difference between “we have no key for this one” and “this one fell over” is the difference between a setup gap and an outage.

A placeholder defeats all of it, because a placeholder is a perfectly good string. The check for whether a provider is configured asks whether the value is non-empty. your_key_here is non-empty. So the provider counted as configured, was asked, was refused, and the refusal was filed under error — an outage — when the truth was no credentials.

An empty value fails loudly. A placeholder fails plausibly. The second is worse, because it produces a symptom that invites an explanation, and the explanation it invites is about the provider rather than about you.

The second mistake, which cost more than the first

Nobody looked at production.

The provider’s partner application for this site was approved on 30 September, two days after the second support email went out. The live site has had working credentials ever since, and has been quoting with them continuously. Asking the live comparison endpoint on the day this was finally understood returned this, for 0.01 BTC to USDT on Tron:

ProviderUSDT paid
FixedFloat814.42
Changelly812.26
StealthEX809.03
SimpleSwap808.21
Exolix807.69
ChangeNOW805.49
PegasusSwap803.98
SideShift799.36

Not merely working. Paying the most of eight, on a site whose entire purpose is to notice which provider pays the most. The one integration believed to be dead was quietly winning the comparison, and it went unnoticed for a fortnight because the environment it was tested in is not the environment that serves anybody.

What changed

Credentials are now read through one function, and that function treats a placeholder as absent. The provider goes back to being reported as unconfigured, which is what it is.

The patterns it matches are deliberately narrow — your_…_here, a handful of literals like changeme, and a run of x’s. It would be easy to write something cleverer that judged whether a string looks like a real key, and that cleverness would eventually refuse a genuine credential and produce this same bug pointing the other way. A guard against a false positive is not worth a false negative here.

There is also a new release check, which is the third script in this repository written because something had to be remembered and was not. It asserts that every non-empty value in the example file is recognised as a placeholder. Add a template value the guard does not catch, and the check fails rather than the bug returning under a different name.

The part that is about this site rather than about code

Two emails went to a company asking them to investigate a problem that did not exist on their side. They were polite, detailed, and a waste of somebody’s afternoon. The evidence in them was real and the conclusion drawn from it was wrong, which is the most persuasive kind of wrong there is.

This site publishes what it measures about providers, including the unflattering parts, and it would be a poor sort of honesty that only ran outward. The failure here was not the placeholder. It was reaching for an explanation outside the system before exhausting the ones inside it — and then writing to a stranger about it twice.

Plan an exchange

Every figure above can be checked against the providers yourself — no account, no sign-up, and nothing is held for you at any point.