# Backend branching
Source: https://docs.insforge.dev/agent-native/branching
Spin up an isolated copy of your project to test schema and config changes
A branch is a child project with its own Postgres, auth config, storage, edge functions, email templates, realtime channels, and schedules. Merge back when ready or reset and retry. Available on InsForge OSS 2.1.0+.
## Concepts
Each branch runs on its own EC2 instance, restored from the parent at create time. `merge` runs a three-way diff against the parent's create-time state. The branch shares the parent's `JWT_SECRET` but gets its own `API_KEY`. Compute services and frontend deployments do not branch.
## Usage
Create a branch with `full` (schema + data) or `schema-only` (faster, empty user tables).
```bash theme={null}
npx @insforge/cli branch create feat-billing --mode full
npx @insforge/cli branch list
```
Preview the merge SQL before applying.
```bash theme={null}
npx @insforge/cli branch merge feat-billing --dry-run --save-sql ./preview.sql
npx @insforge/cli branch merge feat-billing
```
Roll back to the create-time snapshot, or delete the branch.
```bash theme={null}
npx @insforge/cli branch reset feat-billing
npx @insforge/cli branch delete feat-billing
```
## Specific usage cases
Use a branch for risky schema migrations, RLS rewrites, OAuth provider swaps, and edge function refactors. Skip it for trivial changes and data backfills (user-data rows are not auto-merged).
Merges block on conflicts. Resolve on the branch or reset and retry. Quotas: 3 parent projects per org, 2 active branches per parent, no nesting. A successful merge does not auto-delete the branch.
## More resources
* [Database migrations](/core-concepts/database/migrations) for forward-only SQL files.
* [Database overview](/core-concepts/database/overview) for what runs under each branch.
* [CLI reference](https://github.com/InsForge/InsForge) for the full `branch` flag set.
# CLI harness
Source: https://docs.insforge.dev/agent-native/cli-harness
The InsForge CLI is the agent's hands: one terminal interface for schema, config, deploys, and diagnostics.
The `@insforge/cli` is the interface a coding agent uses to operate your backend. Where a human reaches for the dashboard, the agent reaches for the terminal: it runs a command, reads the output, and decides what to do next. Every command speaks `--json`, so the agent works from structured data instead of scraping a screen.
Run the CLI with `npx @insforge/cli`. Do not install it globally, so the agent always uses the version pinned to the project.
## Why a CLI for agents
A dashboard is built for a human pointer; a CLI is built for anything that can write text. Pass `--json` to any command and the agent gets a structured result it can parse; pass `--yes` and it runs without stopping for a confirmation prompt. Schema, auth config, storage, functions, deploys, branches, and diagnostics are all subcommands of the same tool, so there is one surface to learn instead of a dashboard to navigate. It runs in any terminal, any editor, or CI, with no integration to set up. And after a change, the agent can run [`npx @insforge/cli diagnose`](/agent-native/diagnostics) and read back exactly what broke.
## Command surface
| Area | Commands |
| -------------- | -------------------------------------------------------------------------- |
| Auth & context | `login`, `logout`, `whoami`, `current`, `list` |
| Project | `create`, `link` |
| Schema | `db migrations new`, `db migrations up`, `db migrations list` |
| Config as code | `config plan`, `config apply`, `config export` |
| Branching | `branch create`, `branch merge`, `branch reset`, `branch delete` |
| Build | `functions`, `storage`, `deployments`, `secrets`, `schedules`, `ai` |
| Diagnose | `diagnose`, `diagnose advisor`, `diagnose db`, `diagnose logs`, `metadata` |
Run `npx @insforge/cli help ` for the flags on any of these.
## A typical agent run
```bash theme={null}
# connect
npx @insforge/cli login
npx @insforge/cli link
# read current state
npx @insforge/cli --json metadata
# change schema, safely
npx @insforge/cli db migrations new add-orders-table
npx @insforge/cli db migrations up --all
# check the result
npx @insforge/cli diagnose --json
```
## Let the agent interpret the output
Diagnostics ships an AI flag so the agent can hand its own backend data to a model and get back an explanation:
```bash theme={null}
npx @insforge/cli diagnose --ai "why are auth requests failing after the last migration?"
```
This pairs the raw signals (advisor findings, DB health, error logs) with a plain-language read, which is what turns "here is a stack trace" into "here is the fix." See [Diagnostics & advisor](/agent-native/diagnostics).
## Next steps
* Put auth, SMTP, storage, retention, and deployment settings in version control with [config as code](/agent-native/config-as-code).
* Test risky changes on a [backend branch](/agent-native/branching) before touching production.
# Config as code
Source: https://docs.insforge.dev/agent-native/config-as-code
Manage InsForge auth, SMTP, storage, retention, and deployment settings declaratively from a single insforge.toml using the CLI's plan, apply, and export workflow.
## Overview
`insforge.toml` is a declarative, version-controlled snapshot of a subset of your project's config: auth policy, allowed redirect URLs, password rules, SMTP, storage upload size, realtime and schedule retention, and the deployment subdomain. The CLI provides three commands that work against this file:
* **`config plan`**: diff `insforge.toml` against the linked project. Shows what would change.
* **`config apply`**: push the diff to the live project. Per-change capability gating, env-resolved secrets, dry-run mode.
* **`config export`**: pull current project state and write a fresh `insforge.toml`. Useful for bootstrapping from an existing project.
You keep **one** `insforge.toml` in your repo. To apply it to a different environment (staging, prod, a teammate's local backend, or a self-hosted instance), point the CLI at a different project (re-link or use `--project-id`). Secrets are read from environment variables via `env(...)` references, so the file itself stays free of credentials and can be committed safely.
This works the same way on InsForge Cloud projects and on self-hosted OSS deployments.
All examples use `npx @insforge/cli`. Do not install the CLI globally.
## Command summary
| Command | Purpose |
| ----------------------------- | -------------------------------------------------------------------- |
| `config plan` | Show diff between `insforge.toml` and live project state |
| `config apply` | Apply `insforge.toml` to the live project |
| `config apply --dry-run` | Print the plan without applying |
| `config apply --auto-approve` | Skip the interactive confirmation prompt (required in `--json` mode) |
| `config export` | Pull live config and write `insforge.toml` |
| `config export --force` | Overwrite an existing `insforge.toml` without confirmation |
`config plan` and `config apply` read `insforge.toml`; pass `--file ` if it lives somewhere other than `./insforge.toml`. `config export` writes the file; pass `--out ` to write it to a custom location.
## Recommended workflow
If you already configured the project through the dashboard, export it once to get a working file:
```bash theme={null}
npx @insforge/cli config export
```
This writes `insforge.toml` reflecting the current backend state.
Check `insforge.toml` into version control. Secrets are referenced via `env(...)`, so the file is safe to commit.
Change the TOML, then preview the diff before applying:
```bash theme={null}
npx @insforge/cli config plan
```
```bash theme={null}
npx @insforge/cli config apply
```
Review the rendered plan and confirm. In CI, pass `--auto-approve` and `--json`.
To push the same config to staging or a self-hosted backend, point the CLI at the other project and re-run apply:
```bash theme={null}
npx @insforge/cli --project-id config apply
```
Secrets that differ between environments (SMTP password, etc.) are resolved per-environment from the local shell, so the TOML doesn't need to change.
## What `insforge.toml` covers
The file mirrors a curated subset of project config, the parts that are useful to manage declaratively. Anything not in this list still lives on the dashboard and the API.
| Section | Keys |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `[auth]` | `allowed_redirect_urls`, `require_email_verification`, `verify_email_method`, `reset_password_method`, `disable_signup` |
| `[auth.password]` | `min_length`, `require_number`, `require_lowercase`, `require_uppercase`, `require_special_char` |
| `[auth.smtp]` | `enabled`, `host`, `port`, `username`, `password`, `sender_email`, `sender_name`, `min_interval_seconds` |
| `[storage]` | `max_file_size_mb` |
| `[realtime]` | `retention_days` |
| `[schedules]` | `retention_days` |
| `[deployments]` | `subdomain` |
Because TOML has no `null` literal, use `retention_days = 0` to disable retention cleanup for realtime messages or schedule execution logs; `config apply` sends `null` to the backend for that value. Email templates, OAuth provider app credentials, buckets, realtime channels, functions, deployment environment variables, and secrets are not managed through this file.
A complete example:
```toml theme={null}
[auth]
require_email_verification = true
verify_email_method = "code"
reset_password_method = "code"
disable_signup = false
allowed_redirect_urls = [
"https://app.example.com/auth/callback",
"http://localhost:3000/auth/callback",
]
[auth.password]
min_length = 12
require_number = true
require_lowercase = true
require_uppercase = true
require_special_char = false
[auth.smtp]
enabled = true
host = "smtp.sendgrid.net"
port = 587
username = "apikey"
password = "env(SENDGRID_API_KEY)"
sender_email = "noreply@example.com"
sender_name = "Acme"
[storage]
max_file_size_mb = 100
[realtime]
retention_days = 7
[schedules]
retention_days = 0
[deployments]
subdomain = "acme-prod"
```
## `config plan`
```bash theme={null}
npx @insforge/cli config plan
npx @insforge/cli config plan --file ./config/insforge.toml
npx @insforge/cli --json config plan
```
`plan` reads `insforge.toml`, fetches live state via `/api/metadata` and the optional config endpoints for storage, realtime, and schedules, then prints a rendered diff. It also tags any section the live backend doesn't expose yet (older self-hosted versions, etc.). Apply will skip those instead of failing the whole run.
Use `plan` before every `apply` in interactive sessions, and as a CI gate to catch unintended drift.
## `config apply`
```bash theme={null}
npx @insforge/cli config apply
npx @insforge/cli config apply --dry-run
npx @insforge/cli config apply --auto-approve
npx @insforge/cli --json config apply --auto-approve
```
`apply` runs the same diff as `plan`, then walks the change set:
1. **Per-change capability gate.** Each change is checked against the backend's metadata or the section's config endpoint. If the backend doesn't support a section (e.g. an older self-hosted instance without SMTP exposed), that section is skipped with a named warning, and the rest of the changes still apply.
2. **Secret resolution.** `env(...)` references in the TOML are resolved at apply time from the local environment. If a referenced variable is missing, the command aborts before sending any update, so the backend isn't left half-configured.
3. **Per-section dispatch.** Each change is sent to the appropriate backend endpoint (`/api/auth/config`, `/api/auth/smtp-config`, `/api/storage/config`, `/api/realtime/config`, `/api/schedules/config`, `/api/deployments/slug`, etc.). Changes are independent, so a failure on one section won't roll back earlier successful sections.
Flags:
* `--dry-run` prints the plan and exits without applying.
* `--auto-approve` skips the interactive confirmation. Required when `--json` is set, since there's no TTY for the prompt.
* `--file ` overrides the default `./insforge.toml` location.
## `config export`
```bash theme={null}
npx @insforge/cli config export
npx @insforge/cli config export --out ./config/insforge.toml
npx @insforge/cli config export --force
```
`export` pulls the live project's configurable surface and writes it to a TOML file. Use it to:
* Bootstrap an `insforge.toml` from a project you've been configuring through the dashboard.
* Diff hand-edits against current backend state by exporting to a temporary file and comparing.
* Snapshot config before a risky change so you can re-apply the snapshot if you need to roll back.
The file written by `export` is the same shape the CLI expects from `apply`, so round-tripping is supported.
Without `--force`, `export` refuses to overwrite an existing file in interactive mode and surfaces an `OUTPUT_EXISTS` error in `--json` mode.
## Secret references
`auth.smtp.password` and any other sensitive field can be expressed as `env(VAR_NAME)` instead of a literal value:
```toml theme={null}
[auth.smtp]
password = "env(SENDGRID_API_KEY)"
```
At apply time the CLI reads `SENDGRID_API_KEY` from the local environment, validates it's present, and sends the resolved value to the backend. The TOML itself never contains the secret, so it can be committed.
This is what lets one `insforge.toml` apply cleanly to multiple environments: the dev and prod backends differ only in *which* `SENDGRID_API_KEY` is in scope when you run `apply`.
`env(...)` refs in a TOML that's the target of `apply` re-send the resolved password on every run. That is the only way the CLI can tell the backend "the secret may have rotated, please update." Fields without an `env(...)` ref are treated as preserve-existing.
## When to use this
* **Version control for project config.** Redirect URLs, sign-up policy, password policy, email verification mode, SMTP, storage upload size, and retention windows live in a file your team reviews via PR.
* **Multi-environment parity.** One TOML, applied to dev, staging, and prod, keeps the supported project settings aligned everywhere. Environment-specific values (subdomain, SMTP credentials) flow through `--project-id` overrides and `env(...)` refs.
* **CI-driven config changes.** Run `config apply --auto-approve --json` from your deploy pipeline. Combine with `config plan` as a PR check so reviewers see what the merge will change in prod.
* **Disaster recovery.** A committed `insforge.toml` is a known-good config snapshot. Re-apply it after restoring a project to bring auth, SMTP, storage, retention, and deployment settings back to the expected shape in seconds.
* **Self-hosted and local OSS development.** Run `npx @insforge/cli link --api-base-url http://localhost:7130 --api-key ` against a docker-compose stack, then point the CLI's config commands at your local OSS instance the same way you'd point at cloud.
## Troubleshooting
**`Refusing to apply in --json mode without --auto-approve or --yes`.** The CLI never silently applies changes in non-interactive runs. Pass `--auto-approve` (or `-y`) explicitly.
**`your backend doesn't expose `.** The linked backend is on a version that doesn't have the relevant API yet. The rest of your changes still applied. Upgrade the backend (or wait for the next release) to apply that section.
**`env(...)` reference resolves to nothing.** The CLI aborts before any API call when a referenced env var is missing. Set the variable in your shell or your CI's secret store and re-run.
**`Slug is already taken`.** `deployments.subdomain` conflicts with another project's subdomain on the same backend. Pick a different value.
## Related
* [CLI harness](/agent-native/cli-harness): the full command surface an agent drives
* [Deployment security guide](/deployment/deployment-security-guide): hardening a self-hosted backend after deploy
# Diagnostics & advisor
Source: https://docs.insforge.dev/agent-native/diagnostics
The agent reads backend health, advisor findings, and error logs, then applies the fix.
When something breaks, an agent should not have to guess. `npx @insforge/cli diagnose` turns the backend's own signals into something an agent can fetch and act on directly: advisor findings with remediations, database health checks, instance metrics, and aggregated error logs. Each finding comes with a fix, so "what is wrong" and "what to do about it" arrive together. The agent pulls all of this itself, with no dashboard in the loop, which is what lets it close security gaps like a permissive RLS policy before they leak data.
## Full health report
Run `diagnose` with no subcommand for everything at once:
```bash theme={null}
npx @insforge/cli diagnose
npx @insforge/cli diagnose --json
```
The report bundles the advisor scan, database health, instance metrics, and recent error logs into one output. In `--json` mode the agent gets it all as structured data.
## Backend Advisor
The advisor scans for security, performance, and health issues and writes a remediation for each one. The dashboard shows the findings with a "Copy Remediation" button, but the agent does not need the dashboard: it fetches the same scan directly with `--json` and applies the fix itself, so a security issue gets closed without waiting for a human to notice it.
```bash theme={null}
npx @insforge/cli diagnose advisor
npx @insforge/cli diagnose advisor --json
```
A typical finding is a permissive RLS policy that exposes a table to anonymous users. The advisor names the table, the severity, and the SQL to fix it. The agent reads the finding, applies the remediation as a [migration](/core-concepts/database/migrations), and re-scans to confirm it cleared.
## Targeted checks
Each part of the report is also available on its own:
| Command | What it checks |
| ------------------ | ------------------------------------------------------------- |
| `diagnose advisor` | Latest advisor scan: security, performance, and health issues |
| `diagnose db` | Database health: connections, table bloat, index usage |
| `diagnose metrics` | Instance metrics: CPU, memory, disk, and network |
| `diagnose logs` | Error-level logs aggregated across every backend source |
For raw logs from a single source, use the top-level command:
```bash theme={null}
npx @insforge/cli logs function.logs
npx @insforge/cli logs postgres.logs
```
Sources include `insforge.logs`, `postgREST.logs`, `postgres.logs`, `function.logs`, and `function-deploy.logs`.
## Let the agent interpret it
`diagnose --ai` hands the collected diagnostic data to a model and returns a plain-language analysis:
```bash theme={null}
npx @insforge/cli diagnose --ai "why did write latency spike after the last deploy?"
```
This is the difference between dumping a stack trace and explaining the fix. The agent asks a question about the live backend and gets an answer grounded in the actual signals.
## Next steps
* Apply advisor remediations as [migrations](/core-concepts/database/migrations) so the fix is versioned.
* Rehearse a risky fix on a [backend branch](/agent-native/branching) before it touches production.
* Read the [CLI harness](/agent-native/cli-harness) for the rest of the command surface.
# Agent-Native Initiatives
Source: https://docs.insforge.dev/agent-native/overview
The primitives that let a coding agent operate your backend, not just a human clicking a dashboard.
Most backends assume a human in a dashboard. InsForge assumes a coding agent at a terminal. The products (Database, Auth, Storage, and the rest) are the building blocks; the primitives on this page are how an agent operates them: as files it can edit, branches it can test on, and a backend it can diagnose and fix on its own.
New here? Start with [Connect via CLI](/quickstart) to link your project. This section is about how an agent *works* with the backend once it is connected.
## The primitives
The agent's hands. One terminal interface for login, schema, deploys, config, and diagnostics.
Pull advisor findings, DB health, metrics, and error logs the agent can read and fix.
Auth, SMTP, storage, retention, and deployment settings live in `insforge.toml`. Plan and apply like infrastructure.
Clone the whole backend into an isolated branch to test risky changes, then merge or reset.
## Why it matters
A person and an agent want different things from a backend. A person wants a UI to click. An agent wants a stable text interface it can drive, read back, and reason about. That shows up everywhere in InsForge.
Schema changes are [migrations](/core-concepts/database/migrations) in your repo, and project config is an [`insforge.toml`](/agent-native/config-as-code) file, so the agent edits text, commits it, and reviews it in a PR instead of clicking through forms. When it wants to try something risky, it spins up a [backend branch](/agent-native/branching), runs the change against a copy, and throws the branch away if it goes wrong. When something looks off, it fetches [diagnostics and advisor findings](/agent-native/diagnostics) directly with `npx @insforge/cli diagnose`, no dashboard in the loop, and applies the fix itself. That last part is also how the backend gets more secure: the agent reads a security finding like a permissive RLS policy and remediates it on its own, instead of waiting for a human to remember to check. And it reads current schemas, logs, and metadata straight from the backend with `npx @insforge/cli metadata`, so it works from real state rather than guessing.
## The loop
These chain together. A session usually goes:
1. Read the current state with `npx @insforge/cli metadata`.
2. Branch the backend, write a [migration](/core-concepts/database/migrations) and check what is pending with `npx @insforge/cli db migrations list`, or edit `insforge.toml` and preview the config diff with `npx @insforge/cli config plan`.
3. Apply it with `npx @insforge/cli db migrations up --all` or `config apply`, against the branch first, then the parent.
4. Run `npx @insforge/cli diagnose` to check advisor findings and error logs, and ask `diagnose --ai` to interpret them.
5. Apply the remediation, re-run diagnose, and merge the branch.
## Next steps
* Read the [CLI harness](/agent-native/cli-harness) to see the full command surface an agent drives.
* Set up [config as code](/agent-native/config-as-code) so project settings live in version control.
* Use [diagnostics](/agent-native/diagnostics) to let the agent find and fix backend issues.
# Admin login
Source: https://docs.insforge.dev/api-reference/admin/admin-login
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/admin/sessions
Authenticates admin user for dashboard access
# Clear logs
Source: https://docs.insforge.dev/api-reference/admin/clear-logs
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/logs.yaml delete /api/logs
# Create a new secret
Source: https://docs.insforge.dev/api-reference/admin/create-a-new-secret
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/secrets.yaml post /api/secrets
Create a new encrypted secret with a unique key
# Create and Execute Database Migration
Source: https://docs.insforge.dev/api-reference/admin/create-and-execute-database-migration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/tables.yaml post /api/database/migrations
# Create custom OAuth configuration
Source: https://docs.insforge.dev/api-reference/admin/create-custom-oauth-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/oauth/custom/configs
Create a new custom OAuth provider configuration (admin only)
# Create New Bucket
Source: https://docs.insforge.dev/api-reference/admin/create-new-bucket
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml post /api/storage/buckets
# Create new function
Source: https://docs.insforge.dev/api-reference/admin/create-new-function
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/functions.yaml post /api/functions
Create a new function with code that runs in Deno runtime
# Create OAuth configuration
Source: https://docs.insforge.dev/api-reference/admin/create-oauth-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/oauth/configs
Create a new OAuth provider configuration (admin only)
# Create Table
Source: https://docs.insforge.dev/api-reference/admin/create-table
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/tables.yaml post /api/database/tables
# Delete Bucket
Source: https://docs.insforge.dev/api-reference/admin/delete-bucket
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml delete /api/storage/buckets/{bucketName}
Delete an entire bucket and all its objects
# Delete custom OAuth configuration
Source: https://docs.insforge.dev/api-reference/admin/delete-custom-oauth-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml delete /api/auth/oauth/custom/{key}/config
Delete a custom OAuth provider configuration (admin only)
# Delete function
Source: https://docs.insforge.dev/api-reference/admin/delete-function
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/functions.yaml delete /api/functions/{slug}
Permanently delete a function
# Delete OAuth configuration
Source: https://docs.insforge.dev/api-reference/admin/delete-oauth-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml delete /api/auth/oauth/{provider}/config
Delete OAuth provider configuration (admin only)
# Delete secret
Source: https://docs.insforge.dev/api-reference/admin/delete-secret
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/secrets.yaml delete /api/secrets/{key}
Mark a secret as inactive (soft delete). Cannot delete reserved secrets.
# Delete Table
Source: https://docs.insforge.dev/api-reference/admin/delete-table
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/tables.yaml delete /api/database/tables/{tableName}
# Delete users (admin only)
Source: https://docs.insforge.dev/api-reference/admin/delete-users-admin-only
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml delete /api/auth/users
Delete multiple users by their IDs
# Exchange cloud provider authorization code for admin session
Source: https://docs.insforge.dev/api-reference/admin/exchange-cloud-provider-authorization-code-for-admin-session
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/admin/sessions/exchange
Verifies an authorization code/JWT from from Insforge Cloud platform and issues an internal admin session token with project_admin role
# Get active OpenRouter API key
Source: https://docs.insforge.dev/api-reference/admin/get-active-openrouter-api-key
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/ai.yaml get /api/ai/openrouter/api-key
Returns the active OpenRouter API key details for admin copy workflows.
# Get all available AI models
Source: https://docs.insforge.dev/api-reference/admin/get-all-available-ai-models
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/ai.yaml get /api/ai/models
Returns the normalized OpenRouter model catalog fetched from OpenRouter with output_modalities=all.
# Get anon key
Source: https://docs.insforge.dev/api-reference/admin/get-anon-key
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/metadata.yaml get /api/metadata/anon-key
Admin-only endpoint to retrieve the project's opaque anon key (`anon_...`). The anon key is a non-secret client identifier that maps requests to the `anon` role - safe to embed in frontend bundles; row level security is the security boundary. Rotatable via POST /api/secrets/anon-key/rotate.
# Get anon key (deprecated)
Source: https://docs.insforge.dev/api-reference/admin/get-anon-key-deprecated
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/tokens/anon
Deprecated - use GET /api/metadata/anon-key instead. Returns the project's opaque anon key (`anon_...`) under the legacy `accessToken` field for backward compatibility. The anon key is a non-secret client identifier that maps requests to the `anon` role; it replaces the former non-expiring anonymous JWT and can be rotated via POST /api/secrets/anon-key/rotate (admin only).
# Get API key
Source: https://docs.insforge.dev/api-reference/admin/get-api-key
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/metadata.yaml get /api/metadata/api-key
Admin-only endpoint to retrieve the API key
# Get app metadata
Source: https://docs.insforge.dev/api-reference/admin/get-app-metadata
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/metadata.yaml get /api/metadata
Returns aggregated application metadata (auth, database, storage, functions, realtime, deployments). Use the `format` query parameter to choose between JSON and Markdown output.
# Get authentication configuration
Source: https://docs.insforge.dev/api-reference/admin/get-authentication-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/config
Get current authentication settings including all configuration options (admin only)
# Get custom OAuth configuration
Source: https://docs.insforge.dev/api-reference/admin/get-custom-oauth-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/oauth/custom/{key}/config
Get a custom OAuth configuration including client secret (admin only)
# Get database metadata
Source: https://docs.insforge.dev/api-reference/admin/get-database-metadata
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/metadata.yaml get /api/metadata/database
Get database statistics and table information for dashboard
# Get function details
Source: https://docs.insforge.dev/api-reference/admin/get-function-details
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/functions.yaml get /api/functions/{slug}
Get a specific function including its code
# Get logs statistics
Source: https://docs.insforge.dev/api-reference/admin/get-logs-statistics
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/logs.yaml get /api/logs/stats
# Get Model Gateway overview
Source: https://docs.insforge.dev/api-reference/admin/get-model-gateway-overview
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/ai.yaml get /api/ai/overview
Returns key-level OpenRouter usage and activity time series when the key has activity access.
# Get OAuth configuration for specific provider
Source: https://docs.insforge.dev/api-reference/admin/get-oauth-configuration-for-specific-provider
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/oauth/{provider}/config
Get OAuth configuration including client secret (admin only)
# Get secret value
Source: https://docs.insforge.dev/api-reference/admin/get-secret-value
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/secrets.yaml get /api/secrets/{key}
Retrieve the decrypted value of a specific secret by its key
# Get specific user
Source: https://docs.insforge.dev/api-reference/admin/get-specific-user
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/users/{userId}
Get user details by ID (admin only)
# Get Table Schema
Source: https://docs.insforge.dev/api-reference/admin/get-table-schema
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/tables.yaml get /api/database/tables/{tableName}/schema
# List activity logs
Source: https://docs.insforge.dev/api-reference/admin/list-activity-logs
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/logs.yaml get /api/logs
# List All Buckets
Source: https://docs.insforge.dev/api-reference/admin/list-all-buckets
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml get /api/storage/buckets
# List all custom OAuth configurations
Source: https://docs.insforge.dev/api-reference/admin/list-all-custom-oauth-configurations
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/oauth/custom/configs
Get all configured custom OAuth providers (admin only)
# List all functions
Source: https://docs.insforge.dev/api-reference/admin/list-all-functions
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/functions.yaml get /api/functions
Get all functions with their metadata
# List all OAuth configurations
Source: https://docs.insforge.dev/api-reference/admin/list-all-oauth-configurations
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/oauth/configs
Get all configured OAuth providers (admin only)
# List all secrets
Source: https://docs.insforge.dev/api-reference/admin/list-all-secrets
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/secrets.yaml get /api/secrets
Returns metadata for all secrets (without values)
# List all users (admin only)
Source: https://docs.insforge.dev/api-reference/admin/list-all-users-admin-only
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/users
Returns paginated list of users
# List Database Migrations
Source: https://docs.insforge.dev/api-reference/admin/list-database-migrations
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/tables.yaml get /api/database/migrations
# List Objects in Bucket
Source: https://docs.insforge.dev/api-reference/admin/list-objects-in-bucket
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml get /api/storage/buckets/{bucketName}/objects
# List Tables
Source: https://docs.insforge.dev/api-reference/admin/list-tables
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/tables.yaml get /api/database/tables
# Logout admin dashboard session
Source: https://docs.insforge.dev/api-reference/admin/logout-admin-dashboard-session
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/admin/logout
Clears the dashboard-only `insforge_admin_refresh_token` cookie.
# Refresh admin dashboard access token
Source: https://docs.insforge.dev/api-reference/admin/refresh-admin-dashboard-access-token
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/admin/refresh
Uses the dashboard-only httpOnly `insforge_admin_refresh_token` cookie with an `X-CSRF-Token` header.
# Rotate anon key
Source: https://docs.insforge.dev/api-reference/admin/rotate-anon-key
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/secrets.yaml post /api/secrets/anon-key/rotate
Rotate the project's opaque anon key (`anon_...`). A new key is generated and returned; the old key stays valid for the grace period (default 168 hours / 7 days, max 720) so already-deployed frontends and mobile binaries keep working while the new key ships. Admin only.
# Update authentication configuration
Source: https://docs.insforge.dev/api-reference/admin/update-authentication-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml put /api/auth/config
Update authentication settings (admin only)
# Update Bucket
Source: https://docs.insforge.dev/api-reference/admin/update-bucket
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml patch /api/storage/buckets/{bucketName}
# Update custom OAuth configuration
Source: https://docs.insforge.dev/api-reference/admin/update-custom-oauth-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml put /api/auth/oauth/custom/{key}/config
Update a custom OAuth provider configuration (admin only)
# Update function
Source: https://docs.insforge.dev/api-reference/admin/update-function
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/functions.yaml put /api/functions/{slug}
Update an existing function's code or metadata
# Update OAuth configuration
Source: https://docs.insforge.dev/api-reference/admin/update-oauth-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml put /api/auth/oauth/{provider}/config
Update OAuth provider configuration (admin only)
# Update secret
Source: https://docs.insforge.dev/api-reference/admin/update-secret
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/secrets.yaml put /api/secrets/{key}
Update an existing secret's value or metadata
# Update Table Schema
Source: https://docs.insforge.dev/api-reference/admin/update-table-schema
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/tables.yaml patch /api/database/tables/{tableName}/schema
# Create Channel
Source: https://docs.insforge.dev/api-reference/channels/create-channel
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml post /api/realtime/channels
Create a new realtime channel with a pattern for subscription matching
# Delete Channel
Source: https://docs.insforge.dev/api-reference/channels/delete-channel
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml delete /api/realtime/channels/{id}
Delete a channel definition. Existing message history is preserved with null channelId values.
# Get Channel by ID
Source: https://docs.insforge.dev/api-reference/channels/get-channel-by-id
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml get /api/realtime/channels/{id}
Retrieve a specific channel by its UUID
# List All Channels
Source: https://docs.insforge.dev/api-reference/channels/list-all-channels
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml get /api/realtime/channels
Retrieve all configured realtime channels
# Update Channel
Source: https://docs.insforge.dev/api-reference/channels/update-channel
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml put /api/realtime/channels/{id}
Update an existing channel's configuration
# Confirm Presigned Upload
Source: https://docs.insforge.dev/api-reference/client/confirm-presigned-upload
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml post /api/storage/buckets/{bucketName}/objects/{objectKey}/confirm-upload
Confirms that a file was successfully uploaded to S3 using presigned URL
# Create Records
Source: https://docs.insforge.dev/api-reference/client/create-records
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/records.yaml post /api/database/records/{tableName}
Create one or more records. Request body MUST be an array.
# Custom OAuth callback (GET)
Source: https://docs.insforge.dev/api-reference/client/custom-oauth-callback-get
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/oauth/custom/{key}/callback
OAuth callback endpoint for custom OAuth providers
# Delete Object
Source: https://docs.insforge.dev/api-reference/client/delete-object
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml delete /api/storage/buckets/{bucketName}/objects/{objectKey}
# Delete Records
Source: https://docs.insforge.dev/api-reference/client/delete-records
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/records.yaml delete /api/database/records/{tableName}
Delete records matching query filters
# Download Object
Source: https://docs.insforge.dev/api-reference/client/download-object
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml get /api/storage/buckets/{bucketName}/objects/{objectKey}
# Exchange OAuth code for tokens (PKCE)
Source: https://docs.insforge.dev/api-reference/client/exchange-oauth-code-for-tokens-pkce
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/oauth/exchange
Exchange the insforge_code (received from OAuth callback) for access and refresh tokens.
This endpoint is used for PKCE flow in mobile/desktop/server clients:
1. After OAuth callback, your redirect_uri receives `insforge_code` parameter
2. Call this endpoint with the code and your original code_verifier
3. Receive access token and refresh token in response
The code_verifier must match the code_challenge sent during OAuth initiation.
# Exchange reset password code for reset token
Source: https://docs.insforge.dev/api-reference/client/exchange-reset-password-code-for-reset-token
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/email/exchange-reset-password-token
Step 1 of two-step password reset flow (only used when resetPasswordMethod is 'code'):
1. Verify the 6-digit code sent to user's email
2. Return a reset token that can be used to actually reset the password
This endpoint is not used when resetPasswordMethod is 'link', because the browser reset-link flow uses the emailed link token directly.
# Execute function (DELETE)
Source: https://docs.insforge.dev/api-reference/client/execute-function-delete
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/functions.yaml delete /functions/{slug}
Execute a function using DELETE method. Proxied to Deno runtime.
# Execute function (GET)
Source: https://docs.insforge.dev/api-reference/client/execute-function-get
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/functions.yaml get /functions/{slug}
Execute a function using GET method. Proxied to Deno runtime.
# Execute function (PATCH)
Source: https://docs.insforge.dev/api-reference/client/execute-function-patch
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/functions.yaml patch /functions/{slug}
Execute a function using PATCH method. Proxied to Deno runtime.
# Execute function (POST)
Source: https://docs.insforge.dev/api-reference/client/execute-function-post
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/functions.yaml post /functions/{slug}
Execute a function using POST method with JSON body. Proxied to Deno runtime.
# Execute function (PUT)
Source: https://docs.insforge.dev/api-reference/client/execute-function-put
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/functions.yaml put /functions/{slug}
Execute a function using PUT method. Proxied to Deno runtime.
# Generate chat completion (deprecated)
Source: https://docs.insforge.dev/api-reference/client/generate-chat-completion-deprecated
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/ai.yaml post /api/ai/chat/completion
Deprecated compatibility proxy. New integrations should call https://openrouter.ai/api/v1/chat/completions directly with the provisioned OpenRouter key.
# Generate embeddings (deprecated)
Source: https://docs.insforge.dev/api-reference/client/generate-embeddings-deprecated
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/ai.yaml post /api/ai/embeddings
Deprecated compatibility proxy. New integrations should call https://openrouter.ai/api/v1/embeddings directly with the provisioned OpenRouter key.
# Generate images (deprecated)
Source: https://docs.insforge.dev/api-reference/client/generate-images-deprecated
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/ai.yaml post /api/ai/image/generation
Deprecated compatibility proxy. New integrations should use OpenRouter image-capable models directly with the provisioned OpenRouter key.
# Get current session
Source: https://docs.insforge.dev/api-reference/client/get-current-session
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/sessions/current
Returns the currently authenticated user's basic info from the access token.
Project admin tokens return a projectAdmin session object instead of an auth.users row.
This endpoint does not refresh expired access tokens by itself.
For browser apps using the TypeScript SDK, call `auth.getCurrentUser()`
during startup. The SDK will use the httpOnly refresh cookie automatically
when it can refresh the session. Server, mobile, and other non-browser
clients should call `/api/auth/refresh` explicitly.
# Get Download Strategy (Deprecated — use GET on the canonical path)
Source: https://docs.insforge.dev/api-reference/client/get-download-strategy-deprecated-—-use-get-on-the-canonical-path
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml post /api/storage/buckets/{bucketName}/objects/{objectKey}/download-strategy
Deprecated alias of
`GET /api/storage/buckets/{bucketName}/download-strategy/objects/{objectKey}`.
Retained at the original path/method for backward compatibility with
SDK releases that already shipped against this POST endpoint. Any
request body is ignored.
# Get Download Strategy (Direct or Presigned URL)
Source: https://docs.insforge.dev/api-reference/client/get-download-strategy-direct-or-presigned-url
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml get /api/storage/buckets/{bucketName}/download-strategy/objects/{objectKey}
Returns download strategy based on storage backend and bucket visibility.
- S3 with public bucket: Direct URLs (no presigning, better performance)
- S3 with private bucket: Presigned URLs with expiration
- Local storage: Always direct endpoints
Expiry (when presigned) is auto-calculated server-side from bucket
visibility; no request body is accepted.
Object keys may contain `/` (pseudo-folders); the path is matched
with a wildcard, so callers should NOT percent-encode `/` inside
`objectKey`.
# Get public authentication configuration
Source: https://docs.insforge.dev/api-reference/client/get-public-authentication-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/public-config
Get all public authentication configuration including OAuth providers and email auth settings (public endpoint)
# Get Upload Strategy (Direct or Presigned URL)
Source: https://docs.insforge.dev/api-reference/client/get-upload-strategy-direct-or-presigned-url
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml post /api/storage/buckets/{bucketName}/upload-strategy
Returns upload strategy based on storage backend (S3 returns presigned URLs, local returns direct upload endpoints)
# Get user profile by ID
Source: https://docs.insforge.dev/api-reference/client/get-user-profile-by-id
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/profiles/{userId}
Get public profile information for a user by their ID (public endpoint)
# Health check
Source: https://docs.insforge.dev/api-reference/client/health-check
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/health.yaml get /api/health
Check if the API is running and healthy
# Initiate custom OAuth flow (PKCE)
Source: https://docs.insforge.dev/api-reference/client/initiate-custom-oauth-flow-pkce
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/oauth/custom/{key}
Generate OAuth authorization URL for a configured custom OAuth provider using PKCE flow
# Initiate OAuth flow (PKCE)
Source: https://docs.insforge.dev/api-reference/client/initiate-oauth-flow-pkce
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/oauth/{provider}
Generate OAuth authorization URL for any supported provider using PKCE flow.
For mobile/desktop/server clients using PKCE:
1. Generate code_verifier (random string, 43-128 chars)
2. Generate code_challenge = Base64URL(SHA256(code_verifier))
3. Call this endpoint with code_challenge
4. After OAuth callback, use /api/auth/oauth/exchange with code_verifier
# Logout user
Source: https://docs.insforge.dev/api-reference/client/logout-user
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/logout
Logout and clear refresh token cookie
# Open password reset flow from browser link click
Source: https://docs.insforge.dev/api-reference/client/open-password-reset-flow-from-browser-link-click
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/email/reset-password-link
Browser-oriented password reset link flow.
This endpoint is intended for users clicking password reset links in email.
It validates the token on the backend and redirects the browser to the
stored, validated `redirectTo` URL with the reset token in the query string.
Redirect query params:
- Ready: `token=...&insforge_status=ready&insforge_type=reset_password`
- Error: `insforge_status=error&insforge_type=reset_password&insforge_error=...`
- `token`: present only when `insforge_status=ready`
- `insforge_status`: `ready` or `error`
- `insforge_type`: always `reset_password`
- `insforge_error`: present only on error, human-readable message
Your app should render the reset-password form only when `insforge_status=ready`
and `token` is present.
# Provider-specific OAuth callback (GET)
Source: https://docs.insforge.dev/api-reference/client/provider-specific-oauth-callback-get
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/oauth/{provider}/callback
OAuth callback endpoint for provider-specific flows (most providers use GET).
Response varies based on the original OAuth initiation:
- With code_challenge (PKCE): Redirects with `insforge_code` for exchange endpoint
- Without code_challenge (web): Redirects with `access_token` and sets httpOnly cookie
# Provider-specific OAuth callback (POST)
Source: https://docs.insforge.dev/api-reference/client/provider-specific-oauth-callback-post
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/oauth/{provider}/callback
OAuth callback endpoint for providers that use POST (e.g., Apple with form_post response mode).
Response varies based on the original OAuth initiation:
- With code_challenge (PKCE): Redirects with `insforge_code` for exchange endpoint
- Without code_challenge (web): Redirects with `access_token` and sets httpOnly cookie
# Query Records
Source: https://docs.insforge.dev/api-reference/client/query-records
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/records.yaml get /api/database/records/{tableName}
Query records from a table with filtering, sorting, and pagination
# Refresh access token
Source: https://docs.insforge.dev/api-reference/client/refresh-access-token
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/refresh
Refresh access token using refresh token.
- Web clients: Use httpOnly refresh token cookie with X-CSRF-Token header
- Mobile/Desktop/Server clients: Send refreshToken in request body
# Register new user
Source: https://docs.insforge.dev/api-reference/client/register-new-user
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/users
Creates a new user account
# Reset password with token
Source: https://docs.insforge.dev/api-reference/client/reset-password-with-token
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/email/reset-password
Reset user password with a token. The token can be:
- Magic link token (64-character hex token from send-reset-password when method is 'link')
- Reset token (from exchange-reset-password-token after code verification when method is 'code')
Both token types use RESET_PASSWORD purpose and are verified the same way.
Flow summary:
- Code method: send-reset-password → exchange-reset-password-token → reset-password (with resetToken)
- Link method: send-reset-password → GET /api/auth/email/reset-password-link → reset-password
# Send email verification (code or link based on config)
Source: https://docs.insforge.dev/api-reference/client/send-email-verification-code-or-link-based-on-config
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/email/send-verification
Send email verification using the method configured in auth settings (verifyEmailMethod). When method is 'code', sends a 6-digit numeric code. When method is 'link', sends a browser verification link that goes through an InsForge backend endpoint first. Prevents user enumeration by returning success even if email doesn't exist.
# Send password reset (code or link based on config)
Source: https://docs.insforge.dev/api-reference/client/send-password-reset-code-or-link-based-on-config
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/email/send-reset-password
Send password reset email using the method configured in auth settings (resetPasswordMethod). When method is 'code', sends a 6-digit numeric code for two-step flow. When method is 'link', sends a browser reset link that goes through an InsForge backend endpoint first. Prevents user enumeration by returning success even if email doesn't exist.
# Send raw HTML email
Source: https://docs.insforge.dev/api-reference/client/send-raw-html-email
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/email.yaml post /api/email/send-raw
Send a custom HTML email to one or more recipients. Requires user authentication.
# Shared OAuth callback handler
Source: https://docs.insforge.dev/api-reference/client/shared-oauth-callback-handler
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/oauth/shared/callback/{state}
Handles OAuth callbacks from InsForge Cloud shared OAuth
# Update current user's profile
Source: https://docs.insforge.dev/api-reference/client/update-current-users-profile
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml patch /api/auth/profiles/current
Update the profile of the currently authenticated user
# Update Records
Source: https://docs.insforge.dev/api-reference/client/update-records
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/records.yaml patch /api/database/records/{tableName}
Update records matching query filters
# Upload Object
Source: https://docs.insforge.dev/api-reference/client/upload-object
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml put /api/storage/buckets/{bucketName}/objects/{objectKey}
# Upload Object with Auto-Generated Key
Source: https://docs.insforge.dev/api-reference/client/upload-object-with-auto-generated-key
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml post /api/storage/buckets/{bucketName}/objects
# User login
Source: https://docs.insforge.dev/api-reference/client/user-login
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/sessions
Authenticates user and returns access token. For web clients, sets httpOnly refresh token cookie. For mobile/desktop/server clients, returns refreshToken in response body.
# Verify email from browser link click
Source: https://docs.insforge.dev/api-reference/client/verify-email-from-browser-link-click
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml get /api/auth/email/verify-link
Browser-oriented link verification flow.
This endpoint is intended for users clicking verification links in email.
It validates the token on the backend and redirects the browser to the
stored, validated `redirectTo` URL with the verification result.
Redirect query params:
- Success: `insforge_status=success&insforge_type=verify_email`
- Error: `insforge_status=error&insforge_type=verify_email&insforge_error=...`
- `insforge_status`: `success` or `error`
- `insforge_type`: always `verify_email`
- `insforge_error`: present only on error, human-readable message
Recommended handling: use your sign-in page as `redirectTo`. When the
redirect arrives with `insforge_status=success`, show a confirmation message
and ask the user to sign in with their email and password.
# Verify email with code
Source: https://docs.insforge.dev/api-reference/client/verify-email-with-code
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/auth.yaml post /api/auth/email/verify
Verify email address with a 6-digit code.
Successfully verified users will receive a session token.
Browser email clicks should use `GET /api/auth/email/verify-link`.
`POST /api/auth/email/verify` is the JSON API for 6-digit code submission.
# Get Realtime Config
Source: https://docs.insforge.dev/api-reference/configuration/get-realtime-config
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml get /api/realtime/config
Retrieve realtime message retention configuration
# Update Realtime Config
Source: https://docs.insforge.dev/api-reference/configuration/update-realtime-config
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml patch /api/realtime/config
Update realtime message retention configuration
# Clear Messages
Source: https://docs.insforge.dev/api-reference/messages/clear-messages
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml delete /api/realtime/messages
Permanently delete all stored realtime messages
# Get Message Statistics
Source: https://docs.insforge.dev/api-reference/messages/get-message-statistics
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml get /api/realtime/messages/stats
Retrieve aggregated statistics about messages
# List Messages
Source: https://docs.insforge.dev/api-reference/messages/list-messages
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml get /api/realtime/messages
Retrieve message history with optional filters
# Receive Razorpay Webhook
Source: https://docs.insforge.dev/api-reference/payment-webhooks/receive-razorpay-webhook
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/webhooks/razorpay/{environment}
Receive Razorpay events for one environment. The request body must be the raw Razorpay JSON body and must include the Razorpay signature header.
# Receive Stripe Webhook
Source: https://docs.insforge.dev/api-reference/payment-webhooks/receive-stripe-webhook
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/webhooks/stripe/{environment}
Receive Stripe events for one environment. The request body must be the raw Stripe JSON body and must include the Stripe signature header.
# Get Realtime Permissions
Source: https://docs.insforge.dev/api-reference/permissions/get-realtime-permissions
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/realtime.yaml get /api/realtime/permissions
Retrieve RLS policies for subscribe (channels) and publish (messages) operations
# Cancel Razorpay Subscription
Source: https://docs.insforge.dev/api-reference/razorpay-payments/cancel-razorpay-subscription
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/subscriptions/{subscriptionId}/cancel
Cancel a Razorpay subscription after evaluating the caller's UPDATE policy on payments.razorpay_subscriptions.
# Configure Razorpay Keys
Source: https://docs.insforge.dev/api-reference/razorpay-payments/configure-razorpay-keys
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml put /api/payments/razorpay/{environment}/config
Validate and store Razorpay API keys for one environment. A webhook secret is generated automatically when one does not already exist.
# Create Razorpay Item
Source: https://docs.insforge.dev/api-reference/razorpay-payments/create-razorpay-item
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/catalog/items
Create a Razorpay Item, then mirror it locally after Razorpay succeeds.
# Create Razorpay Order
Source: https://docs.insforge.dev/api-reference/razorpay-payments/create-razorpay-order
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/orders
Create a local Razorpay Order record with the caller's user context, create a Razorpay Order, and return Checkout options for the client-side Razorpay Checkout script.
# Create Razorpay Plan
Source: https://docs.insforge.dev/api-reference/razorpay-payments/create-razorpay-plan
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/catalog/plans
Create a Razorpay Plan with its amount-bearing item definition, then mirror it locally after Razorpay succeeds.
# Create Razorpay Subscription
Source: https://docs.insforge.dev/api-reference/razorpay-payments/create-razorpay-subscription
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/subscriptions
Create a Razorpay Subscription and mirror it locally, then return Checkout options for authorization. The backend first evaluates the caller's INSERT policy on payments.razorpay_subscriptions so apps can restrict which subjects can start subscriptions.
# Get Razorpay Key Configuration
Source: https://docs.insforge.dev/api-reference/razorpay-payments/get-razorpay-key-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/razorpay/config
Return masked Razorpay key configuration for test and live environments.
# Get Razorpay Payments Status
Source: https://docs.insforge.dev/api-reference/razorpay-payments/get-razorpay-payments-status
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/razorpay/status
Return Razorpay connection and sync status for each environment.
# Get Razorpay Webhook Setup Values
Source: https://docs.insforge.dev/api-reference/razorpay-payments/get-razorpay-webhook-setup-values
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/razorpay/{environment}/webhook
Return the Razorpay webhook URL and signing secret that must be copied into the Razorpay Dashboard for manual webhook setup.
# List Razorpay Customers
Source: https://docs.insforge.dev/api-reference/razorpay-payments/list-razorpay-customers
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/razorpay/{environment}/customers
Admin/debug read for mirrored Razorpay customers. This is a display mirror only and should not replace app-owned billing tables.
# List Razorpay Payment Catalog
Source: https://docs.insforge.dev/api-reference/razorpay-payments/list-razorpay-payment-catalog
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/razorpay/{environment}/catalog
Return mirrored Razorpay items and plans for one environment.
# List Razorpay Subscriptions
Source: https://docs.insforge.dev/api-reference/razorpay-payments/list-razorpay-subscriptions
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/razorpay/{environment}/subscriptions
Admin/debug read for mirrored Razorpay subscriptions. Use app-owned tables with RLS for end-user payment state.
# List Razorpay Transactions
Source: https://docs.insforge.dev/api-reference/razorpay-payments/list-razorpay-transactions
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/razorpay/{environment}/transactions
Admin/debug read for InsForge's Razorpay transaction projection. Use app-owned fulfillment tables with RLS for end-user order, credit, or entitlement state.
# Pause Razorpay Subscription
Source: https://docs.insforge.dev/api-reference/razorpay-payments/pause-razorpay-subscription
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/subscriptions/{subscriptionId}/pause
Pause a Razorpay subscription immediately after evaluating the caller's UPDATE policy on payments.razorpay_subscriptions.
# Remove Razorpay Keys
Source: https://docs.insforge.dev/api-reference/razorpay-payments/remove-razorpay-keys
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml delete /api/payments/razorpay/{environment}/config
Remove the configured Razorpay keys for one environment.
# Resume Razorpay Subscription
Source: https://docs.insforge.dev/api-reference/razorpay-payments/resume-razorpay-subscription
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/subscriptions/{subscriptionId}/resume
Resume a paused Razorpay subscription immediately after evaluating the caller's UPDATE policy on payments.razorpay_subscriptions.
# Rotate Razorpay Webhook Secret
Source: https://docs.insforge.dev/api-reference/razorpay-payments/rotate-razorpay-webhook-secret
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/webhook/rotate-secret
Generate a new Razorpay webhook signing secret. Update the webhook secret in the Razorpay Dashboard after calling this endpoint.
# Sync Razorpay Payments State
Source: https://docs.insforge.dev/api-reference/razorpay-payments/sync-razorpay-payments-state
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/sync
Sync items, plans, customers, subscriptions, invoices, and payments for every configured Razorpay environment. Razorpay remains the source of truth.
# Sync Razorpay Payments State For One Environment
Source: https://docs.insforge.dev/api-reference/razorpay-payments/sync-razorpay-payments-state-for-one-environment
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/sync
Sync items, plans, customers, subscriptions, invoices, and payments for one Razorpay environment. Razorpay remains the source of truth.
# Update Razorpay Item
Source: https://docs.insforge.dev/api-reference/razorpay-payments/update-razorpay-item
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml patch /api/payments/razorpay/{environment}/catalog/items/{itemId}
Update mutable Razorpay Item fields, then mirror the item locally after Razorpay succeeds.
# Verify Razorpay Order Payment
Source: https://docs.insforge.dev/api-reference/razorpay-payments/verify-razorpay-order-payment
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/orders/verify
Verify the Razorpay Checkout signature for an order payment before recording the verified payment ID locally.
# Verify Razorpay Subscription Authorization
Source: https://docs.insforge.dev/api-reference/razorpay-payments/verify-razorpay-subscription-authorization
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/razorpay/{environment}/subscriptions/verify
Verify the Razorpay Checkout signature for the subscription authorization payment before recording the authorization payment ID locally.
# Create S3 Access Key
Source: https://docs.insforge.dev/api-reference/s3-access-keys/create-s3-access-key
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml post /api/storage/s3/access-keys
Mint a new S3 credential pair usable against the `/storage/v1/s3`
protocol gateway. The plaintext `secretAccessKey` in the response
is returned **exactly once** — it is encrypted at rest and can
never be retrieved again. If you lose it, revoke and re-create.
Limits:
- 50 keys per project (hard cap, enforced transactionally).
- Rate-limited to 20 management requests per 15 min per IP.
# Get S3 Gateway Config
Source: https://docs.insforge.dev/api-reference/s3-access-keys/get-s3-gateway-config
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml get /api/storage/s3/config
Return the externally-reachable endpoint URL and the SigV4 signing
region for the S3 protocol gateway. The endpoint is assembled from
the server's `VITE_API_BASE_URL` env var plus `/storage/v1/s3`, and
the region is `AWS_REGION` (default `us-east-2`).
Intended for Dashboard display so the UI doesn't make any
backend-topology assumptions client-side.
# List S3 Access Keys
Source: https://docs.insforge.dev/api-reference/s3-access-keys/list-s3-access-keys
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml get /api/storage/s3/access-keys
Return every S3 access key configured for this project. Plaintext
secrets are **never** returned here — the secret is only shown once
in the response of `POST /api/storage/s3/access-keys`.
# Revoke S3 Access Key
Source: https://docs.insforge.dev/api-reference/s3-access-keys/revoke-s3-access-key
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml delete /api/storage/s3/access-keys/{id}
Revoke an S3 access key by its id. The in-memory LRU cache is
invalidated synchronously so subsequent S3 protocol requests with
this credential return `403 InvalidAccessKeyId`.
# S3 protocol (DELETE)
Source: https://docs.insforge.dev/api-reference/s3-protocol/s3-protocol-delete
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml delete /storage/v1/s3/{path}
Dispatched to DeleteObject / DeleteBucket / AbortMultipartUpload based on path and query.
# S3 protocol (GET)
Source: https://docs.insforge.dev/api-reference/s3-protocol/s3-protocol-get
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml get /storage/v1/s3/{path}
Dispatched to ListBuckets / ListObjectsV2 / GetObject / HeadObject / ListParts / GetBucketLocation / GetBucketVersioning based on path shape and query.
# S3 protocol (HEAD)
Source: https://docs.insforge.dev/api-reference/s3-protocol/s3-protocol-head
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml head /storage/v1/s3/{path}
Dispatched to HeadBucket / HeadObject based on path shape.
# S3 protocol (POST)
Source: https://docs.insforge.dev/api-reference/s3-protocol/s3-protocol-post
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml post /storage/v1/s3/{path}
Dispatched to CreateMultipartUpload / CompleteMultipartUpload / DeleteObjects based on query.
# S3 protocol (PUT)
Source: https://docs.insforge.dev/api-reference/s3-protocol/s3-protocol-put
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/storage.yaml put /storage/v1/s3/{path}
Dispatched to PutObject / UploadPart / CopyObject / CreateBucket based on path shape, query, and headers.
# Archive Stripe Price
Source: https://docs.insforge.dev/api-reference/stripe-payments/archive-stripe-price
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml delete /api/payments/stripe/{environment}/catalog/prices/{priceId}
Archive a Stripe price in one environment, then mirror the archived state locally.
# Configure Managed Stripe Webhook
Source: https://docs.insforge.dev/api-reference/stripe-payments/configure-managed-stripe-webhook
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/stripe/{environment}/webhook
Create or recreate the InsForge-managed Stripe webhook endpoint for one environment.
# Configure Stripe Secret Key
Source: https://docs.insforge.dev/api-reference/stripe-payments/configure-stripe-secret-key
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml put /api/payments/stripe/{environment}/config
Validate and store a Stripe secret key. New Stripe accounts attempt managed webhook setup and then run a unified sync.
# Create Stripe Checkout Session
Source: https://docs.insforge.dev/api-reference/stripe-payments/create-stripe-checkout-session
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/stripe/{environment}/checkout-sessions
Create a local checkout attempt with the caller's user context and then create a Stripe Checkout Session. Subscription mode requires a billing subject.
# Create Stripe Customer Portal Session
Source: https://docs.insforge.dev/api-reference/stripe-payments/create-stripe-customer-portal-session
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/stripe/{environment}/customer-portal-sessions
Create a Stripe Billing Portal Session for an authenticated user's mapped billing subject.
# Create Stripe Price
Source: https://docs.insforge.dev/api-reference/stripe-payments/create-stripe-price
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/stripe/{environment}/catalog/prices
Create a Stripe price in the requested environment, then mirror it locally after Stripe succeeds.
# Create Stripe Product
Source: https://docs.insforge.dev/api-reference/stripe-payments/create-stripe-product
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/stripe/{environment}/catalog/products
Create a Stripe product in the requested environment, then mirror it locally after Stripe succeeds.
# Delete Stripe Product
Source: https://docs.insforge.dev/api-reference/stripe-payments/delete-stripe-product
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml delete /api/payments/stripe/{environment}/catalog/products/{productId}
Delete a Stripe product from one environment, then remove it from the local mirror.
# Get Stripe Key Configuration
Source: https://docs.insforge.dev/api-reference/stripe-payments/get-stripe-key-configuration
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/stripe/config
Return masked Stripe key configuration for test and live environments.
# Get Stripe Payments Status
Source: https://docs.insforge.dev/api-reference/stripe-payments/get-stripe-payments-status
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/stripe/status
Return Stripe connection, sync, and managed webhook status for each environment.
# Get Stripe Price
Source: https://docs.insforge.dev/api-reference/stripe-payments/get-stripe-price
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/stripe/{environment}/catalog/prices/{priceId}
Get one mirrored Stripe price.
# Get Stripe Product
Source: https://docs.insforge.dev/api-reference/stripe-payments/get-stripe-product
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/stripe/{environment}/catalog/products/{productId}
Get one mirrored Stripe product and its associated prices.
# List Stripe Catalog
Source: https://docs.insforge.dev/api-reference/stripe-payments/list-stripe-catalog
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/stripe/{environment}/catalog
Return mirrored Stripe products and prices for one environment.
# List Stripe Customers
Source: https://docs.insforge.dev/api-reference/stripe-payments/list-stripe-customers
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/stripe/{environment}/customers
Admin/debug read for mirrored Stripe customers. This is a display mirror only and should not replace app-owned billing tables.
# List Stripe Prices
Source: https://docs.insforge.dev/api-reference/stripe-payments/list-stripe-prices
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/stripe/{environment}/catalog/prices
List mirrored Stripe prices for one environment, optionally filtered by product.
# List Stripe Products
Source: https://docs.insforge.dev/api-reference/stripe-payments/list-stripe-products
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/stripe/{environment}/catalog/products
List mirrored Stripe products for one environment.
# List Stripe Subscriptions
Source: https://docs.insforge.dev/api-reference/stripe-payments/list-stripe-subscriptions
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/stripe/{environment}/subscriptions
Admin/debug read for mirrored Stripe subscriptions. Use app-owned tables with RLS for end-user payment state.
# List Stripe Transactions
Source: https://docs.insforge.dev/api-reference/stripe-payments/list-stripe-transactions
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml get /api/payments/stripe/{environment}/transactions
Admin/debug read for InsForge's Stripe transaction projection. Use app-owned fulfillment tables with RLS for end-user order, credit, or entitlement state.
# Remove Stripe Secret Key
Source: https://docs.insforge.dev/api-reference/stripe-payments/remove-stripe-secret-key
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml delete /api/payments/stripe/{environment}/config
Remove the configured Stripe secret key for one environment and best-effort remove managed webhook endpoints.
# Sync Stripe Payments State
Source: https://docs.insforge.dev/api-reference/stripe-payments/sync-stripe-payments-state
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/stripe/sync
Sync products, prices, customers, and subscriptions for every configured Stripe environment. Stripe remains the source of truth.
# Sync Stripe Payments State For One Environment
Source: https://docs.insforge.dev/api-reference/stripe-payments/sync-stripe-payments-state-for-one-environment
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml post /api/payments/stripe/{environment}/sync
Sync products, prices, customers, and subscriptions for one Stripe environment. Stripe remains the source of truth.
# Update Stripe Price
Source: https://docs.insforge.dev/api-reference/stripe-payments/update-stripe-price
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml patch /api/payments/stripe/{environment}/catalog/prices/{priceId}
Update mutable Stripe price fields, then mirror the price locally after Stripe succeeds.
# Update Stripe Product
Source: https://docs.insforge.dev/api-reference/stripe-payments/update-stripe-product
https://raw.githubusercontent.com/InsForge/InsForge/main/openapi/payments.yaml patch /api/payments/stripe/{environment}/catalog/products/{productId}
Update a Stripe product, then mirror it locally after Stripe succeeds.
# Model Gateway
Source: https://docs.insforge.dev/core-concepts/ai/overview
Call any LLM through one InsForge-managed key, with per-project quotas.
Use the Model Gateway to call chat, streaming, and embedding models through one OpenAI-compatible endpoint. InsForge holds the provider keys, tracks usage per project, and routes traffic through [OpenRouter](https://openrouter.ai), so your application code never sees Anthropic, OpenAI, or Mistral credentials directly.
**Want to run AI code, not call a model?** Use [Edge Functions](/core-concepts/functions/overview) to orchestrate prompts, retrieval, and tools. The Model Gateway is the call; functions are the program around it.
```mermaid theme={null}
graph TB
Dashboard[InsForge Dashboard] --> Key[Active OpenRouter Key]
Dashboard --> Catalog[OpenRouter Model Catalog]
Dashboard --> Metrics[OpenRouter Usage Overview]
App[Application Backend or Server Route] --> SDK[OpenAI SDK]
SDK --> OpenRouter[OpenRouter API]
OpenRouter --> OpenAI[OpenAI]
OpenRouter --> Anthropic[Anthropic]
OpenRouter --> Google[Google]
OpenRouter --> More[Other Providers]
style Dashboard fill:#1e293b,stroke:#475569,color:#e2e8f0
style App fill:#166534,stroke:#22c55e,color:#dcfce7
style SDK fill:#1e40af,stroke:#3b82f6,color:#dbeafe
style OpenRouter fill:#c2410c,stroke:#fb923c,color:#fed7aa
```
## Features
### OpenAI-compatible API
Point any OpenAI SDK or `openai`-compatible library at `https://.insforge.dev/v1` and it works. `/v1/chat/completions`, `/v1/embeddings`, and `/v1/models` all behave like the upstream spec.
### Streaming
Server-sent events for chat completions. Use the streaming endpoint the same way you would with OpenAI; the gateway forwards tokens as they arrive from the provider.
### Embeddings
Generate dense vectors from any embedding model OpenRouter supports. Store the result in Postgres with [pgvector](/core-concepts/database/pgvector) for semantic search.
### Per-project quotas
Each project carries its own rate limit and spend cap. Hit it, and the gateway returns a clean 429 instead of leaking provider quota state into your app.
### Usage tracking
Every request is logged with model, token count, and cost. Query usage from the dashboard, CLI, or MCP — billing reconciles to OpenRouter's invoice automatically.
### Multi-provider routing
Switch between Anthropic, OpenAI, Mistral, Llama, Gemini, and dozens more by changing the model name in the request. Application code does not change.
## Build with it
Chat, stream, and embed from Node, browser, and edge runtimes.
Native Swift AI client for iOS and macOS.
Coroutines-first AI client for Android and JVM.
Plain HTTP AI endpoints, callable from any language.
## Next steps
* Set up the [CLI](/quickstart) to link your project (the recommended path).
* Browse the [TypeScript SDK reference](/sdks/typescript/ai) for chat and embedding patterns.
# Analytics
Source: https://docs.insforge.dev/core-concepts/analytics/overview
Product analytics for your app, powered by PostHog.
Use InsForge Analytics to understand how people actually use your app: page traffic, retention, and session replays, all wired up by connecting a PostHog project to your InsForge backend. Once connected, the dashboard renders Traffic, User Retention, and Session Replay pages on top of your PostHog data without leaving InsForge.
Connect PostHog once with one click, drop the setup prompt into your coding agent so it runs the PostHog wizard and installs the PostHog SDK on your frontend, and the Analytics pages start filling in.
PostHog remains the source of truth for events, dashboards, insights, and recordings. InsForge surfaces a focused subset for everyday checks, then deep-links into PostHog for anything beyond it.
```mermaid theme={null}
flowchart TB
Admin["Dashboard"] --> AnalyticsAPI["Analytics API"]
App["Frontend App"] --> SDK["PostHog SDK"]
SDK --> PostHog["PostHog"]
AnalyticsAPI --> PostHog
PostHog --> Traffic["Traffic / KPIs"]
PostHog --> Retention["User Retention"]
PostHog --> Replay["Session Replay"]
Traffic --> Pages["Analytics pages"]
Retention --> Pages
Replay --> Pages
style Admin fill:#1e293b,stroke:#475569,color:#e2e8f0
style App fill:#1e293b,stroke:#475569,color:#e2e8f0
style SDK fill:#1e40af,stroke:#3b82f6,color:#dbeafe
style AnalyticsAPI fill:#166534,stroke:#22c55e,color:#dcfce7
style PostHog fill:#c2410c,stroke:#fb923c,color:#fed7aa
style Traffic fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Retention fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Replay fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Pages fill:#6b21a8,stroke:#a855f7,color:#f3e8ff
```
## Features
### One-click PostHog connection
Connect PostHog from the Analytics page in the dashboard. InsForge provisions or links a PostHog project for you, stores credentials server-side, and unlocks the Traffic, Retention, and Session Replay pages once the connection succeeds.
### SDK setup via PostHog wizard
After connecting, the empty state ships a setup prompt you can paste into your coding agent:
```
I want to add product analytics to this project. Read the current directory and use the InsForge skill to set up PostHog analytics by running `npx @insforge/cli posthog setup`.
```
`@insforge/cli posthog setup` links your InsForge project to PostHog, then prints the official [PostHog wizard](https://posthog.com/docs/libraries/wizard) command (`npx -y @posthog/wizard@latest`) for you (or your agent) to run next. The wizard detects your framework, installs the right PostHog SDK, and drops in initialization code so pageviews, autocapture events, and session recordings start flowing.
### Traffic
KPIs over your selected time range (visitors, pageviews, sessions, bounce rate, and trend), plus breakdowns by Page, Country, and Device Type. Useful for the first "how is the app doing this week" pass without opening PostHog.
### User retention
Cohort retention chart built from your PostHog events. Pick a time range and see how many users come back over the following days or weeks.
### Session replay
A paginated list of recent session recordings with duration, person, and a deep-link into PostHog's full replay player. Helps you watch what users actually did right after spotting something odd in Traffic or Retention.
### Settings and disconnect
The Analytics Config dialog (the gear icon in the sidebar) lets admins review the linked PostHog project, jump straight into PostHog, and disconnect when needed. Disconnecting only severs the InsForge ↔ PostHog link; your PostHog project, events, and recordings stay intact.
## Concepts
Events, autocapture, insights, and dashboards behind the Analytics pages.
How recordings are captured, redacted, and played back.
## Build with it
Auto-detects your framework, installs the right PostHog SDK, and adds initialization code.
Capture custom events on top of what the wizard sets up.
`npx @insforge/cli posthog setup` links your InsForge project to PostHog, then prints the wizard command.
## Next steps
* Open the Analytics page in the dashboard and click **Connect PostHog**.
* Paste the setup prompt into your coding agent, then run the `@posthog/wizard` command it prints to wire the SDK into your app.
* Set up the [CLI](/quickstart) if you want to manage the connection from the terminal.
# Authentication
Source: https://docs.insforge.dev/core-concepts/authentication/overview
Use InsForge to authenticate and authorize your users.
Use InsForge Authentication to handle sign-up, login, sessions, and identity for your app. Users can sign in with email and password, magic link, one-time code, OAuth providers (Google, GitHub, Apple, and others), or any OIDC-compliant identity provider you bring. InsForge issues JSON Web Tokens on login, and every other product on the platform consumes the same token.
**Authentication** is checking that a user is who they say they are. **Authorization** is checking what they can do. InsForge handles the first directly and powers the second through [row-level security](/core-concepts/database/overview) policies that read the auth JWT.
```mermaid theme={null}
graph TB
Client[Client Application] --> SDK[InsForge SDK]
SDK --> AuthAPI[Auth API]
AuthAPI --> JWT[JWT Service]
AuthAPI --> OAuth[OAuth Providers]
AuthAPI --> DB[(PostgreSQL)]
OAuth --> Google[Google OAuth 2.0]
OAuth --> GitHub[GitHub OAuth]
JWT --> Secret[Shared Secret]
JWT --> Validation[Token Validation]
DB --> Users[auth.users Table]
DB --> Providers[auth.user_providers]
style Client fill:#1e293b,stroke:#475569,color:#e2e8f0
style SDK fill:#1e40af,stroke:#3b82f6,color:#dbeafe
style AuthAPI fill:#166534,stroke:#22c55e,color:#dcfce7
style JWT fill:#c2410c,stroke:#fb923c,color:#fed7aa
style OAuth fill:#6b21a8,stroke:#a855f7,color:#f3e8ff
style DB fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Secret fill:#991b1b,stroke:#ef4444,color:#fee2e2
style Google fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
style GitHub fill:#1e293b,stroke:#64748b,color:#f1f5f9
style Validation fill:#991b1b,stroke:#ef4444,color:#fee2e2
style Users fill:#0e7490,stroke:#22d3ee,color:#cffafe
style Providers fill:#0e7490,stroke:#22d3ee,color:#cffafe
```
## Features
### Email and password
The default. New users sign up with an email and password, get a confirmation email, and receive a session JWT on login. Password reset, email verification, and brute-force throttling are built in.
### Magic link and OTP
Send a one-time link or six-digit code to the user's email. Passwordless sign-in, account recovery, and step-up auth all use the same primitive.
### OAuth providers
First-class support for Google, GitHub, Apple, Microsoft, GitLab, Discord, and more. Add custom OAuth 2.0 / OIDC providers (Keycloak, Okta, Auth0, your own IdP) by URL without writing provider-specific code.
### OAuth server mode
Run InsForge itself as an OAuth 2.0 / OIDC identity provider for your own downstream apps. See the [OAuth Server guide](/oauth-server) for the full setup.
### Row-level security
The auth JWT flows through every InsForge SDK call automatically. Postgres RLS policies read claims from the token and decide, row by row, what the user can read and write. The same identity and the same policies apply whether the request hits the database, storage, or a realtime channel.
### `auth.users` in your database
User state lives in your project's Postgres database in the `auth` schema. Join `auth.users` to your application tables via foreign keys, react to identity changes with triggers, and back the whole thing up the same way you back up everything else.
## Build with it
Sign up, log in, and manage sessions from Node, browser, and edge.
Native Swift auth client for iOS and macOS.
Coroutines-first auth client for Android and JVM.
Plain HTTP auth endpoints, callable from any language.
## Next steps
* Set up the [CLI](/quickstart) to link your project (the recommended path).
* Browse the [TypeScript SDK reference](/sdks/typescript/auth) for sign-in patterns.
# Custom Compute
Source: https://docs.insforge.dev/core-concepts/compute/overview
Run long-lived containers next to your InsForge project.
Use InsForge Custom Compute to run long-lived containers next to your project: queue workers, background processors, AI inference loops, websocket servers, scrapers, anything that needs to stay up. Containers attach to your project's database, storage, and auth with the same credentials a function would use.
**Just need to handle a request?** Use [Edge Functions](/core-concepts/functions/overview) for request/response work and short jobs. Custom Compute is for processes that need to run continuously.
```mermaid theme={null}
graph TB
Dashboard[InsForge Dashboard] --> Service[Compute Service]
CLI[InsForge CLI] --> Service
Service --> Container[Long-lived Container]
Container --> DB[(Database)]
Container --> Storage[Storage]
Container --> Auth[Auth]
style Dashboard fill:#1e293b,stroke:#475569,color:#e2e8f0
style CLI fill:#1e40af,stroke:#3b82f6,color:#dbeafe
style Service fill:#166534,stroke:#22c55e,color:#dcfce7
style Container fill:#c2410c,stroke:#fb923c,color:#fed7aa
style DB fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Storage fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Auth fill:#0e7490,stroke:#06b6d4,color:#cffafe
```
## Features
### Container deploys
Push any Docker image to InsForge and it runs. Use a `Dockerfile` from your repo or point at a pre-built image on a registry. No proprietary build pipeline to learn.
### Project-linked credentials
Containers receive the InsForge project URL, service-role JWT, and S3 storage credentials as environment variables. Connect to Postgres, call the SDK, and read objects without provisioning anything.
### Scaling
Run one instance for a singleton worker, or scale horizontally for stateless workloads. Memory, CPU, and replica count are configurable per service.
### Logs
Structured logs per container, queryable by service and time range. Tail in the dashboard, CLI, or MCP without `kubectl exec`-ing into anything.
### Secrets and env vars
Set environment variables and secrets per service, separately from your edge-function secrets. Rotate without redeploying.
## Next steps
* Set up the [CLI](/quickstart) to link your project (the recommended path).
* See [Edge Functions](/core-concepts/functions/overview) if request/response is all you need.
# Database migrations
Source: https://docs.insforge.dev/core-concepts/database/migrations
Track schema changes in git and apply them with the InsForge CLI
Migrations are versioned SQL files in `migrations/` applied with `@insforge/cli`. Each successful run is recorded in `system.custom_migrations`. The workflow is forward-only.
## Concepts
A migration is one SQL file prefixed with a 14-digit UTC timestamp: `_.sql`. The CLI applies pending files in order inside a transaction, sets `search_path` to `public`, and records history only on success. PostgREST reloads schema metadata automatically. `BEGIN`/`COMMIT`/`ROLLBACK` inside a file are rejected.
## Usage
Link the backend, then create a file.
```bash theme={null}
npx @insforge/cli login
npx @insforge/cli link
npx @insforge/cli db migrations new create-employees-table
```
Write the SQL.
```sql theme={null}
create table if not exists public.employees (
id bigint primary key generated always as identity,
name text not null,
email text,
created_at timestamptz default now()
);
```
Apply pending migrations and check history.
```bash theme={null}
npx @insforge/cli db migrations up --all
npx @insforge/cli db migrations list
```
Target a single file with `up `, or apply everything pending up to and including a target with `up --to `.
## Specific usage cases
Adopting migrations on an existing project: run `db migrations fetch` first to materialize remote history into local files. Once applied remotely, never edit a migration in place. Write a forward migration instead.
Once you opt in, route all schema changes through files. Ad hoc dashboard edits cause drift between git and `system.custom_migrations`.
## More resources
* [Database branching](/agent-native/branching) to rehearse a migration on a copy.
* [Database overview](/core-concepts/database/overview) for how PostgREST picks up schema changes.
* [PostgreSQL DDL docs](https://www.postgresql.org/docs/15/ddl.html) for the SQL you write.
# Database
Source: https://docs.insforge.dev/core-concepts/database/overview
Use InsForge to manage your data.
Every InsForge project comes with a full [Postgres](https://www.postgresql.org/) database. Every table is automatically a typed REST and SDK endpoint. Auth tokens scope every read and write through row-level security. The same Postgres handles relational queries, semantic search via pgvector, and realtime change feeds.
**Looking for file storage?** Use [Storage](/core-concepts/storage/overview) for images, PDFs, and other binary content. The database stores rows; storage stores objects.
```mermaid theme={null}
graph TB
Client[Client Application] --> SDK[InsForge SDK]
SDK --> API[InsForge API]
API --> PostgREST[PostgREST v12.2]
PostgREST --> PG[(PostgreSQL 15)]
API --> PG
PG --> RLS[Row Level Security]
PG --> Triggers[Database Triggers]
PG --> Functions[Stored Functions]
PG --> Schemas[Multiple Schemas]
style Client fill:#1e293b,stroke:#475569,color:#e2e8f0
style SDK fill:#1e40af,stroke:#3b82f6,color:#dbeafe
style API fill:#166534,stroke:#22c55e,color:#dcfce7
style PostgREST fill:#c2410c,stroke:#fb923c,color:#fed7aa
style PG fill:#0e7490,stroke:#06b6d4,color:#cffafe
style RLS fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
style Triggers fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
style Functions fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
style Schemas fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
```
## Features
### Tables as APIs
Define a table and you immediately get REST endpoints plus a typed SDK client for it. No code generation step. The auth JWT scopes every query through RLS.
### Migrations
Track and apply SQL changes in order. [Migrations](/core-concepts/database/migrations) ship as plain `.sql` files in your repo, applied with `npx @insforge/cli db migrations up --all` or via the MCP tool.
### Branching
Spin up an isolated database branch to test risky schema changes against a copy of production data. See [Branching](/agent-native/branching).
### pgvector
Native vector search for embeddings, with HNSW and IVFFlat indexes. See [pgvector](/core-concepts/database/pgvector).
### Row-level security
Postgres RLS policies enforce access at the row level. Policies read the auth JWT, so the same rule applies to REST queries, SDK calls, realtime subscriptions, and storage requests.
## Concepts
Apply SQL changes in order, safely.
Isolated databases for preview and risky changes.
Vector search for embeddings.
## Build with it
Typed queries, inserts, and updates from Node, browser, and edge.
Native Swift database client for iOS and macOS.
Coroutines-first database client for Android and JVM.
Plain HTTP database endpoints, callable from any language.
## Next steps
* Set up the [CLI](/quickstart) to link your project (the recommended path).
* Browse the [TypeScript SDK reference](/sdks/typescript/database) for typed queries.
# pgvector
Source: https://docs.insforge.dev/core-concepts/database/pgvector
Store embeddings and run similarity search inside Postgres
[pgvector](https://github.com/pgvector/pgvector) ships on every InsForge project. Use it for semantic search, recommendations, and [RAG](https://www.pinecone.io/learn/retrieval-augmented-generation/).
## Prompt your agent
> Add pgvector to my project. Create a `documents` table with `content` and a 1536-dim `embedding` column, plus an HNSW cosine index. When I insert content, embed it with OpenRouter's `text-embedding-3-small` from a server-side route. Expose a `match_documents(query, count, threshold)` RPC that returns top similarity matches.
## Concepts
A vector is a list of numbers representing an item. Two vectors are similar if they sit close in vector space. Store the vector next to its row, embed the user query the same way, and pgvector ranks by distance.
## Usage
Enable the extension and create a vector column. Match the dimension to your model (`text-embedding-3-small` is 1536).
```sql theme={null}
create extension if not exists vector;
create table documents (
id bigserial primary key,
content text,
embedding vector(1536)
);
```
Generate an embedding server-side and insert it.
```typescript theme={null}
import OpenAI from 'openai';
import { createClient } from '@insforge/sdk';
const openai = new OpenAI({
baseURL: 'https://openrouter.ai/api/v1',
apiKey: process.env.OPENROUTER_API_KEY,
});
const insforge = createClient({ projectId: process.env.INSFORGE_PROJECT_ID });
const { data } = await openai.embeddings.create({
model: 'openai/text-embedding-3-small',
input: 'hello world',
});
await insforge.database.from('documents').insert({
content: 'hello world',
embedding: data[0].embedding,
});
```
Query by cosine distance (`<=>`). L2 (`<->`) and inner product (`<#>`) are also available.
```sql theme={null}
select id, content
from documents
order by embedding <=> $1
limit 5;
```
## Specific usage cases
Wrap search in a Postgres function and call it via `rpc()` to keep the math server-side:
```sql theme={null}
create or replace function match_documents(
query_embedding vector(1536),
match_count int default 5,
match_threshold float default 0
)
returns table (id bigint, content text, similarity float)
language sql stable
as $$
select id, content, 1 - (embedding <=> query_embedding) as similarity
from documents
where 1 - (embedding <=> query_embedding) > match_threshold
order by embedding <=> query_embedding
limit match_count;
$$;
```
Past \~10k rows, add an HNSW index:
```sql theme={null}
create index on documents using hnsw (embedding vector_cosine_ops);
```
## More resources
* [pgvector on GitHub](https://github.com/pgvector/pgvector) for operators and indexes.
* [OpenRouter embeddings](https://openrouter.ai/docs/features/multimodal/embeddings) for the model catalog.
* [Model Gateway overview](/core-concepts/ai/overview) for the InsForge side of OpenRouter.
# Edge Functions
Source: https://docs.insforge.dev/core-concepts/functions/overview
Deno-powered serverless TypeScript with first-class schedules.
Use InsForge edge functions to run TypeScript on [Deno](https://deno.com), deployed close to your users for low latency. Functions can be invoked on-demand from any client, chained from database triggers, or scheduled to run on a cron expression. The runtime ships standard fetch, streaming responses, and ESM imports out of the box.
**Need a process that stays up?** Use [Compute](/core-concepts/compute/overview) for queue workers, AI inference loops, and anything stateful. Edge Functions are for request/response and short-lived jobs.
```mermaid theme={null}
graph TB
HTTP[HTTP Request] --> Fn[Edge Function on Deno]
Schedule[Cron Schedule] --> Fn
Trigger[Database Trigger] --> Fn
Fn --> SDK[InsForge SDK]
SDK --> DB[(Database)]
SDK --> Storage[Storage]
SDK --> Gateway[Model Gateway]
style HTTP fill:#1e293b,stroke:#475569,color:#e2e8f0
style Schedule fill:#1e293b,stroke:#475569,color:#e2e8f0
style Trigger fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
style Fn fill:#c2410c,stroke:#fb923c,color:#fed7aa
style SDK fill:#1e40af,stroke:#3b82f6,color:#dbeafe
style DB fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Storage fill:#166534,stroke:#22c55e,color:#dcfce7
style Gateway fill:#166534,stroke:#22c55e,color:#dcfce7
```
## Features
### HTTP triggers
Every function is reachable at `https://.insforge.dev/functions/`. Standard fetch in, standard `Response` out. Streaming, JSON, redirects, and websockets all work.
### Schedules
Attach a cron expression to a function and InsForge invokes it on time, with retry on failure. See [Schedules](/core-concepts/functions/schedules) for the cron syntax and execution model.
### Database triggers
Wire a function to fire on `INSERT`, `UPDATE`, or `DELETE` against a table. The function receives the row payload and runs with a service-role JWT so it can perform privileged follow-up writes.
### Secrets and environment variables
Set env vars and secrets per function. The dashboard, CLI, and MCP all read and write the same store; secrets never round-trip through your repo.
### Logs
Structured logs are captured per invocation, queryable by status, duration, and function name. The InsForge MCP `get-function-logs` tool lets your agent diagnose failures without leaving the editor.
### Deno standard library
Use the [Deno standard library](https://jsr.io/@std) and any ESM module from `jsr.io`, `esm.sh`, or `npm:` specifiers. You don't run a bundler, and there's no `node_modules` directory to ship.
## Concepts
Run a function on a cron expression instead of in response to a request.
## Build with it
Invoke and stream functions from Node, browser, and edge.
Invoke functions from iOS and macOS apps.
Invoke functions from Android and JVM apps.
Plain HTTP function endpoints, callable from any language.
## Next steps
* Set up the [CLI](/quickstart) to link your project (the recommended path).
* Browse the [TypeScript SDK reference](/sdks/typescript/functions) for invocation patterns.
# Schedules: cron-triggered functions
Source: https://docs.insforge.dev/core-concepts/functions/schedules
Run a function on a cron schedule using pg_cron
Schedules invoke functions on a recurring cron expression. [pg\_cron](https://github.com/citusdata/pg_cron) fires an HTTP request to the function URL at each tick and logs the result.
## Concepts
A schedule is a cron expression, a target URL, and headers. On creation, `${{secrets.KEY}}` placeholders in headers are resolved and encrypted with `pgcrypto`. At each tick, `execute_job()` decrypts headers, calls the function, and writes status and duration to `schedules.job_logs`.
## Usage
Standard 5-field cron (no seconds). Reference secrets in headers instead of hardcoding keys.
```text theme={null}
*/5 * * * * every 5 minutes
0 * * * * every hour
0 0 * * * daily at midnight
0 9 * * 1 every Monday at 9am
0 0 1 * * first of every month
```
Create via dashboard or SQL:
```sql theme={null}
select schedules.create_job(
name => 'daily-cleanup',
schedule => '0 0 * * *',
url => 'https://myapp.functions.insforge.app/cleanup',
headers => jsonb_build_object('Authorization', 'Bearer ${{secrets.CRON_TOKEN}}')
);
```
## Limits
Minimum interval is 1 minute (pg\_cron). Failed runs are logged but not retried, so the function must be idempotent. Deleting a referenced secret breaks every job using it until you update or disable the schedule.
## More resources
* [pg\_cron docs](https://github.com/citusdata/pg_cron) for cron syntax.
* [Functions overview](/core-concepts/functions/overview) for the runtime.
* [crontab.guru](https://crontab.guru) to check an expression.
# Custom SMTP
Source: https://docs.insforge.dev/core-concepts/messaging/custom-smtp
Route every outgoing email through your own SMTP server
When enabled, every email (auth flows and `emails.send()` calls) routes through your SMTP server. Toggle off to revert; credentials are preserved.
## Concepts
Provider is resolved on every send, so saves take effect on the next request. InsForge runs `transporter.verify()` before saving, so a persisted config always works. Passwords are encrypted at rest with AES-256-GCM and never returned by the API.
## Usage
Configure SMTP under **Authentication → Email**.
Flip the switch on the **SMTP Provider** card.
Host, port (`25`, `465`, `587`, `2525`), username, password, sender email, sender name. Private IPs and self-signed certs are rejected.
InsForge runs an SMTP handshake before persisting. Bad credentials fail fast.
The **Email Templates** card unlocks the four auth templates.
The `From:` header is always your configured sender. SDK callers cannot spoof it.
## Email templates
Templates render locally from `email.templates`. Variables use `{{ variable }}` and are HTML-escaped.
| Template | When it sends |
| ------------------------- | ------------------------------------------- |
| `email-verification-code` | New-user verification with a 6-digit code |
| `email-verification-link` | New-user verification with a clickable link |
| `reset-password-code` | Password reset with a 6-digit code |
| `reset-password-link` | Password reset with a clickable link |
Variables: `{{ token }}` (code templates), `{{ link }}` (link templates, must start with `http://` or `https://`), `{{ name }}` and `{{ email }}` (all templates).
## Considerations
* **Rate limiting.** **Min interval (seconds)** caps per-recipient frequency. Sends within the cooldown return HTTP `429`. Defaults to `60`; `0` disables.
* **SSRF protection.** Private, loopback, link-local, and carrier-NAT ranges are rejected.
* **Audit log.** Config saves log `UPDATE_SMTP_CONFIG`; template edits log `UPDATE_EMAIL_TEMPLATE`.
## More resources
* [Messaging overview](/core-concepts/messaging/overview) for the routing model.
* [nodemailer SMTP transport](https://nodemailer.com/smtp/) for connection options.
* [Authentication overview](/core-concepts/authentication/overview) for the flows that emit these emails.
# Messaging
Source: https://docs.insforge.dev/core-concepts/messaging/overview
Send transactional messages from your project. Email today, SMS and push on the roadmap.
InsForge Messaging sends transactional notifications from your project: receipts, digests, password-reset codes, notification roll-ups, anything you would otherwise wire SendGrid, Postmark, or Twilio in for. Email is the first channel; SMS and push are on the roadmap and will share the same API surface.
**Just sending auth emails?** Magic links, verification codes, and password resets are wired into [Authentication](/core-concepts/authentication/overview) out of the box. You only need this product for transactional messages beyond auth.
```mermaid theme={null}
graph TB
Client[Client Application] --> SDK[InsForge SDK]
SDK --> API[Email API]
API --> Service[EmailService]
Service --> Decision{SMTP enabled?}
Decision -->|No| Cloud[InsForge Cloud]
Cloud --> SES[AWS SES]
Decision -->|Yes| SMTP[Your SMTP server]
SES --> Inbox[Recipient Inbox]
SMTP --> Inbox
style Client fill:#1e293b,stroke:#475569,color:#e2e8f0
style SDK fill:#1e40af,stroke:#3b82f6,color:#dbeafe
style API fill:#166534,stroke:#22c55e,color:#dcfce7
style Service fill:#166534,stroke:#22c55e,color:#dcfce7
style Decision fill:#7c3aed,stroke:#a78bfa,color:#ede9fe
style Cloud fill:#7c3aed,stroke:#a78bfa,color:#ede9fe
style SES fill:#ea580c,stroke:#f97316,color:#fed7aa
style SMTP fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Inbox fill:#0e7490,stroke:#06b6d4,color:#cffafe
```
## Channels
Managed SMTP or bring your own provider. Templates, delivery tracking, and webhook events.
Coming soon. Same API, Twilio or Sinch on the back.
Coming soon. APNs and FCM via a single endpoint.
## Features
### One API, every channel
Same `emails.send()` shape for email today, with SMS and push to follow when they land. Switching channels is a field change, not a rewrite.
### Managed delivery or bring your own
Send through InsForge Cloud (AWS SES for email today) for zero setup, or plug in your own provider when you need to control deliverability and sender reputation. See [Custom SMTP](/core-concepts/messaging/custom-smtp).
### Templates
Pick a template by name, pass the variables, and InsForge renders and sends. Templates are editable per project; the four auth templates (`email-verification-*`, `reset-password-*`) ship with sensible defaults.
### Delivery tracking
Send events (`accepted`, `delivered`, `bounced`, `complained`) are recorded per message. Query the audit table in Postgres, subscribe over webhooks, or watch the dashboard.
### Rate limits
Per-project and per-plan limits keep stray loops from melting deliverability. Configurable from the dashboard, enforced at the gateway.
## Concepts
Bring your own SMTP provider (SendGrid, Postmark, AWS SES, etc.).
## Build with it
Send mail from Node, browser, and edge runtimes.
Plain HTTP messaging endpoints, callable from any language.
## Next steps
* Set up the [CLI](/quickstart) to link your project (the recommended path).
* Browse the [TypeScript SDK reference](/sdks/typescript/email) for send patterns.
# Payments
Source: https://docs.insforge.dev/core-concepts/payments/overview
Choose a provider-specific payments integration for Stripe or Razorpay.
InsForge Payments lets your app collect money with your own Stripe or Razorpay account. The two providers use different payment models, so the docs are split by provider instead of describing one generic payment flow.
Stripe or Razorpay remains the source of truth for charges, invoices, refunds,
disputes, taxes, and account-level financial operations. InsForge is not a
payment processor or merchant of record, and it does not replace the provider
dashboard.
## Choose a provider
Use Stripe Checkout, Products, Prices, Subscriptions, and Billing Portal.
Use Razorpay Orders, Items, Plans, Subscriptions, and Razorpay Checkout.
## Architecture
Provider-native tables keep provider concepts intact:
| Provider | Runtime tables | Catalog tables | Subscription tables |
| -------- | ------------------------------------------------------------------------------- | ---------------------------------------------------- | --------------------------------------------------------------------- |
| Stripe | `payments.stripe_checkout_sessions`, `payments.stripe_customer_portal_sessions` | `payments.stripe_products`, `payments.stripe_prices` | `payments.stripe_subscriptions`, `payments.stripe_subscription_items` |
| Razorpay | `payments.razorpay_orders` | `payments.razorpay_items`, `payments.razorpay_plans` | `payments.razorpay_subscriptions` |
Shared tables are used only where the durable shape is useful across providers:
| Table | Purpose |
| ------------------------------- | ---------------------------------------------------------------------------------------------- |
| `payments.provider_connections` | Provider key, account, sync, and webhook setup status by `provider` and `environment`. |
| `payments.customer_mappings` | App billing subject to provider customer ID mapping. |
| `payments.customers` | Admin/customer mirror for dashboard visibility. |
| `payments.webhook_events` | Verified provider webhook event ledger. Use this for durable fulfillment triggers. |
| `payments.transactions` | InsForge dashboard/reporting projection for successful, failed, and refunded payment activity. |
`payments.transactions` is not the fulfillment contract. It is a projection built from provider events and sync. For business logic, create app-owned tables such as `public.orders`, `public.credit_ledger`, or `public.team_entitlements`, then populate them from verified rows in `payments.webhook_events`.
## Fulfillment
Do not fulfill from a Stripe success URL or a Razorpay Checkout callback alone. Those are user experience signals. Durable fulfillment should run from verified provider webhook events.
```sql theme={null}
CREATE TRIGGER fulfill_from_payment_webhook
AFTER INSERT OR UPDATE ON payments.webhook_events
FOR EACH ROW
EXECUTE FUNCTION public.fulfill_payment_event();
```
If your app accepts multiple providers, keep the trigger idempotent and branch on `NEW.provider` and `NEW.event_type`. Protect your app-owned fulfillment tables with your own RLS policies.
Webhook events are processed independently and providers give no ordering guarantee across events. Rows derived from an event are committed before that event is marked `processed`, but rows owned by other events — such as `payments.customer_mappings`, which checkout completion creates — may not exist yet when your trigger fires. Resolve billing subjects from the event payload first and treat lookups into other tables as fallbacks. See the provider guides for subscription fulfillment examples.
Older Stripe-only `payments.payment_history` rows are migrated into
`payments.transactions` for dashboard and reporting. Triggers on
`payment_history` are not rewritten automatically. Move fulfillment logic to
`payments.webhook_events`.
## Build with it
Pick the Stripe or Razorpay provider module for app code.
Review provider-specific Payments API routes and webhook routes.
## Next steps
* Read [Stripe Payments](/core-concepts/payments/stripe) if you are using Stripe Checkout or Billing Portal.
* Read [Razorpay Payments](/core-concepts/payments/razorpay) if you are using Razorpay Orders or Subscriptions.
* Configure provider keys in Dashboard -> Payments -> Settings.
* Add app-specific RLS or server-side membership checks for billing subjects.
* Add trigger-backed fulfillment from `payments.webhook_events`.
# Razorpay Payments
Source: https://docs.insforge.dev/core-concepts/payments/razorpay
Integrate Razorpay Orders, Subscriptions, manual webhooks, and webhook fulfillment with InsForge.
Use the Razorpay integration when you want Razorpay Orders, Razorpay Checkout, Items, Plans, and Subscriptions. Razorpay is not a hosted redirect flow like Stripe Checkout. Your backend creates the provider object, your frontend opens the Razorpay Checkout script, and your backend verifies the returned signature.
## Razorpay model
| Razorpay concept | Meaning in InsForge |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| Item | Amount-bearing sellable unit. Mirrored in `payments.razorpay_items`. |
| Plan | Recurring subscription definition around an item. Mirrored in `payments.razorpay_plans`. |
| Order | One-time payment object. Created through `POST /api/payments/razorpay/{environment}/orders` and mirrored in `payments.razorpay_orders`. |
| Payment | Provider payment result. Projected into `payments.transactions` from webhooks and sync. |
| Subscription | Razorpay subscription tied to a Plan. Mirrored in `payments.razorpay_subscriptions`. |
| Webhook event | Verified provider event in `payments.webhook_events` with `provider = 'razorpay'`. |
Razorpay does not have a Stripe Billing Portal equivalent. InsForge exposes backend routes to cancel, pause, and resume subscriptions after checking the caller against `payments.razorpay_subscriptions` RLS `UPDATE` policies.
For one-time products, Razorpay Orders can be created with only an amount, currency, and receipt. Still, prefer creating Razorpay Items for sellable products so the catalog is visible in InsForge and Razorpay after sync. Treat Orders as payment attempts, not as your product catalog.
## Setup
Configure `test` and `live` Razorpay Key ID and Key Secret in Dashboard -> Payments -> Settings or through the admin API. InsForge generates a webhook signing secret if one does not already exist.
Razorpay webhooks must be created manually in the Razorpay Dashboard. Razorpay normal merchant API keys do not support automatic webhook registration.
1. Open Dashboard -> Payments -> Settings -> Webhooks.
2. Copy the Razorpay Webhook URL and Webhook Secret.
3. In the Razorpay Dashboard, create a webhook with the copied URL and secret.
4. Select the events InsForge handles.
5. Save the webhook and complete a test payment to confirm delivery.
Razorpay can only deliver webhooks to a public HTTPS URL. Localhost URLs need a public tunnel or a deployed backend.
Handled events:
* `payment.authorized`
* `payment.captured`
* `payment.failed`
* `order.paid`
* `invoice.paid`
* `invoice.expired`
* `refund.created`
* `refund.processed`
* `refund.failed`
* `subscription.created`
* `subscription.activated`
* `subscription.charged`
* `subscription.updated`
* `subscription.cancelled`
* `subscription.paused`
* `subscription.resumed`
* `subscription.halted`
* `subscription.completed`
* `subscription.expired`
## One-time orders
Create an app-owned pending order first. Then create a Razorpay Order with the current InsForge user token.
```typescript theme={null}
const { data, error } = await insforge.payments.razorpay.createOrder('test', {
amount: 50000,
currency: 'INR',
receipt: 'order_123',
subject: { type: 'team', id: 'team_123' },
customerEmail: 'buyer@example.com',
notes: { order_id: 'order_123' }
});
if (error) throw error;
```
The SDK wraps `POST /api/payments/razorpay/{environment}/orders`. The response includes `checkoutOptions` with Razorpay Checkout-native fields such as `key` and `order_id`. Load `https://checkout.razorpay.com/v1/checkout.js` in the frontend and pass those options to `new Razorpay(options).open()`.
If your fulfillment trigger reads `notes.order_id`, pass `notes: { order_id: ... }` when creating the Order or Subscription.
After Razorpay Checkout returns `razorpay_order_id`, `razorpay_payment_id`, and `razorpay_signature`, verify the signature on the backend:
```typescript theme={null}
await insforge.payments.razorpay.verifyOrder('test', {
orderId: response.razorpay_order_id,
paymentId: response.razorpay_payment_id,
signature: response.razorpay_signature
});
```
Signature verification proves the immediate Checkout callback came from Razorpay. Durable order fulfillment should still run from verified Razorpay webhook events.
## Subscriptions
Create or sync a Razorpay Plan before creating subscriptions. A Plan is not the same thing as a Stripe Price. It is a recurring definition around a Razorpay Item.
```typescript theme={null}
const { data, error } = await insforge.payments.razorpay.createSubscription('test', {
planId: 'plan_123',
totalCount: 12,
subject: { type: 'team', id: 'team_123' },
customerEmail: 'buyer@example.com'
});
if (error) throw error;
```
The SDK wraps `POST /api/payments/razorpay/{environment}/subscriptions`. The response includes `checkoutOptions.subscription_id`. Open Razorpay Checkout with that subscription ID. After Checkout returns `razorpay_subscription_id`, `razorpay_payment_id`, and `razorpay_signature`, verify the authorization payment:
```typescript theme={null}
await insforge.payments.razorpay.verifySubscription('test', {
subscriptionId: response.razorpay_subscription_id,
paymentId: response.razorpay_payment_id,
signature: response.razorpay_signature
});
```
Manage subscriptions through backend routes:
```typescript theme={null}
await insforge.payments.razorpay.cancelSubscription('test', 'sub_123', {
cancelAtCycleEnd: false
});
await insforge.payments.razorpay.pauseSubscription('test', 'sub_123');
await insforge.payments.razorpay.resumeSubscription('test', 'sub_123');
```
Subscription creation evaluates `INSERT` policies on `payments.razorpay_subscriptions`. Cancel, pause, and resume evaluate `UPDATE` policies on the same table. PostgreSQL also applies `SELECT` policies to rows returned by `INSERT/UPDATE ... RETURNING`, so make the same subject visible to the caller when a policy probe needs to return the row. Grant users only the table access needed for policy checks; provider mutations still run through the backend.
## Webhooks and fulfillment
Razorpay's Checkout callback and signature verification are not a replacement for webhooks. Use `payments.webhook_events` for fulfillment triggers. Do not attach fulfillment triggers to provider mirror tables such as `payments.razorpay_subscriptions`; sync and webhook projection can update those rows independently of provider event delivery.
```sql theme={null}
CREATE OR REPLACE FUNCTION public.fulfill_razorpay_order()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.provider = 'razorpay'
AND NEW.event_type IN ('payment.captured', 'order.paid', 'invoice.paid')
AND NEW.processing_status = 'processed'
AND COALESCE(
NEW.payload -> 'payload' -> 'payment' -> 'entity' -> 'notes' ->> 'order_id',
NEW.payload -> 'payload' -> 'invoice' -> 'entity' -> 'notes' ->> 'order_id'
) IS NOT NULL THEN
UPDATE public.orders
SET status = 'paid',
paid_at = COALESCE(NEW.processed_at, NOW())
WHERE id::text = COALESCE(
NEW.payload -> 'payload' -> 'payment' -> 'entity' -> 'notes' ->> 'order_id',
NEW.payload -> 'payload' -> 'invoice' -> 'entity' -> 'notes' ->> 'order_id'
)
AND status = 'pending';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER fulfill_razorpay_order_from_webhook
AFTER INSERT OR UPDATE ON payments.webhook_events
FOR EACH ROW
EXECUTE FUNCTION public.fulfill_razorpay_order();
```
## Sync and dashboard state
Razorpay sync mirrors Items, Plans, Customers, Subscriptions, Invoices, and Payments. Invoices and payments feed the `payments.transactions` dashboard/reporting projection. Transactions include provider reference IDs such as payment, invoice, order, subscription, and refund IDs so you can inspect the source record in the Razorpay Dashboard.
Keep user-facing order, credit, and entitlement state in your own app tables. Treat `payments.transactions` as dashboard/reporting state, not as the primary business workflow.
## References
* [Razorpay Standard Checkout integration](https://razorpay.com/docs/payments/payment-gateway/web-integration/standard/integration-steps/)
* [Razorpay Subscriptions integration](https://razorpay.com/docs/payments/subscriptions/integration-guide/)
* [Razorpay Webhooks setup](https://razorpay.com/docs/payments/dashboard/account-settings/webhooks/)
* [TypeScript Razorpay payments guide](/sdks/typescript/payments-razorpay)
# Stripe Payments
Source: https://docs.insforge.dev/core-concepts/payments/stripe
Integrate Stripe Checkout, Billing Portal, catalog sync, and webhook fulfillment with InsForge.
Use the Stripe integration when you want Stripe-hosted Checkout, Stripe Products and Prices, Stripe Subscriptions, and the hosted Billing Portal.
InsForge stores Stripe secret keys server-side, creates Checkout and Billing Portal sessions from your app, automatically manages the Stripe webhook endpoint when your backend is reachable, mirrors Stripe state into the `payments` schema, and records verified webhook events.
## Stripe model
| Stripe concept | InsForge table or API |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Product | `payments.stripe_products` |
| Price | `payments.stripe_prices` |
| Checkout Session | `POST /api/payments/stripe/{environment}/checkout-sessions` and `payments.stripe_checkout_sessions` |
| Billing Portal Session | `POST /api/payments/stripe/{environment}/customer-portal-sessions` and `payments.stripe_customer_portal_sessions` |
| Subscription | `payments.stripe_subscriptions` and `payments.stripe_subscription_items` |
| Customer mapping | `payments.customer_mappings` with `provider = 'stripe'` |
| Webhook event | `payments.webhook_events` with `provider = 'stripe'` |
| Dashboard transaction row | `payments.transactions` with `provider = 'stripe'` |
## Setup
Configure `test` and `live` Stripe secret keys in Dashboard -> Payments -> Settings, the CLI, or the admin API.
```bash theme={null}
npx @insforge/cli payments stripe status
npx @insforge/cli payments stripe config set --environment test sk_test_xxx
npx @insforge/cli payments stripe sync --environment test
npx @insforge/cli payments stripe webhooks configure --environment test
```
After a key is connected, InsForge validates the account, stores the key in the secret store, tries to create the managed Stripe webhook endpoint, and runs sync for Products, Prices, Customers, and Subscriptions.
## Checkout
Create Checkout Sessions from frontend code with the current InsForge user token.
```typescript theme={null}
const { data, error } = await insforge.payments.stripe.createCheckoutSession('test', {
mode: 'payment',
lineItems: [{ priceId: 'price_123', quantity: 1 }],
successUrl: `${window.location.origin}/checkout/success`,
cancelUrl: `${window.location.origin}/pricing`,
customerEmail: user?.email ?? null,
metadata: { order_id: orderId },
idempotencyKey: `order:${orderId}`
});
if (error) throw error;
if (data?.checkoutSession.url) {
window.location.assign(data.checkoutSession.url);
}
```
For subscription Checkout, pass a billing subject. The subject is your app-owned billing owner, such as a user, team, workspace, organization, tenant, or group.
```typescript theme={null}
const { data, error } = await insforge.payments.stripe.createCheckoutSession('test', {
mode: 'subscription',
subject: { type: 'team', id: teamId },
lineItems: [{ priceId: 'price_monthly_123', quantity: 1 }],
successUrl: `${window.location.origin}/billing/success`,
cancelUrl: `${window.location.origin}/billing`,
customerEmail: user.email,
idempotencyKey: `team:${teamId}:pro-monthly`
});
if (error) throw error;
if (data?.checkoutSession.url) {
window.location.assign(data.checkoutSession.url);
}
```
Checkout inserts a row in `payments.stripe_checkout_sessions` using the caller's InsForge token. Add RLS policies so users can only create sessions for subjects they are allowed to bill. PostgreSQL applies `SELECT` policies to rows returned by `INSERT ... RETURNING` and idempotent lookups, so retries also need a matching `SELECT` policy for the same subject and idempotency key.
## Billing Portal
Use the hosted Billing Portal for an existing Stripe customer mapping.
```typescript theme={null}
const { data, error } = await insforge.payments.stripe.createCustomerPortalSession('test', {
subject: { type: 'team', id: teamId },
returnUrl: `${window.location.origin}/billing`
});
if (error) {
if ('statusCode' in error && error.statusCode === 404) {
return;
}
throw error;
}
if (data?.customerPortalSession.url) {
window.location.assign(data.customerPortalSession.url);
}
```
Portal creation requires an authenticated user and an existing `payments.customer_mappings` row for the subject. Protect portal creation with RLS or a server-side membership check so users cannot open billing settings for a team or organization they do not manage.
## Webhooks and fulfillment
Stripe webhooks are managed automatically when the backend has a public URL. InsForge listens for the events needed to keep checkout attempts, customers, subscriptions, refunds, and transaction projections current.
Stripe also recommends fulfilling Checkout orders from webhooks instead of the success URL. In InsForge, attach fulfillment triggers to `payments.webhook_events`.
```sql theme={null}
CREATE OR REPLACE FUNCTION public.fulfill_stripe_order()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.provider = 'stripe'
AND NEW.event_type = 'checkout.session.completed'
AND NEW.processing_status = 'processed'
AND (NEW.payload -> 'data' -> 'object' -> 'metadata' ->> 'order_id') IS NOT NULL THEN
UPDATE public.orders
SET status = 'paid',
paid_at = COALESCE(NEW.processed_at, NOW())
WHERE id::text = NEW.payload -> 'data' -> 'object' -> 'metadata' ->> 'order_id'
AND status = 'pending';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER fulfill_stripe_order_from_webhook
AFTER INSERT OR UPDATE ON payments.webhook_events
FOR EACH ROW
EXECUTE FUNCTION public.fulfill_stripe_order();
```
### Event ordering
Webhook events are verified and processed independently. InsForge commits every row derived from an event before marking that event `processed`, but Stripe gives no ordering guarantee across events: `invoice.paid` can be processed before `checkout.session.completed`, so rows created by another event (such as `payments.customer_mappings`) may not exist yet when your trigger fires.
For subscription events, resolve the billing subject from the event payload first — InsForge stamps `insforge_subject_type` and `insforge_subject_id` into subscription metadata at checkout, and Stripe snapshots it onto subscription-generated invoices as `parent.subscription_details.metadata`. Check `invoice.metadata` next, then fall back to `payments.customer_mappings` (the same order InsForge uses internally):
```sql theme={null}
CREATE OR REPLACE FUNCTION public.grant_subscription_access()
RETURNS TRIGGER AS $$
DECLARE
v_subject_type TEXT;
v_subject_id TEXT;
BEGIN
IF NEW.provider = 'stripe'
AND NEW.event_type = 'invoice.paid'
AND NEW.processing_status = 'processed' THEN
v_subject_type := COALESCE(
NEW.payload -> 'data' -> 'object' -> 'parent'
-> 'subscription_details' -> 'metadata' ->> 'insforge_subject_type',
NEW.payload -> 'data' -> 'object' -> 'metadata' ->> 'insforge_subject_type'
);
v_subject_id := COALESCE(
NEW.payload -> 'data' -> 'object' -> 'parent'
-> 'subscription_details' -> 'metadata' ->> 'insforge_subject_id',
NEW.payload -> 'data' -> 'object' -> 'metadata' ->> 'insforge_subject_id'
);
IF v_subject_id IS NULL THEN
SELECT m.subject_type, m.subject_id
INTO v_subject_type, v_subject_id
FROM payments.customer_mappings m
WHERE m.provider = NEW.provider
AND m.environment = NEW.environment
AND m.provider_customer_id = NEW.payload -> 'data' -> 'object' ->> 'customer';
END IF;
IF v_subject_id IS NULL THEN
RAISE WARNING 'Stripe event % has no resolvable billing subject', NEW.provider_event_id;
RETURN NEW;
END IF;
-- Branch on the subject type sent at checkout; team_id is a UUID here,
-- so the type check also guards the cast.
IF v_subject_type = 'team' THEN
INSERT INTO public.team_entitlements (team_id, plan, active, updated_at)
VALUES (v_subject_id::uuid, 'pro', true, NOW())
ON CONFLICT (team_id) DO UPDATE SET
plan = EXCLUDED.plan,
active = true,
updated_at = NOW();
END IF;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER grant_subscription_access_from_stripe_webhook
AFTER INSERT OR UPDATE ON payments.webhook_events
FOR EACH ROW
EXECUTE FUNCTION public.grant_subscription_access();
```
Never let fulfillment skip silently — log or dead-letter events you cannot resolve so they can be replayed.
## Sync and dashboard state
Stripe sync mirrors Products, Prices, Customers, and Subscriptions. Webhooks maintain session, subscription, customer, refund, and transaction state as Stripe emits events.
`payments.transactions` is a reporting projection for the dashboard. It gives you provider reference IDs such as payment intent, charge, invoice, checkout session, and refund IDs so you can look up details in the Stripe Dashboard. Keep user-facing order, credit, or entitlement state in your own tables.
## References
* [Stripe Checkout fulfillment](https://docs.stripe.com/checkout/fulfillment)
* [Stripe Billing Portal Sessions API](https://docs.stripe.com/api/customer_portal/sessions/create)
* [TypeScript Stripe payments guide](/sdks/typescript/payments-stripe)
# Realtime
Source: https://docs.insforge.dev/core-concepts/realtime/overview
Send database changes, broadcasts, presence, and webhook fan-out through realtime channels.
Use InsForge Realtime when your app needs to update without a page refresh. Clients subscribe to channels such as `order:123` or `chat:room-1`, then receive database changes, broadcasts, and presence updates over WebSockets. Channels can also fan out the same messages to webhook URLs when another service should receive the event.
**Need server-side code to run after a database change?** Put that business logic in an [Edge Function](/core-concepts/functions/overview) and invoke it from a database trigger. Use Realtime when the change should be delivered to connected clients or configured webhook endpoints.
```mermaid theme={null}
graph TB
App[Client application] --> SDK[InsForge SDK]
SDK --> Channel[Realtime channel]
Database[(Postgres)] --> Trigger[Database trigger]
Trigger --> Channel
Channel --> WebSocket[WebSocket subscribers]
Channel --> Presence[Presence state]
Channel --> Webhook[Webhook URLs]
Channel --> History[(Message history)]
Auth[Auth token and RLS] --> Channel
style App fill:#1e293b,stroke:#475569,color:#e2e8f0
style SDK fill:#1e40af,stroke:#3b82f6,color:#dbeafe
style Channel fill:#166534,stroke:#22c55e,color:#dcfce7
style Database fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Trigger fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
style WebSocket fill:#c2410c,stroke:#fb923c,color:#fed7aa
style Presence fill:#c2410c,stroke:#fb923c,color:#fed7aa
style Webhook fill:#c2410c,stroke:#fb923c,color:#fed7aa
style History fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Auth fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
```
## Features
### Channels
Channels are named topics that clients can join. Use exact names for shared rooms, or patterns like `order:%` when every record needs its own live stream.
### Database changes
Use database changes when a table write should become a live app event. Create a trigger on the table you want to watch. In its trigger function, call the predefined `realtime.publish(channel, event, payload)` function to decide which channel receives the message, which event name clients handle, and what payload they receive.
For a channel pattern such as `order:%`, a trigger can publish one event per order:
```sql theme={null}
CREATE OR REPLACE FUNCTION public.notify_order_status()
RETURNS TRIGGER AS $$
BEGIN
PERFORM realtime.publish(
'order:' || NEW.id::text,
'status_changed',
jsonb_build_object(
'id', NEW.id,
'status', NEW.status,
'updatedAt', NEW.updated_at
)
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER order_status_realtime
AFTER UPDATE OF status ON public.orders
FOR EACH ROW
WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION public.notify_order_status();
```
Then subscribe from the app with the SDK:
```typescript theme={null}
const channel = `order:${orderId}`;
await insforge.realtime.connect();
const subscription = await insforge.realtime.subscribe(channel);
if (!subscription.ok) {
throw new Error(subscription.error.message);
}
insforge.realtime.on('status_changed', (message) => {
renderOrderStatus(message.status);
});
```
### Client broadcasts
Clients can publish messages to channels they have already joined. Use this for chat, typing indicators, cursors, collaborative editing signals, and other user-to-user updates that do not need to start from a database write.
```typescript theme={null}
await insforge.realtime.publish(`chat:${roomId}`, 'typing', {
userId,
isTyping: true
});
```
### Webhooks
Attach webhook URLs to a channel when another service should receive each message. InsForge posts the event payload to every configured URL, includes headers for the event name, channel, and message ID, retries transient network failures, and records webhook delivery counts in message history.
### Presence
Presence tracks who is online in a channel. Clients receive the current member snapshot when they subscribe, then `presence:join` and `presence:leave` events as members come and go. Store durable room membership, roles, and permissions in your own tables; presence is only online state.
```typescript theme={null}
const response = await insforge.realtime.subscribe(`chat:${roomId}`);
if (response.ok) {
renderOnlineMembers(response.presence.members);
}
insforge.realtime.on('presence:join', (message) => {
addOnlineMember(message.member);
});
insforge.realtime.on('presence:leave', (message) => {
removeOnlineMember(message.member.presenceId);
});
```
### Row-level security
Realtime can be open while prototyping, then locked down with Postgres RLS. Use `SELECT` policies on `realtime.channels` to control who can subscribe, and `INSERT` policies on `realtime.messages` to control who can publish from a client.
This policy lets authenticated users subscribe to `order:` channels only when the order belongs to them:
```sql theme={null}
ALTER TABLE realtime.channels ENABLE ROW LEVEL SECURITY;
CREATE POLICY "users_subscribe_own_orders"
ON realtime.channels
FOR SELECT
TO authenticated
USING (
pattern = 'order:%'
AND EXISTS (
SELECT 1
FROM public.orders
WHERE id = NULLIF(split_part(realtime.channel_name(), ':', 2), '')::uuid
AND user_id = auth.uid()
)
);
```
Use `realtime.channel_name()` in subscribe policies because clients subscribe to resolved channels such as `order:123`, while `realtime.channels` stores patterns such as `order:%`.
### Message history
Every delivered event is recorded with WebSocket and webhook delivery counts. The dashboard can inspect recent messages, delivery stats, and retention settings when you need to debug live behavior.
## Build with it
Subscribe to channels, publish events, and track presence from Node, browser, and edge.
Native Swift realtime client for iOS and macOS.
Coroutines-first realtime client for Android and JVM.
Use the raw Socket.IO contract from any language.
## Next steps
* Set up the [CLI](/quickstart) to link your project.
* Create channels in the Realtime dashboard.
* Use the [TypeScript SDK reference](/sdks/typescript/realtime) for client subscriptions.
* Add webhook URLs to a channel when another service needs the same event stream.
# Sites
Source: https://docs.insforge.dev/core-concepts/sites/overview
Deploy frontend apps from your project, powered by Vercel.
Use InsForge Sites to ship the browser-facing app that belongs to your project. The InsForge CLI uploads your frontend source through InsForge, which creates a Vercel production deployment. The dashboard tracks the URL, status, deployment history, environment variables, and domains.
**Need to deploy a container or backend service?** Use [Compute](/core-concepts/compute/overview) for workers, queues, WebSocket servers, and long-running services. Sites are for frontend websites and framework builds that produce a hosted web app.
```mermaid theme={null}
flowchart TB
CLI[InsForge CLI] --> API[InsForge deployment API]
Dashboard[Dashboard] --> API
API --> Source[Frontend source upload]
API --> Config[Environment variables and domains]
Source --> Vercel[Vercel production build]
Config --> Vercel
Vercel --> App[Frontend app]
App --> URL[Public URL]
App --> Status[Status and deployment history]
style CLI fill:#1e293b,stroke:#475569,color:#e2e8f0
style Dashboard fill:#1e293b,stroke:#475569,color:#e2e8f0
style API fill:#166534,stroke:#22c55e,color:#dcfce7
style Source fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Config fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
style Vercel fill:#c2410c,stroke:#fb923c,color:#fed7aa
style App fill:#166534,stroke:#22c55e,color:#dcfce7
style URL fill:#166534,stroke:#22c55e,color:#dcfce7
style Status fill:#4c1d95,stroke:#8b5cf6,color:#ede9fe
```
## Features
### CLI deploys
Deploy from your app's source directory. The CLI uploads the source tree, skips local-only files such as `node_modules`, `.git`, build output, and `.env` files, then starts the Vercel build through InsForge.
```bash theme={null}
npx @insforge/cli deployments deploy ./frontend
```
### Framework builds
Deploy React, Vue, Svelte, Next.js, static sites, and other frontend projects. InsForge sends the source files to Vercel, where framework detection and project files such as `package.json` and `vercel.json` decide how the app builds.
### Environment variables
Manage provider environment variables from the dashboard. Use public prefixes such as `VITE_` or `NEXT_PUBLIC_` only for values that are safe to expose in browser code.
```bash theme={null}
npx @insforge/cli deployments env list
npx @insforge/cli deployments env set VITE_INSFORGE_URL https://your-project.region.insforge.app
npx @insforge/cli deployments env set VITE_INSFORGE_ANON_KEY ik_xxx
```
### Deployment history
Review previous runs, sync Vercel status, inspect metadata, and cancel in-progress deployments from the Deployment Logs page.
```bash theme={null}
npx @insforge/cli deployments list
npx @insforge/cli deployments status deployment_123 --sync
npx @insforge/cli deployments cancel deployment_123
```
### Domains
Every ready deployment gets a default URL at `https://.insforge.site`. You can also set an InsForge-managed slug at `https://.insforge.site`. For a custom domain, add the domain in the dashboard and configure the DNS record it returns, usually a CNAME for subdomains.
## Deploy with it
Connect your project and run InsForge CLI commands from your app directory.
## Next steps
* Set up the [CLI](/quickstart) and connect your project.
* Add browser-safe environment variables from the dashboard or with `npx @insforge/cli deployments env set`.
* Run `npx @insforge/cli deployments deploy ./frontend`.
# Storage
Source: https://docs.insforge.dev/core-concepts/storage/overview
Store and serve large binary files.
Use InsForge to store and serve large binary files: images, videos, PDFs, audio, backups, anything you would not put in a database row. Every project gets an S3-compatible bucket. Files are served behind signed URLs, access policies follow the same row-level security model as the database, and the S3 API works with rclone, the AWS CLI, Terraform, and SDKs in any language.
**Looking for structured data?** Use [Database](/core-concepts/database/overview) for rows, relations, and queries. Storage holds objects; the database holds rows. Keep file metadata (owner, name, size, content type) in a database table and the bytes in storage.
```mermaid theme={null}
graph TB
Client[Client Application] --> SDK[InsForge SDK]
SDK --> StorageAPI[Storage API]
StorageAPI --> S3[AWS S3]
StorageAPI --> DB[(PostgreSQL)]
DB --> Metadata[File Metadata]
DB --> Buckets[Bucket Configuration]
S3 --> DirectUpload[Presigned URLs]
S3 --> SecureAccess[IAM Policies]
style Client fill:#1e293b,stroke:#475569,color:#e2e8f0
style SDK fill:#1e40af,stroke:#3b82f6,color:#dbeafe
style StorageAPI fill:#166534,stroke:#22c55e,color:#dcfce7
style S3 fill:#ea580c,stroke:#f97316,color:#fed7aa
style DB fill:#0e7490,stroke:#06b6d4,color:#cffafe
style Metadata fill:#0e7490,stroke:#22d3ee,color:#cffafe
style Buckets fill:#0e7490,stroke:#22d3ee,color:#cffafe
style DirectUpload fill:#ea580c,stroke:#fb923c,color:#fed7aa
style SecureAccess fill:#ea580c,stroke:#fb923c,color:#fed7aa
```
## Features
### S3-compatible API
Point any S3 client at your project's bucket. Native AWS credentials, native multipart uploads, native presigned URLs. See [S3 compatibility](/core-concepts/storage/s3-compatibility).
### Signed URLs
Generate time-limited URLs to share private objects without exposing your credentials. The SDK and REST API both issue signed URLs for upload and download.
### Row-level security
Storage policies read the same auth JWT as database queries. The same user who can `SELECT` a row can `GET` the file the row references, so you never maintain a separate set of storage permissions.
### Buckets
Group objects into buckets with separate access policies. Public buckets serve files directly over HTTPS; private buckets require a signed URL or an authenticated request.
### Direct uploads
Browser and mobile clients upload straight to storage with a presigned URL. The backend never proxies bytes.
## Concepts
Point any S3 client at your project's bucket with native credentials.
## Build with it
Upload, download, list, and manage objects from Node, browser, and edge.
Native Swift storage client for iOS and macOS.
Coroutines-first storage client for Android and JVM.
Plain HTTP storage endpoints, callable from any language.
## Next steps
* Set up the [CLI](/quickstart) to link your project (the recommended path).
* Browse the [TypeScript SDK reference](/sdks/typescript/storage) for uploads and downloads.
# S3-compatible gateway
Source: https://docs.insforge.dev/core-concepts/storage/s3-compatibility
Use any AWS SigV4 client against InsForge Storage
InsForge Storage speaks the [AWS S3 protocol](https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html) at `/storage/v1/s3`. Cloud projects only.
## Concepts
Long-lived access keys signed with SigV4. Project-admin scope across every bucket, path-style URLs only. S3 uploads appear immediately in the REST API and Dashboard. Generate keys in **Storage → Settings → S3 Configuration**.
## Usage
Fetch endpoint and region from the Dashboard or `GET /api/storage/s3/config`.
```ini theme={null}
# ~/.aws/credentials
[insforge]
aws_access_key_id = your_access_key_id
aws_secret_access_key = your_secret_access_key
# ~/.aws/config
[profile insforge]
region = us-east-2
endpoint_url = https://project_ref.region.insforge.app/storage/v1/s3
s3 =
addressing_style = path
```
```bash theme={null}
aws --profile insforge s3 cp ./photo.jpg s3://my-bucket/photo.jpg
aws --profile insforge s3 sync ./dist s3://my-bucket/dist
```
In code, set `forcePathStyle: true` and point `endpoint` at `/storage/v1/s3`.
```ts theme={null}
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
const client = new S3Client({
forcePathStyle: true,
region: 'us-east-2',
endpoint: 'https://project_ref.region.insforge.app/storage/v1/s3',
credentials: { accessKeyId: '...', secretAccessKey: '...' },
});
await client.send(new PutObjectCommand({ Bucket: 'my-bucket', Key: 'hello.txt', Body: 'hello' }));
```
## Limits
`PutObject` caps at 5 GB, multipart at 5 TB. 50 keys per project, 15-minute clock skew. Secret keys show once on creation.
Not supported: presigned URLs (use `POST /api/storage/buckets/:bucket/upload-strategy`), session tokens, virtual-hosted URLs. Versioning, SSE-C/KMS, ACLs, object lock, tagging, lifecycle, and CORS return `501 NotImplemented`.
## More resources
* [Storage overview](/core-concepts/storage/overview) for the gateway internals.
* [TypeScript storage SDK](/sdks/typescript/storage) for browser uploads.
* [AWS SigV4 reference](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-signing.html) for signing details.
# Deploy to aws ec2
Source: https://docs.insforge.dev/deployment/deploy-to-aws-ec2
# Deploy InsForge to AWS EC2
This guide will walk you through deploying InsForge on an AWS EC2 instance using Docker Compose.
This cloud walkthrough is community-maintained and can lag the latest InsForge release. The canonical, always-current setup is the `deploy/docker-compose/` directory in the [InsForge repo](https://github.com/InsForge/InsForge).
## 📋 Prerequisites
* AWS Account with EC2 access
* Basic knowledge of SSH and command-line operations
* Domain name (optional, for custom domain setup)
## 🚀 Deployment Steps
### 1. Create and Configure EC2 Instance
#### 1.1 Launch EC2 Instance
1. **Log into AWS Console** and navigate to EC2 Dashboard
2. **Click "Launch Instance"**
3. **Configure Instance:**
* **Name**: `insforge-server` (or your preferred name)
* **AMI**: Ubuntu Server 24.04 LTS (HVM), SSD Volume Type
* **Instance Type**: `t3.medium` or larger (minimum 2 vCPU, 4 GB RAM)
* For production: `t3.large` (2 vCPU, 8 GB RAM) recommended
* For testing: `t3.small` (2 vCPU, 2 GB RAM) minimum
* **Key Pair**: Create new or select existing key pair (download and save the `.pem` file)
* **Storage**: 30 GB gp3 (minimum 20 GB recommended)
#### 1.2 Configure Security Group
Create or configure security group with the following inbound rules:
| Type | Protocol | Port Range | Source | Description |
| ---------- | -------- | ---------- | --------- | --------------------- |
| SSH | TCP | 22 | My IP | SSH access |
| HTTP | TCP | 80 | 0.0.0.0/0 | HTTP access |
| HTTPS | TCP | 443 | 0.0.0.0/0 | HTTPS access |
| Custom TCP | TCP | 7130 | 0.0.0.0/0 | Dashboard + API |
| Custom TCP | TCP | 5432 | 0.0.0.0/0 | PostgreSQL (optional) |
> ⚠️ **Security Note**: For production, restrict PostgreSQL (5432) to specific IP addresses or remove external access entirely. Consider using a reverse proxy (nginx) and exposing only ports 80/443.
#### 1.3 Allocate Elastic IP (Recommended)
1. Navigate to **Elastic IPs** in EC2 Dashboard
2. Click **Allocate Elastic IP address**
3. Associate the Elastic IP with your instance
This ensures your instance keeps the same IP address even after restarts.
### 2. Connect to Your EC2 Instance
```bash theme={null}
# Set correct permissions for your key file
chmod 400 your-key-pair.pem
# Connect via SSH
ssh -i your-key-pair.pem ubuntu@your-ec2-public-ip
```
### 3. Install Dependencies
#### 3.1 Update System Packages
```bash theme={null}
sudo apt update && sudo apt upgrade -y
```
#### 3.2 Install Docker
```text theme={null}
Follow the instructions of the link below to install and verify docker on your new ubuntu ec2 instance:
https://docs.docker.com/engine/install/ubuntu/
```
#### 3.3 Add Your User to Docker Group
After installing Docker, you need to add your user to the `docker` group to run Docker commands without `sudo`:
```bash theme={null}
# Add your user to the docker group
sudo usermod -aG docker $USER
# Apply the group changes
newgrp docker
```
**Verify it works:**
```bash theme={null}
# This should now work without sudo
docker ps
```
> 💡 **Note**: If `docker ps` doesn't work immediately, log out and log back in via SSH, then try again.
> ⚠️ **Security Note**: Adding a user to the `docker` group grants them root-equivalent privileges on the system. This is acceptable for single-user environments like your EC2 instance, but be cautious on shared systems.
#### 3.4 Install Git
```bash theme={null}
sudo apt install git -y
```
### 4. Deploy InsForge
#### 4.1 Clone Repository
```bash theme={null}
cd ~
git clone https://github.com/insforge/insforge.git
cd insforge/deploy/docker-compose
```
#### 4.2 Create Environment Configuration
Copy the example template to create your `.env` file:
```bash theme={null}
cp .env.example .env
nano .env
```
The full template lives at `deploy/docker-compose/.env.example`. These are the variables you must set:
```env theme={null}
# Required
JWT_SECRET=your-secret-key-here-must-be-32-char-or-above
ROOT_ADMIN_USERNAME=admin
ROOT_ADMIN_PASSWORD=change-this-password
POSTGRES_PASSWORD=change-this-password
# Optional: falls back to JWT_SECRET if left blank
ENCRYPTION_KEY=
# Optional: enables AI features
OPENROUTER_API_KEY=
# Optional: enables site deployments
VERCEL_TOKEN=
VERCEL_TEAM_ID=
VERCEL_PROJECT_ID=
# Optional: OAuth providers
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
```
The `.env.example` template carries the remaining variables and their defaults, so editing the copied file is enough.
**Generate Secure Secrets:**
```bash theme={null}
# Generate JWT_SECRET (32+ characters)
openssl rand -base64 32
# Generate ENCRYPTION_KEY (must be exactly 32 characters)
openssl rand -base64 24
```
> 💡 **Important**: Save these secrets securely. You'll need them if you ever migrate or restore your instance.
#### 4.3 Start InsForge Services
```bash theme={null}
# Pull Docker images and start services
docker compose up -d
# View logs to ensure everything started correctly
docker compose logs -f
```
Press `Ctrl+C` to exit log view.
#### 4.4 Verify Services
```bash theme={null}
# Check running containers
docker compose ps
# You should see 4 running services:
# - postgres
# - postgrest
# - insforge
# - deno
```
### 5. Access Your InsForge Instance
#### 5.1 Test Backend API
```bash theme={null}
curl http://your-ec2-ip:7130/api/health
```
Expected response:
```json theme={null}
{
"status": "ok",
"version": "2.1.7",
"service": "Insforge OSS Backend",
"timestamp": "2025-10-17T..."
}
```
#### 5.2 Access Dashboard
Open your browser and navigate to:
```text theme={null}
http://your-ec2-ip:7130
```
Log in with the `ROOT_ADMIN_USERNAME` and `ROOT_ADMIN_PASSWORD` you set in `.env`.
### 6. Configure Domain (Optional but Recommended)
#### 6.1 Update DNS Records
Add DNS A records pointing to your EC2 Elastic IP:
```text theme={null}
api.yourdomain.com → your-ec2-ip
app.yourdomain.com → your-ec2-ip
```
#### 6.2 Install Nginx Reverse Proxy
```bash theme={null}
sudo apt install nginx -y
```
Create Nginx configuration:
```bash theme={null}
sudo nano /etc/nginx/sites-available/insforge
```
Add the following configuration:
```nginx theme={null}
# Backend API
server {
listen 80;
server_name api.yourdomain.com;
location / {
proxy_pass http://localhost:7130;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
# Dashboard (served by the backend on the same port as the API)
server {
listen 80;
server_name app.yourdomain.com;
location / {
proxy_pass http://localhost:7130;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
```
Enable the configuration:
```bash theme={null}
sudo ln -s /etc/nginx/sites-available/insforge /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
#### 6.3 Install SSL Certificate (Recommended)
```bash theme={null}
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Obtain SSL certificates
sudo certbot --nginx -d api.yourdomain.com -d app.yourdomain.com
# Follow the prompts to complete setup
```
Update your `.env` file with HTTPS URLs:
```bash theme={null}
cd ~/insforge/deploy/docker-compose
nano .env
```
Change:
```env theme={null}
API_BASE_URL=https://api.yourdomain.com
VITE_API_BASE_URL=https://api.yourdomain.com
```
Restart services:
```bash theme={null}
docker compose down
docker compose up -d
```
## 🔧 Management & Maintenance
### View Logs
```bash theme={null}
# All services
docker compose logs -f
# Specific service
docker compose logs -f insforge
docker compose logs -f postgres
docker compose logs -f deno
```
### Stop Services
```bash theme={null}
docker compose down
```
### Restart Services
```bash theme={null}
docker compose restart
```
### Update InsForge
InsForge ships prebuilt images, so an update is a pull and restart. Run this from `~/insforge/deploy/docker-compose`:
```bash theme={null}
cd ~/insforge/deploy/docker-compose
git pull origin main
docker compose pull && docker compose up -d
```
### Backup Database
Run these from `~/insforge/deploy/docker-compose`:
```bash theme={null}
# Create backup
docker compose exec postgres pg_dump -U postgres insforge > backup_$(date +%Y%m%d_%H%M%S).sql
# Restore from backup
cat backup_file.sql | docker compose exec -T postgres psql -U postgres -d insforge
```
### Monitor Resources
```bash theme={null}
# Check disk usage
df -h
# Check memory usage
free -h
# Check Docker stats
docker stats
```
## 🐛 Troubleshooting
### Services Won't Start
```bash theme={null}
# Check logs for errors
docker compose logs
# Check disk space
df -h
# Check memory
free -h
# Restart Docker daemon
sudo systemctl restart docker
docker compose up -d
```
### Cannot Connect to Database
```bash theme={null}
# Check if PostgreSQL is running
docker compose ps postgres
# Check PostgreSQL logs
docker compose logs postgres
# Verify credentials in .env file
cat .env | grep POSTGRES
```
### Port Already in Use
```bash theme={null}
# Check what's using the port
sudo netstat -tulpn | grep :7130
# Kill the process or change port in docker-compose.yml
```
### Out of Memory
Consider upgrading to a larger instance type:
```text theme={null}
- Current: t3.medium (4 GB RAM)
- Upgrade to: t3.large (8 GB RAM)
```
### SSL Certificate Issues
```bash theme={null}
# Renew certificates
sudo certbot renew
# Test renewal
sudo certbot renew --dry-run
```
## 📊 Performance Optimization
### For Production Workloads
1. **Upgrade Instance Type**: Use `t3.large` or `t3.xlarge`
2. **Enable Auto-scaling**: Set up Application Load Balancer with auto-scaling groups
3. **Use RDS**: Migrate from containerized PostgreSQL to AWS RDS for better reliability
4. **Enable CloudWatch**: Monitor metrics and set up alarms
5. **Configure Backups**: Set up automated daily backups
6. **Use S3 for Storage**: Configure S3 bucket for file uploads instead of local storage
### Database Optimization
```conf theme={null}
# Increase PostgreSQL shared_buffers (edit postgresql.conf in deploy/docker-init/db/)
# Recommended: 25% of available RAM
shared_buffers = 1GB
effective_cache_size = 3GB
```
## 🔒 Security Best Practices
1. **Change Default Passwords**: Update admin and database passwords
2. **Enable Firewall**: Use AWS Security Groups effectively
3. **Regular Updates**: Keep system and Docker images updated
4. **SSL/TLS**: Always use HTTPS in production
5. **Backup Regularly**: Automate database backups
6. **Monitor Logs**: Set up log monitoring and alerts
7. **Limit SSH Access**: Restrict SSH to specific IP addresses
8. **Use IAM Roles**: Instead of AWS access keys where possible
## 🆘 Support & Resources
* **Documentation**: [https://docs.insforge.dev](https://docs.insforge.dev)
* **GitHub Issues**: [https://github.com/insforge/insforge/issues](https://github.com/insforge/insforge/issues)
* **Discord Community**: [https://discord.com/invite/MPxwj5xVvW](https://discord.com/invite/MPxwj5xVvW)
## 📝 Cost Estimation
**Monthly AWS Costs (approximate):**
| Component | Type | Monthly Cost |
| --------------- | ----------------- | ---------------- |
| EC2 Instance | t3.medium | \~\$30 |
| Storage (30 GB) | EBS gp3 | \~\$3 |
| Elastic IP | (if running 24/7) | \$0 |
| Data Transfer | First 100GB free | Variable |
| **Total** | | **\~\$33/month** |
> 💡 **Cost Optimization**: Use AWS Savings Plans or Reserved Instances for long-term deployments to save up to 70%.
***
**Congratulations! 🎉** Your InsForge instance is now running on AWS EC2. You can start building applications by connecting AI agents to your backend platform.
For other production deployment strategies, check out our [deployment guides](./README.md).
# Deploy to azure virtual machines
Source: https://docs.insforge.dev/deployment/deploy-to-azure-virtual-machines
# 📖 Deploying InsForge to Azure Virtual Machines (Extended Guide)
This guide provides comprehensive, step-by-step instructions for deploying, managing, and securing InsForge on an Azure Virtual Machine (VM) using Docker Compose.
This cloud walkthrough is community-maintained and can lag the latest InsForge release. The canonical, always-current setup is the `deploy/docker-compose/` directory in the [InsForge repo](https://github.com/InsForge/InsForge).
## Prerequisites
* An active **Azure account**.
* An **SSH client** to connect to the virtual machine.
* Basic familiarity with the **Linux command line**.
***
## Step 1: 🖥️ Create an Azure Virtual Machine
1. **Log in to the [Azure Portal](https://portal.azure.com/)** and navigate to **Virtual machines**.
2. Click **+ Create** > **Azure virtual machine**.
3. **Basics Tab:**
* **Resource Group:** Create a new one (e.g., `insforge-rg`).
* **Virtual machine name:** `insforge-vm`.
* **Image:** **Ubuntu Server 22.04 LTS** or newer.
* **Size:** `Standard_B2s` (2 vCPUs, 4 GiB memory) is a good start. For production, consider `Standard_B4ms` (4 vCPUs, 16 GiB memory).
* **Authentication type:** **SSH public key**.
* **SSH public key source:** **Generate new key pair**. Name it `insforge-key`.
4. **Networking Tab:**
* In the **Network security group** section, click **Create new**.
* Add the following **inbound port rules** to allow traffic:
* `22` (SSH)
* `80` (HTTP for Nginx)
* `443` (HTTPS for Nginx/SSL)
* `7130` (InsForge API and dashboard)
5. **Review and Create:**
* Click **Review + create**, then **Create**.
* When prompted, **Download private key and create resource**. Save the `.pem` file securely.
* Once deployed, find and copy your VM's **Public IP address**.
***
## Step 2: ⚙️ Connect and Set Up the Server
1. **Connect via SSH:**
Open your terminal, give your key the correct permissions, and connect to the VM.
```bash theme={null}
chmod 400 /path/to/your/insforge-key.pem
ssh -i /path/to/your/insforge-key.pem azureuser@
```
2. **Update System Packages:**
```bash theme={null}
sudo apt update && sudo apt upgrade -y
```
3. **Install Docker:**
Follow the official, up-to-date instructions on the Docker website to install Docker Engine on Ubuntu:
**[https://docs.docker.com/engine/install/ubuntu/](https://docs.docker.com/engine/install/ubuntu/)**
4. **Add Your User to the Docker Group:**
This step allows you to run Docker commands without `sudo`.
```bash theme={null}
# Add your user to the docker group
sudo usermod -aG docker $USER
# Apply the group changes
newgrp docker
```
Verify it works. This command should now run without `sudo`:
```bash theme={null}
docker ps
```
> 💡 **Note:** If `docker ps` doesn't work, log out of your SSH session and log back in, then try again.
>
> ⚠️ **Security Note:** Adding a user to the `docker` group grants them root-equivalent privileges. This is acceptable for a single-user VM but be cautious on shared systems.
5. **Install Git:**
```bash theme={null}
sudo apt install git -y
```
***
## Step 3: 🚀 Deploy InsForge
1. **Clone the Repository:**
Navigate to your home directory and clone the InsForge project.
```bash theme={null}
cd ~
git clone https://github.com/InsForge/InsForge.git
cd InsForge/deploy/docker-compose
```
2. **Create Environment Configuration:**
Create your `.env` file from the example and open it for editing.
```bash theme={null}
cp .env.example .env
nano .env
```
`.env.example` lists every supported variable with comments. For a basic deployment you only need to set a few. Set these values and update the API URLs to your VM's public IP:
```ini theme={null}
# Required
JWT_SECRET=your-secret-key-here-must-be-32-char-or-above
ROOT_ADMIN_USERNAME=admin
ROOT_ADMIN_PASSWORD=change-this-password
POSTGRES_PASSWORD=change-this-password
# API URLs (replace with your VM public IP or domain)
API_BASE_URL=http://:7130
VITE_API_BASE_URL=http://:7130
# Optional
# ENCRYPTION_KEY falls back to JWT_SECRET if left empty
ENCRYPTION_KEY=
# OPENROUTER_API_KEY=
# VERCEL_TOKEN=
# GOOGLE_CLIENT_ID=
```
The rest of `.env.example` covers optional features (OpenRouter, Vercel deployments, OAuth providers). Leave those blank unless you need them.
> **Generate a Secure JWT Secret:** Run this on your VM and paste the result into `JWT_SECRET`:
>
> ```bash theme={null}
> openssl rand -base64 32
> ```
3. **Start InsForge Services:**
Pull the Docker images and start all services in the background.
```bash theme={null}
docker compose up -d
```
4. **Verify Services:**
Check that all four containers are running.
```bash theme={null}
docker compose ps
```
You should see the `postgres`, `postgrest`, `insforge`, and `deno` services running.
***
## Step 4: 🔑 Access Your InsForge Instance
1. **Test Backend API:**
Use `curl` to check the health endpoint.
```bash theme={null}
curl http://:7130/api/health
```
You should see a response like: `{"status":"ok", ...}`
2. **Access Dashboard:**
Open your browser and navigate to: `http://:7130`
Log in with the `ROOT_ADMIN_USERNAME` and `ROOT_ADMIN_PASSWORD` you set in your `.env` file.
***
## Step 5: 🌐 Configure Domain (Optional but Recommended)
1. **Update DNS Records:**
In your domain provider's DNS settings, add two **A records** pointing to your VM's Public IP address:
* `api.yourdomain.com` → ``
* `app.yourdomain.com` → ``
2. **Install and Configure Nginx as a Reverse Proxy:**
```bash theme={null}
sudo apt install nginx -y
sudo nano /etc/nginx/sites-available/insforge
```
Paste the following configuration:
```nginx theme={null}
# Backend API
server {
listen 80;
server_name api.yourdomain.com;
location / {
proxy_pass http://localhost:7130;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Frontend Dashboard (served by the same port as the API)
server {
listen 80;
server_name app.yourdomain.com;
location / {
proxy_pass http://localhost:7130;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
}
}
```
Enable the configuration and reload Nginx:
```bash theme={null}
sudo ln -s /etc/nginx/sites-available/insforge /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
3. **Install SSL Certificate with Certbot:**
```bash theme={null}
# Install Certbot for Nginx
sudo apt install certbot python3-certbot-nginx -y
# Obtain SSL certificates and configure Nginx automatically
sudo certbot --nginx -d api.yourdomain.com -d app.yourdomain.com
```
Follow the prompts. Certbot will handle the rest.
4. **Update `.env` with HTTPS URLs:**
Edit your `.env` file and update the URLs.
```bash theme={null}
cd ~/InsForge
nano .env
```
Change the URLs to `https`:
```ini theme={null}
API_BASE_URL=https://api.yourdomain.com
VITE_API_BASE_URL=https://api.yourdomain.com
```
Restart the services for the changes to take effect:
```bash theme={null}
docker compose down && docker compose up -d
```
***
## 🔧 Management & Maintenance
* **View Logs:** `docker compose logs -f` (all services) or `docker compose logs -f insforge` (specific service).
* **Stop Services:** `docker compose down`
* **Restart Services:** `docker compose restart`
* **Update InsForge:** Run these from `~/InsForge/deploy/docker-compose`. The images are prebuilt, so pull the latest tags instead of rebuilding.
```bash theme={null}
cd ~/InsForge/deploy/docker-compose
git -C ~/InsForge pull origin main
docker compose pull && docker compose up -d
```
* **Backup Database:** Run from `~/InsForge/deploy/docker-compose`.
```bash theme={null}
docker compose exec postgres pg_dump -U postgres insforge > backup_$(date +%Y%m%d_%H%M%S).sql
```
## 🐛 Troubleshooting
* **Services Won't Start:** Check `docker compose logs` for errors. Ensure you have enough disk space (`df -h`) and memory (`free -h`).
* **Port Already in Use:** Check which process is using the port with `sudo netstat -tulpn | grep :7130`.
* **Out of Memory:** Consider upgrading your Azure VM to a size with more RAM.
## 📊 Cost Estimation
> **Disclaimer:** Prices are estimates based on Pay-As-You-Go rates in a common region (e.g., East US) and can vary. Always check the official [Azure Pricing Calculator](https://azure.microsoft.com/en-us/pricing/calculator/) for the most accurate information. On Azure, you pay for the VM's resources (CPU, RAM, Storage), which are shared by all the Docker services you run on it.
### Free Tier (for Testing)
* **Cost:** **\~\$0/month** for the first 12 months.
* **Resources:** Azure provides a free tier that includes 750 hours/month of a `B1s` burstable VM.
* **Limitations:** This VM has very limited resources (1 vCPU, 1 GiB RAM) and may run slowly. It's suitable only for basic testing and familiarization, not for active development or production.
### Starter Setup (for Development & Small Projects)
* **Cost:** **\~$30 - $40/month**
* **Resources:** This estimate is for a `Standard_B2s` VM (2 vCPU, 4 GiB RAM) running all the InsForge Docker containers.
* **Breakdown:** The cost primarily consists of the VM compute hours. It also includes the OS disk storage and a static public IP address. This single VM runs your database, backend, Deno, and all other services.
### Production Setup (for Scalability & Reliability)
For production, you can choose between an all-in-one, larger VM or a more robust setup using managed services.
* **Option A: All-in-One Larger VM**
* **Cost:** **\~$150 - $170/month**
* **Resources:** A more powerful `Standard_B4ms` VM (4 vCPU, 16 GiB RAM) to handle higher traffic and all services.
* **Pros:** Simple to manage, consolidated cost.
* **Cons:** Database and application share resources, which can create performance bottlenecks. Scaling requires upgrading the entire VM.
* **Option B: Managed Services (Recommended for Production)**
* **Cost:** **\~\$120+/month** (highly variable)
* **Resources:**
* **Application VM:** A `Standard_B2s` VM for the app services (InsForge, PostgREST, Deno). `(~$30/month)`
* **Managed Database:** Use **Azure Database for PostgreSQL** for reliability, automated backups, and scaling. `(~$40+/month for a starter tier)`
* **Pros:** Highly reliable and scalable. Database performance is isolated and guaranteed. Managed backups and security.
* **Cons:** More complex setup, costs are distributed across multiple services.
## 🔒 Security Best Practices
* **Change Default Passwords:** Always update admin and database passwords.
* **Enable Firewall:** Use Azure **Network Security Groups (NSGs)** to restrict access to necessary ports and IP addresses.
* **Regular Updates:** Periodically run `sudo apt update && sudo apt upgrade -y` and update InsForge.
* **Backup Regularly:** Automate database and configuration backups.
# Deploy to google cloud compute engine
Source: https://docs.insforge.dev/deployment/deploy-to-google-cloud-compute-engine
# Deploy InsForge to Google Cloud Compute Engine
This guide will walk you through deploying InsForge on Google Cloud Compute Engine using Docker Compose.
This cloud walkthrough is community-maintained and can lag the latest InsForge release. The canonical, always-current setup is the `deploy/docker-compose/` directory in the [InsForge repo](https://github.com/InsForge/InsForge).
## 📋 Prerequisites
* Google Cloud Account with billing enabled
* Basic knowledge of SSH and command-line operations
* Domain name (optional, for custom domain setup)
## 🚀 Deployment Steps
### 1. Create and Configure Compute Engine Instance
#### 1.1 Create Google Cloud Project
1. **Log into Google Cloud Console** at [console.cloud.google.com](https://console.cloud.google.com)
2. **Click "Select a project"** in the top navigation bar
3. **Click "New Project"**
4. **Enter project name** (e.g., `insforge-deployment`)
5. **Click "Create"**
6. **Wait for project creation to complete**
#### 1.2 Enable Required APIs
1. In your project, navigate to **APIs & Services** → **Library**
2. Search for and enable these APIs:
* **Compute Engine API**
* **Cloud Storage API** (if using for backups)
* **Cloud SQL Admin API** (if using Cloud SQL)
#### 1.3 Create Compute Engine Instance
1. Navigate to **Compute Engine** → **VM instances**
2. Click **"Create Instance"**
3. Configure your instance:
* **Name**: `insforge-server` (or your preferred name)
* **Region**: Choose a region close to your users
* **Zone**: Select an availability zone (e.g., us-central1-a)
* **Machine configuration**:
* **Series**: N2 or E2
* **Machine type**: `e2-medium` or larger (minimum 2 vCPU, 4 GB RAM)
* For production: `e2-standard-2` (2 vCPU, 8 GB RAM) recommended
* For testing: `e2-small` (2 vCPU, 2 GB RAM) minimum
* **Boot disk**:
* **Operating system**: Ubuntu LTS (Ubuntu 22.04 LTS or newer)
* **Boot disk type**: Balanced persistent disk
* **Size**: 30 GB (minimum 20 GB recommended)
* **Firewall**:
* Allow HTTP traffic: **Checked**
* Allow HTTPS traffic: **Checked**
#### 1.4 Configure Firewall Rules
1. Navigate to **VPC network** → **Firewall**
2. Create or modify firewall rules to allow the following ports:
| Name | Direction | Targets | Protocols/ports | Source filters |
| ------------------ | --------- | --------------- | --------------- | ------------------------------------- |
| insforge-ssh | Ingress | insforge-server | tcp:22 | Your IP address |
| insforge-http | Ingress | insforge-server | tcp:80 | 0.0.0.0/0 |
| insforge-https | Ingress | insforge-server | tcp:443 | 0.0.0.0/0 |
| insforge-app | Ingress | insforge-server | tcp:7130 | 0.0.0.0/0 |
| insforge-deno | Ingress | insforge-server | tcp:7133 | 0.0.0.0/0 |
| insforge-postgrest | Ingress | insforge-server | tcp:5430 | 0.0.0.0/0 |
| insforge-postgres | Ingress | insforge-server | tcp:5432 | 0.0.0.0/0 (only if needed externally) |
> ⚠️ **Security Note**: For production, restrict PostgreSQL (5432) to specific IP addresses or remove external access entirely. Consider using a reverse proxy (nginx) and exposing only ports 80/443.
### 2. Connect to Your Compute Engine Instance
1. In the Google Cloud Console, go to **Compute Engine** → **VM instances**
2. Find your instance and click the **SSH** button in the same row, or:
```bash theme={null}
# Use gcloud CLI to SSH (if you have gcloud SDK installed locally)
gcloud compute ssh insforge-server --zone=your-zone
```
### 3. Install Dependencies
#### 3.1 Update System Packages
```bash theme={null}
sudo apt update && sudo apt upgrade -y
```
#### 3.2 Install Docker
```bash theme={null}
# Add Docker's official GPG key
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add Docker repository
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```
#### 3.3 Add Your User to Docker Group
After installing Docker, you need to add your user to the `docker` group to run Docker commands without `sudo`:
```bash theme={null}
# Add your user to the docker group
sudo usermod -aG docker $USER
# Apply the group changes
newgrp docker
```
**Verify it works:**
```bash theme={null}
# This should now work without sudo
docker ps
```
> 💡 **Note**: If `docker ps` doesn't work immediately, log out and log back in via SSH, then try again.
> ⚠️ **Security Note**: Adding a user to the `docker` group grants them root-equivalent privileges on the system. This is acceptable for single-user environments like your Compute Engine instance, but be cautious on shared systems.
#### 3.4 Install Git
```bash theme={null}
sudo apt install git -y
```
### 4. Deploy InsForge
#### 4.1 Clone Repository
```bash theme={null}
cd ~
git clone https://github.com/insforge/insforge.git
cd insforge/deploy/docker-compose
```
#### 4.2 Create Environment Configuration
Create your `.env` file with production settings:
```bash theme={null}
nano .env
```
The repo ships a template at `deploy/docker-compose/.env.example`. Copy it and edit the values:
```bash theme={null}
cp .env.example .env
nano .env
```
At a minimum, set these values:
```env theme={null}
# Authentication (required)
# IMPORTANT: Generate a strong random secret for production (32+ characters)
JWT_SECRET=your-secret-key-here-must-be-32-char-or-above
# Admin account (used for initial setup)
ROOT_ADMIN_USERNAME=admin
ROOT_ADMIN_PASSWORD=change-this-password
# Database (required)
POSTGRES_PASSWORD=your-secure-postgres-password
```
Optional values you may want to set:
```env theme={null}
# Encryption key for secrets and database encryption.
# Falls back to JWT_SECRET if left empty.
ENCRYPTION_KEY=
# AI/LLM (get a key from https://openrouter.ai/keys)
OPENROUTER_API_KEY=
# Site deployments and custom domains
VERCEL_TOKEN=
VERCEL_TEAM_ID=
VERCEL_PROJECT_ID=
# OAuth providers (Google, GitHub, etc.)
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
```
See `deploy/docker-compose/.env.example` for the full list of supported variables.
**Generate Secure Secrets:**
```bash theme={null}
# Generate JWT_SECRET (32+ characters)
openssl rand -base64 32
# Generate ENCRYPTION_KEY (32 characters)
openssl rand -base64 24
```
> 💡 **Important**: Save these secrets securely. You'll need them if you ever migrate or restore your instance.
#### 4.3 Start InsForge Services
```bash theme={null}
# Pull Docker images and start services
docker compose up -d
# View logs to ensure everything started correctly
docker compose logs -f
```
Press `Ctrl+C` to exit log view.
#### 4.4 Verify Services
```bash theme={null}
# Check running containers
docker compose ps
# You should see 4 running services:
# - postgres
# - postgrest
# - insforge
# - deno
```
### 5. Access Your InsForge Instance
#### 5.1 Test Backend API
```bash theme={null}
curl http://your-external-ip:7130/api/health
```
Expected response:
```json theme={null}
{
"status": "ok",
"version": "2.1.7",
"service": "Insforge OSS Backend",
"timestamp": "2025-10-17T..."
}
```
#### 5.2 Access Dashboard
Open your browser and navigate to:
```text theme={null}
http://your-external-ip:7130
```
### 6. Configure Domain (Optional but Recommended)
#### 6.1 Reserve a Static External IP
1. In Google Cloud Console, go to **VPC network** → **External IP addresses**
2. Click **Reserve Static Address**
3. **Name**: `insforge-ip`
4. **Type**: Regional or Global (Regional for VM instances)
5. **Region**: Same as your VM instance
6. **Click Reserve**
#### 6.2 Update DNS Records
Point your domain's DNS records to the reserved static IP:
```text theme={null}
api.yourdomain.com → your-static-external-ip
app.yourdomain.com → your-static-external-ip
```
#### 6.3 Install Nginx Reverse Proxy
```bash theme={null}
sudo apt install nginx -y
```
Create Nginx configuration:
```bash theme={null}
sudo nano /etc/nginx/sites-available/insforge
```
Add the following configuration:
```nginx theme={null}
# Backend API
server {
listen 80;
server_name api.yourdomain.com;
location / {
proxy_pass http://localhost:7130;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
# Dashboard
server {
listen 80;
server_name app.yourdomain.com;
location / {
proxy_pass http://localhost:7130;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
```
Enable the configuration:
```bash theme={null}
sudo ln -s /etc/nginx/sites-available/insforge /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
#### 6.4 Install SSL Certificate (Recommended)
```bash theme={null}
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Obtain SSL certificates
sudo certbot --nginx -d api.yourdomain.com -d app.yourdomain.com
# Follow the prompts to complete setup
```
Update your `.env` file with HTTPS URLs:
```bash theme={null}
cd ~/insforge/deploy/docker-compose
nano .env
```
Change:
```env theme={null}
API_BASE_URL=https://api.yourdomain.com
VITE_API_BASE_URL=https://api.yourdomain.com
```
Restart services:
```bash theme={null}
docker compose down
docker compose up -d
```
## 🔧 Management & Maintenance
### View Logs
```bash theme={null}
# All services
docker compose logs -f
# Specific service
docker compose logs -f insforge
docker compose logs -f postgres
docker compose logs -f deno
```
### Stop Services
```bash theme={null}
docker compose down
```
### Restart Services
```bash theme={null}
docker compose restart
```
### Update InsForge
```bash theme={null}
cd ~/insforge/deploy/docker-compose
git pull origin main
docker compose pull && docker compose up -d
```
### Backup Database
```bash theme={null}
# Create backup (run from deploy/docker-compose/)
docker compose exec postgres pg_dump -U postgres insforge > backup_$(date +%Y%m%d_%H%M%S).sql
# Store backup in Google Cloud Storage (optional)
# First, install Google Cloud CLI and authenticate
# Then:
gsutil cp backup_$(date +%Y%m%d_%H%M%S).sql gs://your-backup-bucket/
```
### Monitor Resources
```bash theme={null}
# Check disk usage
df -h
# Check memory usage
free -h
# Check Docker stats
docker stats
```
## 🐛 Troubleshooting
### Services Won't Start
```bash theme={null}
# Check logs for errors
docker compose logs
# Check disk space
df -h
# Check memory
free -h
# Restart Docker daemon
sudo systemctl restart docker
docker compose up -d
```
### Cannot Connect to Database
```bash theme={null}
# Check if PostgreSQL is running
docker compose ps postgres
# Check PostgreSQL logs
docker compose logs postgres
# Verify credentials in .env file
cat .env | grep POSTGRES
```
### Port Already in Use
```bash theme={null}
# Check what's using the port
sudo netstat -tulpn | grep :7130
# Kill the process or change port in docker-compose.yml
```
### Out of Memory
Consider upgrading to a larger instance type:
```text theme={null}
- Current: e2-small (2 vCPU, 2 GB RAM)
- Upgrade to: e2-standard-2 (2 vCPU, 8 GB RAM)
```
### SSL Certificate Issues
```bash theme={null}
# Renew certificates
sudo certbot renew
# Test renewal
sudo certbot renew --dry-run
```
## 📊 Performance Optimization
### For Production Workloads
1. **Upgrade Instance Type**: Use `e2-standard-2` or `e2-standard-4`
2. **Use Cloud SQL**: Migrate from containerized PostgreSQL to Google Cloud SQL for better reliability
3. **Enable Cloud Monitoring**: Monitor metrics and set up alerts
4. **Configure Backups**: Set up automated daily backups
5. **Use Cloud Storage**: Configure Google Cloud Storage for file uploads instead of local storage
### Database Optimization
```conf theme={null}
# Increase PostgreSQL shared_buffers (edit postgresql.conf in deploy/docker-init/db/)
# Recommended: 25% of available RAM
shared_buffers = 1GB
effective_cache_size = 3GB
```
## 🔒 Security Best Practices
1. **Change Default Passwords**: Update admin and database passwords
2. **Enable Firewall**: Use Google Cloud Firewall rules effectively
3. **Regular Updates**: Keep system and Docker images updated
4. **SSL/TLS**: Always use HTTPS in production
5. **Backup Regularly**: Automate database backups
6. **Monitor Logs**: Set up log monitoring and alerts
7. **Limit SSH Access**: Restrict SSH to specific IP addresses
8. **Use Service Accounts**: Instead of API keys where possible
## 🆘 Support & Resources
* **Documentation**: [https://docs.insforge.dev](https://docs.insforge.dev)
* **GitHub Issues**: [https://github.com/insforge/insforge/issues](https://github.com/insforge/insforge/issues)
* **Discord Community**: [https://discord.com/invite/MPxwj5xVvW](https://discord.com/invite/MPxwj5xVvW)
## 📝 Cost Estimation
**Monthly Google Cloud Costs (approximate):**
| Component | Type | Monthly Cost |
| ----------------------- | ---------------------------- | ---------------- |
| Compute Engine | e2-medium (2 vCPU, 4 GB RAM) | \~\$29 |
| Persistent Disk (30 GB) | Standard | \~\$3 |
| Network Egress | First 1GB free | Variable |
| **Total** | | **\~\$32/month** |
> 💡 **Cost Optimization**: Use sustained use discounts for 24/7 running instances to save up to 30%. Consider preemptible instances for development/testing environments.
***
**Congratulations! 🎉** Your InsForge instance is now running on Google Cloud Compute Engine. You can start building applications by connecting AI agents to your backend platform.
For other production deployment strategies, check out our [deployment guides](./README.md).
# Deployment security guide
Source: https://docs.insforge.dev/deployment/deployment-security-guide
# Deployment & Security Guide for VPS Installation
This comprehensive guide covers deploying InsForge on a generic VPS (Virtual Private Server) for production, hardening your instance with security best practices, and maintaining it over time with safe updates and rollback procedures.
> **Scope**: This guide is provider-agnostic. It works on any Linux VPS — Ubuntu/Debian recommended — from providers such as DigitalOcean, Hetzner, Linode, Vultr, OVH, or a bare-metal server. For cloud-specific guides (AWS EC2, GCP, Azure, Render), see the [deployment directory](./README.md).
***
## 📋 Table of Contents
* [Prerequisites](#prerequisites)
* [Part 1 — Deployment](#part-1--deployment)
* [Server Requirements](#1-server-requirements)
* [Initial Server Setup](#2-initial-server-setup)
* [Install Docker & Docker Compose](#3-install-docker--docker-compose)
* [Deploy InsForge with Docker Compose](#4-deploy-insforge-with-docker-compose)
* [Environment Variable Configuration](#5-environment-variable-configuration)
* [Reverse Proxy Setup](#6-reverse-proxy-setup)
* [HTTPS / TLS Setup](#7-https--tls-setup)
* [Part 2 — Security](#part-2--security)
* [Port Management](#8-port-management)
* [Firewall Setup (UFW)](#9-firewall-setup-ufw)
* [Run Services as a Non-Root User](#10-run-services-as-a-non-root-user)
* [SSH Hardening](#11-ssh-hardening)
* [Docker Security](#12-docker-security)
* [Secrets Management](#13-secrets-management)
* [Part 3 — Updating & Maintenance](#part-3--updating--maintenance)
* [Pre-Update Backup](#14-pre-update-backup)
* [Updating InsForge](#15-updating-insforge)
* [Rollback Procedure](#16-rollback-procedure)
* [Automated Backups](#17-automated-backups)
* [Monitoring & Health Checks](#18-monitoring--health-checks)
* [Quick Reference](#quick-reference)
* [Troubleshooting](#troubleshooting)
***
## Prerequisites
Before starting, ensure you have:
* A VPS running **Ubuntu 22.04 LTS** or **Ubuntu 24.04 LTS** (Debian 12 also works)
* **Root or sudo access** to the server
* A registered **domain name** (recommended for production)
* Basic familiarity with the Linux command line and SSH
***
## Part 1 — Deployment
### 1. Server Requirements
| Resource | Minimum | Recommended |
| ----------- | ------------- | ------------------ |
| **CPU** | 2 vCPU | 4 vCPU |
| **RAM** | 2 GB | 4 GB+ |
| **Storage** | 20 GB SSD | 40 GB+ SSD |
| **OS** | Ubuntu 22.04+ | Ubuntu 24.04 LTS |
| **Network** | Public IPv4 | Public IPv4 + IPv6 |
> 💡 **Tip**: For production workloads with multiple users, start with 4 GB RAM. Monitor usage with `docker stats` and scale vertically as needed.
InsForge consists of **4 services** that run together:
| Service | Description | Internal Port |
| -------------- | ----------------------------- | --------------------- |
| **PostgreSQL** | Primary database | 5432 |
| **PostgREST** | Auto-generated REST API layer | 3000 (mapped to 5430) |
| **InsForge** | Node.js backend + dashboard | 7130 |
| **Deno** | Serverless functions runtime | 7133 |
***
### 2. Initial Server Setup
#### 2.1 Connect to Your VPS
```bash theme={null}
ssh root@your-server-ip
```
#### 2.2 Update System Packages
```bash theme={null}
apt update && apt upgrade -y
```
#### 2.3 Create a Deploy User (Non-Root)
Never run production services as root. Create a dedicated user:
```bash theme={null}
# Create the deploy user and add to sudo group
adduser deploy
usermod -aG sudo deploy
# Switch to the deploy user
su - deploy
```
#### 2.4 Set the Timezone
```bash theme={null}
sudo timedatectl set-timezone UTC
```
#### 2.5 Enable Automatic Security Updates
```bash theme={null}
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades
```
***
### 3. Install Docker & Docker Compose
#### 3.1 Install Docker Engine
```bash theme={null}
# Add Docker's official GPG key
sudo apt install ca-certificates curl gnupg -y
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the Docker repository
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
```
#### 3.2 Add Deploy User to the Docker Group
```bash theme={null}
sudo usermod -aG docker deploy
newgrp docker
```
#### 3.3 Verify Docker Installation
```bash theme={null}
docker --version
docker compose version
docker run hello-world
```
> ⚠️ **Security Note**: Adding a user to the `docker` group grants root-equivalent privileges on the host. This is acceptable for a dedicated deploy user but should not be done for general-purpose accounts on shared servers.
***
### 4. Deploy InsForge with Docker Compose
#### 4.1 Download the Production Docker Compose File
```bash theme={null}
mkdir -p ~/insforge && cd ~/insforge
# Download the production-ready Docker Compose file and environment template
wget https://raw.githubusercontent.com/insforge/insforge/main/deploy/docker-compose/docker-compose.yml
wget https://raw.githubusercontent.com/insforge/insforge/main/deploy/docker-compose/.env.example
# Create your environment file
cp .env.example .env
```
#### 4.2 Start InsForge
```bash theme={null}
docker compose up -d
```
#### 4.3 Verify All Services Are Running
```bash theme={null}
docker compose ps
```
You should see 4 containers in a `running` or `healthy` state:
```text theme={null}
NAME SERVICE STATUS
insforge insforge running
postgres postgres healthy
postgrest postgrest healthy
deno deno running
```
#### 4.4 Test the Health Endpoint
```bash theme={null}
curl http://localhost:7130/api/health
```
Expected response:
```json theme={null}
{
"status": "ok",
"version": "1.x.x",
"service": "Insforge OSS Backend",
"timestamp": "2026-..."
}
```
***
### 5. Environment Variable Configuration
Edit your `.env` file to configure InsForge for production:
```bash theme={null}
nano ~/insforge/.env
```
#### 5.1 Required Variables
These **must** be changed from defaults before going to production:
```env theme={null}
# ── Security (CRITICAL — generate unique values) ──────────────
JWT_SECRET=