agentblue API v1.0.0

Base URL https://api.agentblue.app · OpenAPI https://api.agentblue.app/v1/openapi.json · every service lives under /v1/{service}

Authentication

Every call to a service needs an API key, sent as Authorization: Bearer blue_… (or X-Api-Key: blue_…). A key carries scopes — the services it may call — and its own calls-per-minute. Keys are issued by the agentblue team; the key is shown once and never stored in clear.

curl https://api.agentblue.app/v1/me -H "Authorization: Bearer blue_XXXX"

Errors & limits

Success answers are JSON objects with status 200 (or 201). Every error is an RFC 9457 problem document, application/problem+json, with a stable type (https://api.agentblue.app/problems/{slug}), a title, the status, a human detail and the request id as instance (also in the X-Request-Id header on every response — quote it when you write to us).

{"type":"https://api.agentblue.app/problems/no-face","title":"No face found","status":422,"detail":"no face scored above 0.7","instance":"req_…"}

Rate limits are per key per minute; every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (seconds). Over the limit you get 429 with Retry-After. Outputs the API stores for you (crops, renders) are served from /files/{id}.{ext}: unguessable, immutable, cached a year, kept as the response's expires_at says.

Problem typeMeaning
bad-requestBad request
invalid-jsonThe body is not valid JSON
validationA parameter is invalid
invalid-urlThe URL is invalid
blocked-urlThe URL is not allowed
fetch-failedThe URL could not be fetched
unsupported-media-typeUnsupported media type
payload-too-largeThe payload is too large
no-faceNo face found
unauthorizedA valid API key is required
forbiddenThe key may not call this service
not-foundNot found
method-not-allowedMethod not allowed
rate-limitedToo many requests
engine-failedThe engine failed
internalInternal error

Platform

Health, your key, this document, stored files

GET /v1/health

Is the API up

Responses: 200 OK

GET /v1/me

The key you are calling with

Responses: 200 The key · 401 Unauthorized

GET /v1/openapi.json

This document

Responses: 200 OpenAPI 3.1

GET /files/{id}

A stored output (a crop, a render…), immutable, cached a year

ParameterTypeWhereDescription
id *stringpaththe id with its extension, as a service returned it (e.g. 3fK…9q.webp)

Responses: 200 The file · 404 NotFound

Faces

Face detection and face-centred crops for profile pictures: send an image (by URL, upload or base64), get the faces with boxes, confidence and landmarks, or a square (or any aspect) crop centred on the face as a stored file. Engine: OpenCV YuNet (2023), on our own servers — nothing leaves the platform.

POST /v1/faces/detect

Detect faces

Returns every face found (largest first) with its box, confidence and five landmarks. GET with the same parameters in the query string works too.

ParameterTypeWhereDescription
urlstring (uri)bodyA public http(s) URL of a JPEG, PNG, GIF or WebP (up to 25 MB). Give one of url, file, image_base64.
image_base64stringbodyThe image as base64 (a data: URL prefix is fine).
curl -X POST https://api.agentblue.app/v1/faces/detect \
  -H "Authorization: Bearer blue_XXXX" -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/photo.jpg"}'

Responses: 200 The faces · 401 Unauthorized · 403 Forbidden · 400 Problem · 413 Problem · 415 Problem · 429 RateLimited · 502 Problem

{"ok":true,"image":{"width":1200,"height":800,"mime":"image/jpeg","bytes":183452,"source":"https://example.com/photo.jpg"},"count":1,
 "faces":[{"box":{"x":512,"y":210,"width":190,"height":240},"confidence":0.98,"landmarks":{"right_eye":[560,290],"left_eye":[650,292],"nose":[605,345],"mouth_right":[570,395],"mouth_left":[640,397]}}],
 "model":"yunet-2023mar","ms":84}

POST /v1/faces/crop

Face-centred crop (a profile picture)

Finds the face (the largest by default), cuts a crop centred on it with `padding` around (0.45 = the face box's larger side plus 45 % on every side), in the `aspect` you ask, resized to `size`, encoded as `format`, and stores it: the answer carries the file's URL. When no face is found the answer is a 422 `no-face` problem — or pass `no_face=center` to crop the middle of the picture instead.

ParameterTypeWhereDescription
urlstring (uri)bodyA public http(s) URL of a JPEG, PNG, GIF or WebP (up to 25 MB). Give one of url, file, image_base64.
image_base64stringbodyThe image as base64 (a data: URL prefix is fine).
sizeintegerbodythe output's longer side in pixels, 16–2048 · default 400
paddingnumberbodyroom around the face, as a fraction of the face size, 0–3 · default 0.45
aspectstringbodythe crop's aspect, like 1:1, 4:3, 3:4, 16:9 · default 1:1
formatstringbody · default webp · one of webp, jpg, png
qualityintegerbody1–100 (webp, jpg) · default 85
whichstringbodylargest, first (leftmost), or a face index from /detect · default largest
no_facestringbody · default error · one of error, center
curl -X POST https://api.agentblue.app/v1/faces/crop \
  -H "Authorization: Bearer blue_XXXX" -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/photo.jpg", "size": 400, "format": "webp"}'

Responses: 201 The crop, stored · 422 No face (type no-face) · 401 Unauthorized · 403 Forbidden · 400 Problem · 413 Problem · 415 Problem · 429 RateLimited · 502 Problem

{"ok":true,"count":1,"face":{"box":{"x":512,"y":210,"width":190,"height":240},"confidence":0.98,…},
 "crop":{"x":385,"y":97,"width":456,"height":456},
 "file":{"id":"3fKq…","url":"https://api.agentblue.app/files/3fKq….webp","mime":"image/webp","bytes":21804,"width":400,"height":400,"expires_at":"2027-10-17 10:00:00"},
 "options":{"size":400,"padding":0.45,"aspect":"1:1","format":"webp","quality":85,"which":"largest","no_face":"error"},"model":"yunet-2023mar","ms":131}

Schemas

Problem — RFC 9457 problem details — every error of the API
{
    "type": "object",
    "description": "RFC 9457 problem details \u2014 every error of the API",
    "properties": {
        "type": {
            "type": "string",
            "format": "uri",
            "example": "https://api.agentblue.app/problems/no-face"
        },
        "title": {
            "type": "string"
        },
        "status": {
            "type": "integer"
        },
        "detail": {
            "type": "string"
        },
        "instance": {
            "type": "string",
            "description": "the request id (also in X-Request-Id) \u2014 quote it when you write to us"
        },
        "errors": {
            "type": "object",
            "additionalProperties": {
                "type": "string"
            },
            "description": "field \u2192 what is wrong (validation problems)"
        }
    },
    "required": [
        "type",
        "title",
        "status"
    ]
}
KeyInfo
{
    "type": "object",
    "properties": {
        "id": {
            "type": "integer"
        },
        "name": {
            "type": "string"
        },
        "prefix": {
            "type": "string"
        },
        "scopes": {
            "type": "array",
            "items": {
                "type": "string"
            }
        },
        "rate_per_minute": {
            "type": "integer"
        }
    }
}
StoredFile — An output the API stored for you
{
    "type": "object",
    "description": "An output the API stored for you",
    "properties": {
        "id": {
            "type": "string"
        },
        "url": {
            "type": "string",
            "format": "uri"
        },
        "mime": {
            "type": "string"
        },
        "bytes": {
            "type": "integer"
        },
        "width": {
            "type": "integer"
        },
        "height": {
            "type": "integer"
        },
        "expires_at": {
            "type": "string",
            "nullable": true,
            "description": "when the file is removed (null = kept)"
        }
    }
}
Point — [x, y] in the original image
{
    "type": "array",
    "items": {
        "type": "integer"
    },
    "minItems": 2,
    "maxItems": 2,
    "description": "[x, y] in the original image"
}
Face
{
    "type": "object",
    "properties": {
        "box": {
            "type": "object",
            "properties": {
                "x": {
                    "type": "integer"
                },
                "y": {
                    "type": "integer"
                },
                "width": {
                    "type": "integer"
                },
                "height": {
                    "type": "integer"
                }
            },
            "description": "pixels in the original image"
        },
        "confidence": {
            "type": "number",
            "description": "0\u20131"
        },
        "landmarks": {
            "type": "object",
            "properties": {
                "right_eye": {
                    "$ref": "#/components/schemas/Point"
                },
                "left_eye": {
                    "$ref": "#/components/schemas/Point"
                },
                "nose": {
                    "$ref": "#/components/schemas/Point"
                },
                "mouth_right": {
                    "$ref": "#/components/schemas/Point"
                },
                "mouth_left": {
                    "$ref": "#/components/schemas/Point"
                }
            }
        }
    }
}
DetectResult
{
    "type": "object",
    "properties": {
        "ok": {
            "type": "boolean"
        },
        "image": {
            "type": "object",
            "properties": {
                "width": {
                    "type": "integer"
                },
                "height": {
                    "type": "integer"
                },
                "mime": {
                    "type": "string"
                },
                "bytes": {
                    "type": "integer"
                },
                "source": {
                    "type": "string",
                    "enum": [
                        "url",
                        "upload",
                        "base64"
                    ]
                }
            }
        },
        "count": {
            "type": "integer"
        },
        "faces": {
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/Face"
            }
        },
        "model": {
            "type": "string"
        },
        "ms": {
            "type": "integer"
        }
    }
}
CropResult
{
    "type": "object",
    "properties": {
        "ok": {
            "type": "boolean"
        },
        "image": {
            "type": "object",
            "properties": {
                "width": {
                    "type": "integer"
                },
                "height": {
                    "type": "integer"
                },
                "mime": {
                    "type": "string"
                },
                "bytes": {
                    "type": "integer"
                },
                "source": {
                    "type": "string",
                    "enum": [
                        "url",
                        "upload",
                        "base64"
                    ]
                }
            }
        },
        "count": {
            "type": "integer"
        },
        "face": {
            "$ref": "#/components/schemas/Face"
        },
        "crop": {
            "type": "object",
            "properties": {
                "x": {
                    "type": "integer"
                },
                "y": {
                    "type": "integer"
                },
                "width": {
                    "type": "integer"
                },
                "height": {
                    "type": "integer"
                }
            }
        },
        "file": {
            "$ref": "#/components/schemas/StoredFile"
        },
        "options": {
            "type": "object"
        },
        "model": {
            "type": "string"
        },
        "ms": {
            "type": "integer"
        }
    }
}