Getting started
Every microservice works the same way: send a request with your API key, get the result straight back.
Three steps
- Create a Bloodweb account and verify your email. New accounts start with 25,000 free tokens.
- Make an API key in the dashboard. It is shown once, so copy it somewhere safe.
- Call a service. This turns an iPhone photo into a JPG:
curl -H "Authorization: Bearer YOUR_KEY" \
-F file=@photo.heic -F to=jpg \
https://bloodweb.net/api/v1/image-convert -o photo.jpg
// Node 18 or later
import { readFile, writeFile } from 'node:fs/promises';
const form = new FormData();
form.append('file', new Blob([await readFile('photo.heic')]), 'photo.heic');
form.append('to', 'jpg');
const res = await fetch('https://bloodweb.net/api/v1/image-convert', {
method: 'POST',
headers: { Authorization: 'Bearer YOUR_KEY' },
body: form,
});
if (!res.ok) throw new Error((await res.json()).error.message);
await writeFile('photo.jpg', Buffer.from(await res.arrayBuffer()));
console.log('Cost', res.headers.get('x-tokens'), 'tokens, balance', res.headers.get('x-balance'));
import requests
with open('photo.heic', 'rb') as f:
res = requests.post(
'https://bloodweb.net/api/v1/image-convert',
headers={'Authorization': 'Bearer YOUR_KEY'},
files={'file': f},
data={'to': 'jpg'},
)
if not res.ok:
raise SystemExit(res.json()['error']['message'])
with open('photo.jpg', 'wb') as out:
out.write(res.content)
print('Cost', res.headers['X-Tokens'], 'tokens, balance', res.headers['X-Balance'])
<?php
$ch = curl_init('https://bloodweb.net/api/v1/image-convert');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_KEY'],
CURLOPT_POSTFIELDS => ['file' => new CURLFile('photo.heic'), 'to' => 'jpg'],
CURLOPT_RETURNTRANSFER => true,
]);
$body = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) !== 200) {
exit(json_decode($body, true)['error']['message'] . "\n");
}
file_put_contents('photo.jpg', $body);
Each service page lists its options with an example of its own.
Your API key
Send the key in the Authorization header of every call, as Bearer followed by the key. An X-API-Key header works too.
Keys are only read from headers, never from the address, because addresses end up in logs and browser history. Keep keys on your server: anyone who can see a key can spend your tokens. If one leaks, revoke it in the dashboard and make another; you can have up to 10, one per app.
Sending files and options
- Files go as a normal form upload (
multipart/form-data), with the options as extra form fields. - JSON works as well: send
Content-Type: application/jsonand put a file in as base64 text under the same name (adata:URI is fine). JSON bodies are limited to 20MB. - Services that need no file, such as the QR code generator and the converters, also answer a plain
GETwith the options in the address.
What comes back
The result itself: the image, the PDF, the zip, or JSON for the data services. There is no wrapper to unpack. Three headers tell you about the call:
X-Tokens | What this call cost. |
X-Balance | Your balance after it. |
X-Took-Ms | How long we spent on it, in milliseconds. |
Files you send exist only while your call runs and are deleted when it ends. We keep a record that the call happened (which service, when, how big, whether it worked), never the file or its contents.
Tokens
Every successful call costs tokens: a fixed number for most services, or a number per page, file, image or minute where size drives the work. The pricing page lists them all.
- Calls that fail cost nothing.
- A call needs enough balance for its base price before it starts, otherwise it answers
402. - A large job that turns out to cost more than your balance still finishes. Your balance goes below zero by the difference, and the next call waits until you top up.
- Bought tokens never expire.
Errors
A failed call answers with a matching HTTP status and a small JSON body. The code is stable and safe to test for; the message is written for people and may be reworded.
{"error": {"code": "bad_param", "message": "\"quality\" must be between 1 and 100."}}
| Status | Codes | Meaning |
|---|---|---|
| 400 | missing_param bad_param missing_file too_many_files bad_json upload_failed | Something is missing or a value is wrong. The message names the parameter. |
| 400 | bad_data data_too_long bad_color unknown_unit ambiguous_unit incompatible_units unknown_currency | The value itself cannot be used by that service, such as a barcode with a wrong check digit. |
| 401 | missing_key invalid_key revoked_key | No key was sent, or it is not a working key. |
| 402 | insufficient_tokens | The balance does not cover this call. Top up in the dashboard. |
| 403 | account_disabled | The account the key belongs to is not active. |
| 404 | unknown_service | There is no service at that address. |
| 405 | method_not_allowed | That service does not accept GET (or POST). The Allow header says what it does accept. |
| 413 | file_too_large body_too_large too_long | The upload is bigger, or the audio longer, than the service accepts. |
| 415 | unsupported_type | The file is not a type the service reads. Types are detected from the file itself, not its name. |
| 422 | processing_failed bad_pdf pdf_encrypted bad_audio output_too_large too_many_rows | The file could not be processed, for example it is damaged or password protected. |
| 429 | rate_limited too_many_at_once too_many_attempts | Too many calls. Wait the number of seconds in the Retry-After header. |
| 500 | internal | Our fault. Try again, and tell us if it keeps happening. |
| 503 | busy rates_unavailable | A heavy service is at capacity, or exchange rates are unavailable. Try again shortly. |
| 504 | timeout | The job took too long and was stopped. Send a smaller input. |
Rate limits
- Each key can make 120 calls a minute.
- Each account can have 4 calls running at the same time.
Over either limit the call answers 429 and costs nothing. Wait the number of seconds in the Retry-After header, then send it again. Every response also carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (seconds until the minute ends). Need more? Write to us.
For tools
The whole API is described in OpenAPI 3.0 at /api/v1/openapi.json, which Postman and most code generators can import. A plain list of services is at /api/v1/.
Help
Questions, a problem, or a service you wish existed: support@bloodweb.net. The rules of use are in the microservices terms.