Irongist API Documentation

The Irongist API allows you to interact with your encrypted database tables using simple HTTP requests. All values are automatically encrypted, indexed (when possible), and decrypted internally.

💡 Tip: This API is designed to behave like a lightweight database engine with built-in encryption and automatic indexing.

Base URL

POST /api/{keyId}/{action}

Actions: insert, select, update, delete

Example: POST /api/abc123def456/select

Authentication

X-API-KEY: your_api_key_here
⚠️ Required for all requests. Requests without a valid API key will be rejected with a 401 error.

Column Types

TypeStorage FormatNormalizationExample Input
textEncrypted stringLowercase, trimmed"Hello World" → "hello world"
numberEncrypted stringNormalized numeric (removes trailing zeros)"123.00" → "123"
dateEncrypted stringY-m-d format"2024-12-25"
timestampEncrypted stringY-m-d H:i:s format"2024-12-25 14:30:00"
emailEncrypted stringLowercase, trimmed"User@Example.com" → "user@example.com"
⚠️ Important: All values are normalized before encryption. This affects comparisons (e.g., text is case-insensitive, "John" equals "JOHN").

System Fields

Every table has these automatic system fields:

  • id - Auto-incrementing primary key (number)
  • createdAt - Unix timestamp when row was created
  • updatedAt - Unix timestamp when row was last updated
💡 Note: System fields are automatically indexed and can be used in WHERE clauses and ORDER BY.

Insert

Insert a new record into the table.

Request Example

POST /api/abc123/insert
X-API-KEY: your_api_key

{
    "first_name": "John",
    "last_name": "Doe",
    "email": "john@example.com",
    "age": 30
}

Response Example

{
    "action": "insert",
    "record": {
        "id": 1,
        "createdAt": 1775946157,
        "updatedAt": 1775946157,
        "first_name": "John",
        "last_name": "Doe",
        "email": "john@example.com",
        "age": 30
    }
}
⚠️ Required: All custom fields defined in the table must be provided.

Select

Query records from the table.

Request Parameters

ParameterTypeRequiredDefaultDescription
selectarray✅ Yes-Fields to return (system + custom fields)
whereobject❌ No{}Filter conditions
orderByobject❌ Noid ASCSorting (system fields only)
limitinteger❌ No50Max records to return (max 100)
offsetinteger❌ No0Number of records to skip

Basic Examples

Get all records (first 50)

{
    "select": ["id", "first_name", "email", "createdAt"]
}

Get all records with custom limit and offset (pagination)

{
    "select": ["first_name", "email"],
    "limit": 20,
    "offset": 0
}

Page 2 (records 21-40)

{
    "select": ["first_name", "email"],
    "limit": 20,
    "offset": 20
}

With exact match (uses index - fast)

{
    "select": ["first_name", "email"],
    "where": {
        "email": { "eq": "john@example.com" }
    }
}

With multiple conditions (implicit AND)

{
    "select": ["first_name", "email", "age"],
    "where": {
        "email": { "eq": "john@example.com" },
        "age": { "gt": 18 }
    }
}

With IN operator (uses index - fast)

{
    "select": ["first_name", "email"],
    "where": {
        "id": { "in": [1, 2, 3, 4, 5] }
    }
}

With BETWEEN operator (range)

{
    "select": ["first_name", "age"],
    "where": {
        "age": { "between": [18, 65] }
    }
}

With LIKE operator (pattern matching)

{
    "select": ["first_name", "email"],
    "where": {
        "first_name": { "like": "%john%" }
    }
}

Order By Examples

⚠️ Note: ORDER BY only works on system fields: id, createdAt, updatedAt. Custom fields cannot be ordered.

Sort by createdAt descending (newest first)

{
    "select": ["first_name", "email"],
    "orderBy": {
        "createdAt": "DESC"
    },
    "limit": 10
}

Sort by id ascending (oldest first)

{
    "select": ["first_name", "email"],
    "orderBy": {
        "id": "ASC"
    }
}

Multiple sort fields

{
    "select": ["first_name", "email"],
    "orderBy": {
        "createdAt": "DESC",
        "id": "ASC"
    },
    "limit": 20
}

