API Reference

FLXBL automatically generates REST and GraphQL APIs from your schema. This reference covers all available endpoints and operations.

Base URL

All API requests use this base URL:

https://api.flxbl.dev/api/v1

For self-hosted instances, use your configured URL.

Authentication

Use API keys for programmatic access to the FLXBL Dynamic API. Include your API key in the Authorization header:

# API Key Authentication
curl -X GET https://api.flxbl.dev/api/v1/dynamic/Product \
  -H "Authorization: Bearer flxbl_ab12cd34_..."

# Get your API key from your FLXBL dashboard at platform.flxbl.dev

Generate API keys from your FLXBL dashboard at platform.flxbl.dev. API keys are scoped to your tenant and provide access to the Dynamic API endpoints.

REST API Endpoints

For each entity in your schema, these endpoints are generated:

# Entity CRUD Operations
GET    /api/v1/dynamic/{Entity}           # List all
POST   /api/v1/dynamic/{Entity}           # Create
GET    /api/v1/dynamic/{Entity}/:id       # Read
PUT    /api/v1/dynamic/{Entity}/:id       # Full update
PATCH  /api/v1/dynamic/{Entity}/:id       # Partial update
DELETE /api/v1/dynamic/{Entity}/:id       # Delete
POST   /api/v1/dynamic/{Entity}/query     # Query with DSL

# Vector Search
POST   /api/v1/dynamic/{Entity}/vector-search  # Similarity search

# Relationship Operations
POST   /api/v1/dynamic/{Entity}/:id/relationships/{rel}
GET    /api/v1/dynamic/{Entity}/:id/relationships/{rel}?direction=out
PATCH  /api/v1/dynamic/{Entity}/:id/relationships/{rel}/:targetId
DELETE /api/v1/dynamic/{Entity}/:id/relationships/{rel}/:targetId

# File Storage
POST   /api/v1/files/upload-url           # Get presigned upload URL
POST   /api/v1/files/:id/confirm          # Confirm upload
GET    /api/v1/files/:id/download-url     # Get presigned download URL
GET    /api/v1/files/:id                  # Get file metadata
GET    /api/v1/files                      # List files
DELETE /api/v1/files/:id                  # Delete file

# GraphQL Endpoint
POST   /api/v1/dynamic-gql/:tenantId
GET    /api/v1/dynamic-gql/:tenantId/schema.graphql
Important: Entity names in URLs are case-sensitive. Use the exact name from your schema (e.g., Product not products).

Create (POST)

# Create a product
curl -X POST https://api.flxbl.dev/api/v1/dynamic/Product \
  -H "Authorization: Bearer flxbl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Wireless Headphones",
    "price": 299.99,
    "inStock": true,
    "tags": ["electronics", "audio"]
  }'

# Response
{
  "id": "node_abc123",
  "name": "Wireless Headphones",
  "price": 299.99,
  "inStock": true,
  "tags": ["electronics", "audio"],
  "createdAt": "2025-01-15T10:30:00Z",
  "updatedAt": "2025-01-15T10:30:00Z"
}

Read (GET)

# Get a product by ID
curl -X GET https://api.flxbl.dev/api/v1/dynamic/Product/node_abc123 \
  -H "Authorization: Bearer flxbl_your_api_key"

# List all products
curl -X GET https://api.flxbl.dev/api/v1/dynamic/Product \
  -H "Authorization: Bearer flxbl_your_api_key"

Update (PUT/PATCH)

# Full update (PUT) - replaces all fields
curl -X PUT https://api.flxbl.dev/api/v1/dynamic/Product/node_abc123 \
  -H "Authorization: Bearer flxbl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Premium Wireless Headphones",
    "price": 349.99,
    "inStock": true,
    "tags": ["electronics", "audio", "premium"]
  }'

# Partial update (PATCH) - only updates specified fields
curl -X PATCH https://api.flxbl.dev/api/v1/dynamic/Product/node_abc123 \
  -H "Authorization: Bearer flxbl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "price": 279.99
  }'

Delete (DELETE)

# Delete a product
# IMPORTANT: Do NOT include Content-Type header for DELETE without body
curl -X DELETE https://api.flxbl.dev/api/v1/dynamic/Product/node_abc123 \
  -H "Authorization: Bearer flxbl_your_api_key"
Important: Do NOT include Content-Type: application/json header for DELETE requests without a body. This will cause a 400 error.

Relationship Operations

Manage relationships between entities:

# Create a relationship
curl -X POST https://api.flxbl.dev/api/v1/dynamic/Product/node_abc/relationships/BELONGS_TO \
  -H "Authorization: Bearer flxbl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "targetId": "node_category_xyz",
    "properties": {
      "addedAt": "2025-01-15T10:30:00Z"
    }
  }'

# Get relationships
curl -X GET "https://api.flxbl.dev/api/v1/dynamic/Product/node_abc/relationships/BELONGS_TO?direction=out" \
  -H "Authorization: Bearer flxbl_your_api_key"

# Delete a relationship
curl -X DELETE https://api.flxbl.dev/api/v1/dynamic/Product/node_abc/relationships/BELONGS_TO/node_category_xyz \
  -H "Authorization: Bearer flxbl_your_api_key"

Batch Operations

FLXBL supports batch operations for high-performance bulk data processing. All batch operations are atomic (all-or-nothing) and support up to 1,000 items per request.

Batch Create (POST)

Create multiple entities in a single request:

# Batch create multiple products
curl -X POST https://api.flxbl.dev/api/v1/dynamic/Product/batch \
  -H "Authorization: Bearer flxbl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "name": "Widget A", "price": 29.99 },
      { "name": "Widget B", "price": 39.99 }
    ]
  }'

# Response
{
  "successful": [
    { "id": "node_abc", "name": "Widget A", "price": 29.99, ... },
    { "id": "node_def", "name": "Widget B", "price": 39.99, ... }
  ],
  "failed": [],
  "totalCount": 2,
  "successCount": 2,
  "failureCount": 0,
  "stats": {
    "processingTimeMs": 150,
    "validationTimeMs": 20,
    "databaseTimeMs": 130
  }
}

Batch Update (PATCH)

Update multiple entities at once. Each item requires an id and a data object:

# Batch update multiple products
curl -X PATCH https://api.flxbl.dev/api/v1/dynamic/Product/batch \
  -H "Authorization: Bearer flxbl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "id": "node_abc", "data": { "price": 24.99 } },
      { "id": "node_def", "data": { "price": 34.99 } }
    ]
  }'

Batch Delete (DELETE)

Delete multiple entities by their IDs:

# Batch delete multiple products
curl -X DELETE https://api.flxbl.dev/api/v1/dynamic/Product/batch \
  -H "Authorization: Bearer flxbl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": ["node_abc", "node_def", "node_ghi"]
  }'

Response Format

All batch operations return a consistent response format with success/failure details and performance metrics:

# Response format (all batch operations)
{
  "successful": [ ... ],     # Successfully processed entities
  "failed": [                # Failed items with error details
    {
      "index": 1,
      "item": { "name": "Invalid" },
      "error": {
        "code": "VALIDATION_ERROR",
        "message": "Field 'price' is required",
        "field": "price"
      }
    }
  ],
  "totalCount": 10,          # Total items in request
  "successCount": 9,         # Successfully processed
  "failureCount": 1,         # Failed items
  "stats": {                 # Performance metrics
    "processingTimeMs": 150,
    "validationTimeMs": 20,
    "databaseTimeMs": 130
  }
}
Field Description
successful Array of successfully processed entities
failed Array of failed items with index and error details
successCount Number of successfully processed items
failureCount Number of failed items
stats Performance metrics (processing, validation, database time)
Note: Batch operations are pre-validated before any database writes. If validation fails for any item, the entire batch is rejected.

Vector Search

Perform cosine similarity search on entities with VECTOR fields. This is useful for semantic search, recommendations, and RAG applications.

Endpoint

POST /api/v1/dynamic/{Entity}/vector-search

Request Body

Field Type Description
field string Name of the VECTOR field to search against (required)
vector number[] Query vector — dimensions must match the field's vectorDimensions (required)
topK number Maximum results to return, 1–100 (default: 10)
where object Optional filter conditions applied after similarity ranking
select string[] Optional fields to include in response (default: all)

Example

# Vector similarity search on a Product's embedding field
curl -X POST https://api.flxbl.dev/api/v1/dynamic/Product/vector-search \
  -H "Authorization: Bearer flxbl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "field": "embedding",
    "vector": [0.1, 0.2, 0.3, "...1536 dimensions..."],
    "topK": 5,
    "where": {
      "isActive": { "$eq": true }
    },
    "select": ["name", "price", "description"]
  }'

