Aetherfy vector REST API
Base URL and authentication for the Aetherfy vector API
The Aetherfy vector API is served from https://vectors.aetherfy.com. Every
customer-facing route lives under /api/v1. Authentication is a bearer token:
Authorization: Bearer <api key>Collection names are tenant-scoped by Aetherfy on the server side. You always send your own bare collection name — never a prefixed or namespaced one — and Aetherfy resolves it to your account’s collection.
curl -s https://vectors.aetherfy.com/api/v1/collections \
-H "Authorization: Bearer $AETHERFY_API_KEY"A request with no Authorization header, or one that is not a Bearer header,
is refused with 401 MISSING_API_KEY. A syntactically valid key that does not
resolve is refused with 401 INVALID_API_KEY. All error shapes are documented on
errors.
Collection routes in the Aetherfy vector API
| Method | Path | Purpose |
|---|---|---|
| POST | /api/v1/collections | Create a collection. Body: {name, vectors:{size,distance}, description?, regions?}. Re-creating an existing collection with the same configuration is idempotent and returns 200; a different configuration under an existing name returns 409 COLLECTION_NAME_TAKEN. |
| GET | /api/v1/collections | List collections. Workspaceless form only. |
| GET | /api/v1/collections/{name} | Collection info. |
| PATCH | /api/v1/collections/{name} | Update metadata. description only — any other key returns 400. |
| DELETE | /api/v1/collections/{name} | Delete the collection. |
Aetherfy fixes the rest of the collection configuration server-side. There is no
request field for optimizers_config, hnsw_config, or any other engine tuning
at creation time.
Because a same-configuration create is idempotent on Aetherfy, a script may call
create unconditionally on every run without checking collection_exists first —
the second and later runs return 200 and change nothing. Only a create that
asks for a different configuration under a name already in use is an error.
# Create.
curl -s -X POST https://vectors.aetherfy.com/api/v1/collections \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"articles","vectors":{"size":4,"distance":"Cosine"},"description":"Article embeddings"}'
# Read.
curl -s https://vectors.aetherfy.com/api/v1/collections/articles \
-H "Authorization: Bearer $AETHERFY_API_KEY"
# Update the description (the only mutable field).
curl -s -X PATCH https://vectors.aetherfy.com/api/v1/collections/articles \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"description":"Article embeddings, v2"}'
# Delete.
curl -s -X DELETE https://vectors.aetherfy.com/api/v1/collections/articles \
-H "Authorization: Bearer $AETHERFY_API_KEY"Collection names are validated by Aetherfy: 1 to 100 characters, drawn from
[a-zA-Z0-9_-] only. Descriptions are at most 500 characters and may not contain
HTML angle brackets. Both violations return 400.
Response headers and body on an Aetherfy collection read
GET /api/v1/collections/{name} returns a body of the form
{result, schema_version} and carries three response headers that Aetherfy adds:
| Header | Meaning |
|---|---|
ETag | Version tag for the collection record |
X-Collection-Source | Which store answered the read |
X-Collection-Status | Lifecycle status of the collection |
These headers are specific to the single-collection read on Aetherfy; the list route does not carry them.
Point routes in the Aetherfy vector API
| Method | Path | Purpose |
|---|---|---|
| PUT | /api/v1/collections/{name}/points | Upsert points (streaming). Body: {"points":[{id, vector, payload?}]} |
| POST | /api/v1/collections/{name}/points/search | Similarity search |
| POST | /api/v1/collections/{name}/points/retrieve | Retrieve by ids. Body: {ids:[...], with_payload?, with_vector?} |
| GET | /api/v1/collections/{name}/points/{id} | Retrieve a single point |
| POST | /api/v1/collections/{name}/points/scroll | Paginate through points |
| POST | /api/v1/collections/{name}/points/count | Count. Body: {filter?, exact?} |
| POST | /api/v1/collections/{name}/points/delete | Delete by {points:[ids]} or by {filter:{...}} |
Upsert on Aetherfy is PUT, not POST. This is the single most common mistake
against this API — see the unsupported-endpoint section below for what POST on
that path actually does.
On the retrieve route the flags are with_payload (default true) and
with_vector — singular — defaulting to false. The search body takes the same
singular spelling, with_vector. Both Aetherfy SDKs expose this option under the
plural name (with_vectors in Python, withVectors in JavaScript), so a
hand-written REST search body that says with_vectors is not a flag Aetherfy
reads. On the count route a limit
key in the body is stripped by Aetherfy before the request reaches the engine, so
sending one has no effect.
# Upsert (PUT, not POST).
curl -s -X PUT https://vectors.aetherfy.com/api/v1/collections/articles/points \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"points":[
{"id":1,"vector":[0.1,0.2,0.3,0.4],"payload":{"lang":"en"}},
{"id":2,"vector":[0.4,0.3,0.2,0.1],"payload":{"lang":"fr"}}
]}'
# Search.
curl -s -X POST https://vectors.aetherfy.com/api/v1/collections/articles/points/search \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"vector":[0.1,0.2,0.3,0.4],"limit":5,"with_payload":true}'
# Retrieve by id.
curl -s -X POST https://vectors.aetherfy.com/api/v1/collections/articles/points/retrieve \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ids":[1,2],"with_payload":true,"with_vector":false}'
# Retrieve a single point.
curl -s https://vectors.aetherfy.com/api/v1/collections/articles/points/1 \
-H "Authorization: Bearer $AETHERFY_API_KEY"
# Scroll.
curl -s -X POST https://vectors.aetherfy.com/api/v1/collections/articles/points/scroll \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"limit":100,"with_payload":true}'
# Count.
curl -s -X POST https://vectors.aetherfy.com/api/v1/collections/articles/points/count \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"exact":true}'
# Delete by id, then by filter.
curl -s -X POST https://vectors.aetherfy.com/api/v1/collections/articles/points/delete \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"points":[1,2]}'
curl -s -X POST https://vectors.aetherfy.com/api/v1/collections/articles/points/delete \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filter":{"must":[{"key":"lang","match":{"value":"fr"}}]}}'Per-request caps on these routes — search and scroll limit, retrieve id count,
delete point count, upsert point count and wire size — are on
limits.
Payload and index routes in the Aetherfy vector API
| Method | Path | Purpose |
|---|---|---|
| POST | /api/v1/collections/{name}/points/payload | Set payload — merge |
| PUT | /api/v1/collections/{name}/points/payload | Overwrite payload — replace |
| POST | /api/v1/collections/{name}/points/payload/delete | Delete named payload keys |
| PUT or POST | /api/v1/collections/{name}/index | Create a payload field index |
| DELETE | /api/v1/collections/{name}/index/{field} | Delete a payload field index |
POST merges into the existing payload; PUT replaces it wholesale. Aetherfy
reserves every payload key beginning __aetherfy_: writing one returns 400
RESERVED_FIELD, and any such key is stripped from read responses.
# Merge keys into the existing payload.
curl -s -X POST https://vectors.aetherfy.com/api/v1/collections/articles/points/payload \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"payload":{"reviewed":true},"points":[1,2]}'
# Replace the payload wholesale.
curl -s -X PUT https://vectors.aetherfy.com/api/v1/collections/articles/points/payload \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"payload":{"lang":"en"},"points":[1]}'
# Remove named keys.
curl -s -X POST https://vectors.aetherfy.com/api/v1/collections/articles/points/payload/delete \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"keys":["reviewed"],"points":[1,2]}'Schema routes in the Aetherfy vector API
| Method | Path | Purpose |
|---|---|---|
| GET | /api/v1/schema/{collection} | Read the stored payload schema |
| PUT | /api/v1/schema/{collection} | Write it. Body: {schema, enforcement_mode, description?} |
| DELETE | /api/v1/schema/{collection} | Remove it |
| POST | /api/v1/schema/{collection}/analyze | Infer a schema from stored points. Body: {sample_size?} |
enforcement_mode accepts "off", "warn", or "strict"; anything else returns
400 INVALID_ENFORCEMENT_MODE. sample_size must be between 100 and 10 000, or
Aetherfy returns 400 INVALID_SAMPLE_SIZE.
The PUT route supports If-Match for compare-and-set. A mismatch returns 412
SCHEMA_VERSION_MISMATCH, whose body carries current_etag so you can re-read
and retry.
# Read the current schema.
curl -s https://vectors.aetherfy.com/api/v1/schema/articles \
-H "Authorization: Bearer $AETHERFY_API_KEY"
# Infer one from the stored points.
curl -s -X POST https://vectors.aetherfy.com/api/v1/schema/articles/analyze \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"sample_size":500}'
# Remove it.
curl -s -X DELETE https://vectors.aetherfy.com/api/v1/schema/articles \
-H "Authorization: Bearer $AETHERFY_API_KEY"Region discovery in the Aetherfy vector API
GET /api/v1/regions returns the region-to-regional-URL map that the Aetherfy
SDKs use to build a region-pinned client.
curl -s https://vectors.aetherfy.com/api/v1/regions \
-H "Authorization: Bearer $AETHERFY_API_KEY"Which regions actually hold your data is a property of your plan, not of this
route: Free and Starter accounts are single-region, with the region fixed by the
first resource created, and replication across regions begins at the tier named
Performance. Asking for a region outside your plan’s scope returns 422
STARTER_REGION_CONSISTENCY or 422 COLLECTION_REGIONS_NOT_IN_SCOPE.
Workspace-scoped routes in the Aetherfy vector API
Every collection route above has a workspace-scoped twin. Insert
/workspaces/{workspace} between /api/v1 and /collections:
| Workspaceless | Workspace-scoped |
|---|---|
POST /api/v1/collections | POST /api/v1/workspaces/{workspace}/collections |
GET /api/v1/collections/{name} | GET /api/v1/workspaces/{workspace}/collections/{name} |
PATCH /api/v1/collections/{name} | PATCH /api/v1/workspaces/{workspace}/collections/{name} |
DELETE /api/v1/collections/{name} | DELETE /api/v1/workspaces/{workspace}/collections/{name} |
PUT /api/v1/collections/{name}/points | PUT /api/v1/workspaces/{workspace}/collections/{name}/points |
POST /api/v1/collections/{name}/points/search | POST /api/v1/workspaces/{workspace}/collections/{name}/points/search |
The collection name in the workspace-scoped form must be bare — it may not
contain a /. The collection list route (GET /api/v1/collections) exists in the
workspaceless form only.
curl -s -X POST https://vectors.aetherfy.com/api/v1/workspaces/research/collections/articles/points/search \
-H "Authorization: Bearer $AETHERFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"vector":[0.1,0.2,0.3,0.4],"limit":5}'Both Aetherfy SDKs reach the workspace-scoped routes through the workspace
client option rather than by hand-building the path — see the SDK
reference.
Distance values accepted by the Aetherfy vector API
Aetherfy normalizes the distance string case-insensitively at collection creation.
| You send (any case) | Aetherfy stores and returns |
|---|---|
cosine | Cosine |
euclid | Euclid |
euclidean | Euclid |
dot | Dot |
manhattan | Manhattan |
Euclidean is the one value that does not round-trip through Aetherfy, and it
catches SDK users too: DistanceMetric.EUCLIDEAN sends the string Euclidean,
so a collection created with it reads back config.distance == "Euclid" and an
equality check against Euclidean silently fails. Every other name comes back
exactly as the table’s left column, capitalised.
Qdrant compatibility and forwarding in the Aetherfy vector API
Anything under /api/v1/collections/{name}/points/** is forwarded verbatim to
Qdrant by Aetherfy. Nothing inspects or rewrites the body, which is why Qdrant’s
filter DSL, point shapes, and query bodies work unchanged — and why an
Aetherfy-side typo in a filter key is silently accepted rather than rejected.
Filter syntax and the one key-name defect worth knowing about are on
filtering.
The one consequence to internalise: Aetherfy validates the envelope (auth, tenancy, caps, reserved keys), and Qdrant validates the query. An option Aetherfy does not know about is not an error at the Aetherfy layer.
Endpoints the Aetherfy vector API does not support
Aetherfy is Qdrant-compatible but not a Qdrant passthrough. These are refused, deliberately, and no amount of retrying will change the answer.
| Request | Result | Use instead |
|---|---|---|
PUT /collections/{name} (Qdrant-native create) | 405 METHOD_NOT_ALLOWED | POST /api/v1/collections |
PATCH /collections/{name} with optimizers_config, hnsw_config, or any non-description key | 400 | Only description is mutable |
POST /collections/{name}/points expecting upsert | Not upsert — falls through to Qdrant’s batch retrieve, which expects body.ids | PUT /api/v1/collections/{name}/points |
| Snapshot endpoints | 404 “Unsupported endpoint” | — |
/telemetry, /metrics | 404 “Unsupported endpoint” | — |
/cluster, /locks, shard endpoints | 404 “Unsupported endpoint” | — |
| Collection creation with engine tuning fields | Not accepted — configuration is fixed server-side by Aetherfy | — |
Any payload key beginning __aetherfy_ | 400 RESERVED_FIELD on write; stripped from reads | Choose another key |
Query-time tuning is the one engine knob Aetherfy does expose, and it goes in the
request body’s params field — see search tuning.