Complex WHERE Examples

OR condition

{
    "select": ["first_name", "email"],
    "where": {
        "OR": [
            { "email": { "eq": "john@example.com" } },
            { "email": { "eq": "jane@example.com" } }
        ]
    }
}

Nested AND/OR

{
    "select": ["first_name", "email", "age"],
    "where": {
        "AND": [
            {
                "OR": [
                    { "first_name": { "like": "%john%" } },
                    { "first_name": { "like": "%jane%" } }
                ]
            },
            { "age": { "gte": 18 } },
            { "status": { "eq": "active" } }
        ]
    },
    "orderBy": { "createdAt": "DESC" },
    "limit": 50,
    "offset": 0
}

Complex pagination example

{
    "select": ["id", "first_name", "email", "createdAt", "updatedAt"],
    "where": {
        "AND": [
            { "status": { "eq": "active" } },
            { "createdAt": { "gte": 1700000000 } }
        ]
    },
    "orderBy": { "createdAt": "DESC" },
    "limit": 25,
    "offset": 50
}

Response Format

{
    "data": [
        {
            "id": 1,
            "createdAt": 1775946157,
            "updatedAt": 1775946157,
            "first_name": "John",
            "email": "john@example.com"
        }
    ],
    "limit": 50,
    "offset": 0
}
⚡ Performance: eq and in queries use indexes for fast lookups. Other operators (like, gt, lt, between, neq) fall back to full scan.

Update

Update existing records.

⚠️ Safety Feature: UPDATE requests MUST include a where clause. This prevents accidental updates of all records in the table.

Request Example

POST /api/abc123/update
X-API-KEY: your_api_key

{
    "update": {
        "first_name": "Jonathan",
        "age": 31
    },
    "where": {
        "id": { "eq": 1 }
    }
}

Response Example

{
    "action": "update",
    "affected": 1
}

Update Multiple Records

{
    "update": {
        "status": "inactive"
    },
    "where": {
        "age": { "lt": 18 }
    }
}

Invalid Request (Will Be Rejected)

{
    "update": {
        "status": "inactive"
    }
    // Missing "where" clause - REJECTED
}
💡 Note: The response shows the number of affected rows. Updated rows are automatically re-encrypted and re-indexed.

Delete

Delete records from the table.

⚠️ Safety Feature: DELETE requests MUST include a non-empty where clause. This prevents accidental deletion of all records in the table.

Request Example

POST /api/abc123/delete
X-API-KEY: your_api_key

{
    "where": {
        "id": { "eq": 1 }
    }
}

Response Example

{
    "action": "delete",
    "deleted": 1
}

Delete Multiple Records

{
    "where": {
        "status": { "eq": "inactive" }
    }
}

Invalid Requests (Will Be Rejected)

Missing where clause

{
    // No "where" field - REJECTED
}

Empty where clause

{
    "where": {}  // Empty object - REJECTED
}
⚠️ Warning: Always use a specific WHERE condition to avoid deleting unintended records. The API will reject any DELETE request without a non-empty where clause.

WHERE Operators Reference

OperatorDescriptionIndexed?Example
eqEquals✅ Yes{"age": {"eq": 25}}
neqNot equals❌ No{"status": {"neq": "deleted"}}
gtGreater than❌ No{"age": {"gt": 18}}
gteGreater than or equal❌ No{"age": {"gte": 18}}
ltLess than❌ No{"age": {"lt": 65}}
lteLess than or equal❌ No{"age": {"lte": 65}}
likePattern matching❌ No{"name": {"like": "%john%"}}
inIn array✅ Yes{"id": {"in": [1,2,3]}}
betweenRange❌ No{"age": {"between": [18,65]}}
💡 Tip: Use indexed operators (eq, in) whenever possible for best performance.

Pagination Guide

Use limit and offset to paginate through results.

Pagination Formulas

  • Page 1: {"limit": 20, "offset": 0}
  • Page 2: {"limit": 20, "offset": 20}
  • Page 3: {"limit": 20, "offset": 40}
  • Page N: {"limit": L, "offset": (N-1) * L}

Complete Pagination Example