# Response
[
  {
    "data": {
      "id": "node_abc123",
      "name": "Wireless Headphones",
      "price": 299.99,
      "description": "Premium noise-canceling headphones"
    },
    "score": 0.95
  },
  {
    "data": {
      "id": "node_def456",
      "name": "Bluetooth Speaker",
      "price": 149.99,
      "description": "Portable wireless speaker"
    },
    "score": 0.87
  }
]

Each result includes a score (0–1) representing cosine similarity, where 1 is an exact match. Use the where parameter to filter results by any field, and select to control which fields are returned.

Note: The query vector's dimensions must exactly match the field's vectorDimensions configuration. For programmatic usage, see client.vectorSearch() in the SDK.

File Storage

FLXBL provides S3-compatible file storage with presigned URLs for secure, direct-to-storage uploads and downloads. Files can be associated with entities via FILE fields.

Upload Workflow

File uploads use a three-step presigned URL workflow:

  1. Request upload URLPOST /api/v1/files/upload-url with file metadata
  2. Upload to S3PUT the file directly to the presigned URL
  3. Confirm uploadPOST /api/v1/files/:id/confirm to finalize
# Step 1: Get a presigned upload URL
curl -X POST https://api.flxbl.dev/api/v1/files/upload-url \
  -H "Authorization: Bearer flxbl_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "fileName": "product-hero.jpg",
    "mimeType": "image/jpeg",
    "sizeBytes": 2048576
  }'

# Response
{
  "fileId": "file_abc123",
  "uploadUrl": "https://s3.amazonaws.com/bucket/...",
  "expiresAt": "2026-01-15T11:30:00Z"
}

# Step 2: Upload the file directly to S3
curl -X PUT "https://s3.amazonaws.com/bucket/..." \
  -H "Content-Type: image/jpeg" \
  --data-binary @product-hero.jpg

# Step 3: Confirm the upload
curl -X POST https://api.flxbl.dev/api/v1/files/file_abc123/confirm \
  -H "Authorization: Bearer flxbl_your_api_key"

# Response
{
  "id": "file_abc123",
  "tenantId": "tenant_xyz",
  "fileName": "product-hero.jpg",
  "mimeType": "image/jpeg",
  "sizeBytes": 2048576,
  "createdAt": "2026-01-15T10:30:00Z"
}

Download

Request a presigned download URL and fetch the file directly from S3:

# Get a presigned download URL
curl -X GET https://api.flxbl.dev/api/v1/files/file_abc123/download-url \
  -H "Authorization: Bearer flxbl_your_api_key"

# Response
{
  "url": "https://s3.amazonaws.com/bucket/...",
  "fileName": "product-hero.jpg",
  "mimeType": "image/jpeg",
  "expiresAt": "2026-01-15T11:30:00Z"
}

# Download the file
curl -O "https://s3.amazonaws.com/bucket/..."

File Metadata

Field Description
id Unique file identifier
fileName Original file name
mimeType MIME type (e.g., image/jpeg)
sizeBytes File size in bytes (max 100 MB)
entityName Optional associated entity name
entityId Optional associated entity ID
fieldName Optional associated field name
createdAt Upload confirmation timestamp

Other File Endpoints

  • GET /api/v1/files/:id — Get file metadata
  • GET /api/v1/files?entityName=Product&limit=50 — List files with optional filters
  • DELETE /api/v1/files/:id — Delete a file (returns 204)
Tip: FLXBL supports any S3-compatible storage (AWS S3, MinIO, DigitalOcean Spaces, etc.). Configure your storage backend via the FILE_STORAGE_* environment variables.

GraphQL API

FLXBL also generates a complete GraphQL API. The endpoint requires your tenant ID:

# GraphQL endpoint
POST /api/v1/dynamic-gql/:tenantId

# Query example
query {
  products(where: { inStock: { equals: true } }, limit: 10) {
    id
    name
    price
    belongsTo {
      id
      name
    }
  }
}

# Count query - get total count for pagination
query {
  productsCount(where: { inStock: { equals: true } })
}
# Returns: { "data": { "productsCount": 157 } }

# Query with sorting
query {
  products(
    where: { inStock: { equals: true } }
    orderBy: "price"
    orderDirection: ASC
    limit: 20
    offset: 0
  ) {
    id
    name
    price
  }
}

# Mutation example
mutation {
  createProduct(input: {
    name: "New Product"
    price: 99.99
  }) {
    id
    name
    createdAt
  }
}

Download the GraphQL schema:

GET /api/v1/dynamic-gql/{tenantId}/schema.graphql