{
    "select": ["id", "first_name", "email", "createdAt"],
    "where": {
        "status": { "eq": "active" }
    },
    "orderBy": { "createdAt": "DESC" },
    "limit": 20,
    "offset": 40
}
⚠️ Limits: Maximum limit is 100. Requests with limit > 100 will be capped to 100 automatically.

Performance Guide

Fast Operations (Use Index)

  • eq on any field (system or custom)
  • in on any field
  • ✅ Queries with only eq and in operators

Slow Operations (Full Scan)

  • ⚠️ like - Pattern matching requires scanning all rows
  • ⚠️ gt, gte, lt, lte - Range queries on encrypted data
  • ⚠️ between - Range queries
  • ⚠️ neq - Not equals
  • ⚠️ Mixed queries with any slow operator

Best Practices

  • Always use limit to restrict result size
  • Use indexed operators for WHERE clauses on large tables
  • Avoid deep nesting (>3 levels) of AND/OR conditions
  • Keep limit reasonable (10-50 for good performance)
  • Use specific eq filters before range filters
📊 Performance Tip: For tables with >10,000 rows, prefer eq and in queries over like or range queries.

Limits & Constraints

ConstraintValueDescription
Max limit100Maximum records per request
Default limit50Default if not specified
Max nesting depth10Maximum AND/OR nesting levels
ORDER BY fieldsid, createdAt, updatedAtOnly system fields support ordering
Min text length1Text fields cannot be empty

Error Responses

Error Format

{
    "error": "Error message description",
    "status": 400
}

Common Error Codes

  • 400 - Bad Request (invalid JSON, missing fields, invalid operator)
  • 401 - Unauthorized (invalid or missing API key)
  • 404 - Not Found (table doesn't exist)
  • 500 - Internal Server Error

Example Error Responses

Invalid Field

{
    "error": "Invalid field in select: unknown_field",
    "status": 400
}

Missing Required Fields

{
    "error": "For insert action please make sure all columns are present, missing: first_name",
    "status": 400
}

Invalid Value Type

{
    "error": "Invalid email value for email",
    "status": 400
}

Complete Working Examples

Example 1: User Registration Flow

// 1. Insert new user
POST /api/users/insert
{
    "first_name": "John",
    "last_name": "Doe",
    "email": "john@example.com",
    "age": 30,
    "status": "active"
}

// 2. Query the user
POST /api/users/select
{
    "select": ["first_name", "last_name", "email", "createdAt"],
    "where": {
        "email": { "eq": "john@example.com" }
    }
}

// 3. Update user
POST /api/users/update
{
    "update": {
        "age": 31,
        "status": "inactive"
    },
    "where": {
        "id": { "eq": 1 }
    }
}

// 4. Delete user
POST /api/users/delete
{
    "where": {
        "id": { "eq": 1 }
    }
}

Example 2: Paginated User List

// Get active users, page 1 (records 1-20)
{
    "select": ["id", "first_name", "last_name", "email", "createdAt"],
    "where": {
        "status": { "eq": "active" }
    },
    "orderBy": { "createdAt": "DESC" },
    "limit": 20,
    "offset": 0
}

// Get active users, page 2 (records 21-40)
{
    "select": ["id", "first_name", "last_name", "email", "createdAt"],
    "where": {
        "status": { "eq": "active" }
    },
    "orderBy": { "createdAt": "DESC" },
    "limit": 20,
    "offset": 20
}

Example 3: Search Functionality

{
    "select": ["id", "first_name", "last_name", "email"],
    "where": {
        "OR": [
            { "first_name": { "like": "%john%" } },
            { "last_name": { "like": "%john%" } },
            { "email": { "like": "%john%" } }
        ]
    },
    "limit": 50,
    "offset": 0
}

Example 4: Advanced Filtering with Range

{
    "select": ["id", "first_name", "age", "createdAt"],
    "where": {
        "AND": [
            { "status": { "eq": "active" } },
            { "age": { "between": [25, 40] } },
            { "createdAt": { "gte": 1700000000 } }
        ]
    },
    "orderBy": { "age": "DESC" },
    "limit": 30,
    "offset": 0
}