Cursor-Based Pagination

FLXBL implements the Relay Connection specification for cursor-based pagination, providing stable, efficient pagination even when data changes.

# GraphQL cursor pagination (Relay spec)
query {
  productsConnection(first: 10) {
    edges {
      cursor
      node {
        id
        name
        price
      }
    }
    pageInfo {
      hasNextPage
      hasPreviousPage
      startCursor
      endCursor
    }
    totalCount
  }
}

# Next page using cursor
query {
  productsConnection(first: 10, after: "eyJpZCI6Im5vZGVfMTAifQ==") {
    edges {
      cursor
      node { id name }
    }
    pageInfo { hasNextPage endCursor }
  }
}

# Backward pagination
query {
  productsConnection(last: 10, before: "eyJpZCI6Im5vZGVfMjAifQ==") {
    edges { cursor node { id name } }
    pageInfo { hasPreviousPage startCursor }
  }
}

Pagination arguments:

Argument Description
first Number of items to fetch (forward pagination, max 100)
after Cursor to start after (use endCursor from previous page)
last Number of items to fetch (backward pagination, max 100)
before Cursor to start before (use startCursor from previous page)
Important: You cannot use first and last together. Use first/after for forward pagination or last/before for backward pagination.

GraphQL Batch Mutations

GraphQL also supports batch mutations for bulk operations with the same semantics as REST batch endpoints:

# Batch create mutation
mutation {
  batchCreateProduct(input: [
    { name: "Widget A", price: 29.99 },
    { name: "Widget B", price: 39.99 }
  ]) {
    successful { id name price }
    failed { index error { code message field } }
    successCount
    failureCount
  }
}

# Batch update mutation
mutation {
  batchUpdateProduct(input: [
    { id: "node_abc", data: { price: 24.99 } },
    { id: "node_def", data: { price: 34.99 } }
  ]) {
    successful { id name price }
    successCount
  }
}

# Batch delete mutation
mutation {
  batchDeleteProduct(ids: ["node_abc", "node_def"]) {
    successful { id }
    successCount
    failureCount
  }
}

Available batch mutations for each entity:

  • batchCreate{Entity} - Create multiple entities
  • batchUpdate{Entity} - Update multiple entities by ID
  • batchDelete{Entity} - Delete multiple entities by ID

Integrate with External Tools

FLXBL generates standard OpenAPI and GraphQL specifications that work with your favorite API tools.

Postman / Insomnia

Import your schema's OpenAPI spec directly into Postman or Insomnia for interactive API testing:

  1. Download your OpenAPI spec: GET /api/v1/schemas/:schemaId/openapi.json
  2. In Postman: Import → File → Select openapi.json
  3. All your entity endpoints, authentication, and request bodies are ready to use

Apollo Sandbox / GraphiQL

Connect Apollo Sandbox or GraphiQL to your GraphQL endpoint for schema exploration and query building:

  1. Point your GraphQL client to POST /api/v1/dynamic-gql/:tenantId
  2. Include your API key in the Authorization: Bearer flxbl_xxx header
  3. Download the schema: GET /api/v1/dynamic-gql/:tenantId/schema.graphql
Tip: The GraphQL endpoint supports introspection, so tools like Apollo Sandbox will automatically discover your schema's types and operations.

Rate Limiting

FLXBL implements multi-layer rate limiting:

Layer Default Limit Scope
Global 500 req/min Per IP address
Auth endpoints 20 req/min Per IP address
Tenant 300 req/min Per tenant

Rate limit information is included in response headers:

# Rate limit headers in response
X-RateLimit-Limit: 100          # Max requests per window
X-RateLimit-Remaining: 95       # Requests remaining
X-RateLimit-Reset: 60           # Seconds until reset

When rate limited, the API returns 429 Too Many Requests. Use the X-RateLimit-Reset header to know when to retry.

Error Responses

Errors follow a consistent format:

Status Meaning
400 Bad request - Invalid input or missing required fields
401 Unauthorized - Missing or invalid authentication
403 Forbidden - Insufficient permissions
404 Not found - Entity or resource doesn't exist
429 Too many requests - Rate limit exceeded
500 Internal error - Server-side issue

Next Steps

  • SDK - Type-safe client for programmatic API access
  • CLI - Generate typed SDKs and manage schemas from your terminal
  • Query DSL - Learn the powerful query language
  • Schema Design - Design better schemas
  • MCP Integration - AI-assisted development