Skip to main content
Guides

Building & publishing APIs

Create an API, generate endpoints from your tables or define custom ones, configure them, and publish.

RestWard automatically generates REST API endpoints from your database tables and queries. You can also create custom endpoints with specific configurations.

Understanding APIs and endpoints

An API is a collection of related endpoints that your consumers can call. An endpoint is a single REST route (like GET /users/{id}) that maps to a database table or query.

  • Each API has a slug (e.g., my-api) that identifies it. Its tables are served on the API's endpoint at /api/<schema>/<table>, for example /api/public/users
  • Each endpoint has a method (GET, POST, PUT, DELETE), a path, and configuration for authentication and rate limiting

Creating a new API

To set up a new API:

  1. Open the APIs page (from API Explorer, click All APIs), then click New API
  2. Under Basic Information, enter the API Name (display name for your reference)
  3. Enter the Slug (lowercase, URL-safe identifier)
  4. Under Database Connection, use the Select Connection dropdown to choose a database connection
  5. Once a connection is selected, a Database Selection panel appears. Click Refresh to browse the databases on that connection, then search for and select the database you want
  6. Under Configuration, choose a Scaling Tier:
    • Cold - scales to zero when idle (most cost-effective)
    • Warm - keeps at least 1 replica running
    • Hot - keeps 2 or more replicas running
  7. (Optional) Enter Included Schemas - a comma-separated list of schemas to expose (e.g., public, dbo)
  8. (Optional) Under the schemas, use the Exclude tables picker to check the tables that must stay out of the API. The picker lists the real tables of the included schemas; checked tables get no endpoints, are never routed by the running API, and are left out of the OpenAPI document
  9. Click Create API

Your API is now created. RestWard generates a default endpoint for each table: GET /table-name, POST /table-name, etc.

Generating endpoints from tables

How endpoint settings reach live traffic. Until you Re-generate endpoints, the running API serves every table (not views) in its included schemas that the connection's database user can see, at /api/<schema>/<table>, with the organization's enabled authentication methods and each API key's own rate limit. Once endpoints are generated, the Endpoints list is authoritative: only enabled endpoints are served, and each one's authentication type, rate limit and cache TTL apply. Endpoint settings, new or changed custom paths, and edits to the API's exclude list apply within one refresh interval (about 30 seconds by default), while the platform is reachable. Exclusions remove both table routes and custom routes onto those tables, along with their paths in both OpenAPI documents. During a platform outage the runtime keeps its last good route table; exclusion changes take effect after refreshing succeeds. Schema changes apply after Refresh now, restward api refresh, a generated table-set change, or the opt-in automatic schema refresh interval. Automatic refresh is off by default.

Choosing which tables are exposed

Every table in the included schemas becomes an endpoint unless you exclude it:

  • On create: the New API form has an Exclude tables picker under Included Schemas. It lists the real tables of the schemas you entered; check the ones to leave out.
  • On an existing API: open the API's page and click Edit API — the same picker, pre-checked with the tables already excluded. Saving stores the full list (uncheck everything to expose all tables again), together with the API name and scaling tier.

Exclusion matches by table name (case-insensitive): if two included schemas contain a table with the same name, excluding that name excludes both. Excluded tables keep working for your own applications — they are simply not part of the generated API.

When you create an API, RestWard automatically generates endpoints for all selected tables. Each endpoint includes:

  • A path based on the table name (e.g., /users, /orders)
  • HTTP methods: GET (list/retrieve), POST (create), PUT (update), DELETE (delete)
  • Default authentication (API Key)
  • Default rate limit (100 requests per minute)
  • No caching (0 seconds TTL)

To regenerate endpoints after schema changes:

  1. Go to Endpoints
  2. Click Re-generate at the top
  3. Select the API Configuration to regenerate
  4. Click Re-generate again

This adds endpoints for new tables and updates existing ones. Custom endpoints are preserved (not deleted).

Creating custom endpoints

To create an endpoint manually:

  1. Go to Endpoints
  2. Click Custom Endpoint
  3. Select the API Configuration (required)
  4. Choose the HTTP Method (GET, POST, PUT, DELETE)
  5. Enter the Path (e.g., /v1/custom or /users/{id})
  6. Select the Database Connection
  7. Select the Source Table (the list loads automatically once a connection is chosen)
  8. Configure:
    • Rate Limit (/min) - requests allowed per minute (e.g., 100)
    • Cache TTL (seconds) - how long to cache the response (0 = no cache)
    • Auth - authentication type (ApiKey, Jwt, Mtls, Public)
  9. Click Create Endpoint

A custom endpoint is an extra route onto an operation of its source table, chosen by the method (paths under /docs, /openapi.json, /openapi-enhanced.json, /health, /alive and /metrics are reserved by the API and refused; so are paths that start with a route parameter, such as /{id}/items, and catch-all parameters such as /{*rest}, because they can match a reserved path):

Method Path Does
GET without {id} list rows (with the usual limit, offset, sort and filters)
GET with {id} read one row by primary key
POST without {id} create a row
PUT with {id} update the columns sent
PATCH with {id} update the columns sent, strictly validated
DELETE with {id} delete a row

Generated tables also accept PATCH on <table>/{id}: without its own endpoint row it follows the PUT endpoint's settings (enabled, authentication, rate limit), so disabling PUT disables PATCH too.

The only route parameter allowed is {id}. A custom endpoint whose method and path match a generated endpoint is not added as a second route (use the generated endpoint's settings instead). New, changed and deleted custom endpoints apply within one refresh interval (about 30 seconds by default) while the platform is reachable, including their paths in both OpenAPI documents. Their settings (enable/disable, auth, rate limit, cache) follow the same interval.

Editing an endpoint

To modify an endpoint:

  1. Go to Endpoints
  2. Hover over the endpoint row and click Edit (pencil icon)
  3. Modify any field:
    • Method - HTTP verb
    • Path - route path
    • Source Table - database table (can be any valid table name)
    • Description - optional notes
    • Rate Limit - requests per minute
    • Cache TTL - response caching duration
    • Auth - authentication method
  4. Click Save Changes

Understanding endpoint configuration

Authentication types

  • ApiKey - Consumer includes the API key in the X-API-Key header
  • Jwt - Consumer includes a JWT token in the Authorization header
  • Mtls - Consumer presents a client certificate
  • Public - Endpoint requires no authentication (not recommended for sensitive data; a Public write endpoint lets anyone write)

ApiKey, Jwt and Mtls endpoints accept only that method, and the method must also be enabled for your organization under Auth & Keys; otherwise requests get 401.

Rate limiting

Rate limits control how many requests each consumer can make to the endpoint per minute: every API key, JWT subject or client certificate (or client IP address on Public endpoints) has its own count. Set to 0 for no endpoint limit. The caller's own quota (API key, JWT subject or client certificate) applies as well, so the stricter limit wins. Over the limit, requests get 429 with Retry-After set to the seconds left in the window; the X-RateLimit-* headers show the limit closest to running out.

Caching

Cache TTL (Time To Live) stores responses for the specified seconds. For example:

  • 0 seconds = no caching (live data on every request)
  • 60 seconds = response cached for 1 minute
  • 3600 seconds = response cached for 1 hour

Caching applies to GET endpoints. Responses are cached per consumer and per URL (including the query string); a successful write through the API to the same table clears that table's cached responses at once, but changes made directly in the database appear only after the TTL. Responses carry X-Cache: HIT or MISS. Generated read endpoints start with a 30-second TTL; set it to 0 for data that must always be live.

Disabling or deleting endpoints

To remove an endpoint:

  1. Go to Endpoints
  2. Hover over the row and click Delete (trash icon)
  3. Confirm deletion

Requests to a deleted endpoint get 404, as do requests to a disabled one. Deleted endpoints cannot be recovered, but Re-generate recreates the generated ones (with default settings). A table whose write endpoints (POST, PUT, DELETE) are deleted or disabled is read-only.

Publishing your API

Your API is live once it is provisioned. Its base URL is the API's endpoint, shown on the API in the dashboard (and by restward list), and each table is served under it:

Text
<endpoint>/api/<schema>/<table>

For example, the users table in the public schema of an API at https://YOUR-API-HOSTNAME is https://YOUR-API-HOSTNAME/api/public/users. The API's OpenAPI document is at <endpoint>/openapi.json. See the Quick Start for a first request.

To let consumers authenticate their requests, issue keys for this API on the API keys & tenant API auth page.

Your API's hostname

Every API is served at a hostname of its own, shown as the API's endpoint on its detail page: https://{api}-{org}-{hash}.run.restward.tech, for example https://chinook-test-org-vzubqp.run.restward.tech. {api} and {org} are the API and organization slugs, and {hash} is six characters derived from your organization. When the whole label would be longer than 63 characters, the slugs are shortened (the organization slug first); the hash is never shortened. The hostname is fixed when the API is created, so renaming your organization does not change it.

The docs write it as https://YOUR-API-HOSTNAME; use your API's endpoint instead. The older shared host https://run.restward.tech serves no new APIs. For an API that was moved from it, it only answers with a 308 Permanent Redirect to the same path on the API's own hostname.

Use the endpoint from the dashboard as your base URL (set RESTWARD_API_URL or wherever your client keeps it) and do not depend on the redirect:

  • A client that follows the redirect sends its X-API-Key or Authorization header a second time, through an extra hop, on every request.
  • Many HTTP clients do not follow redirects for POST, PUT or DELETE, or drop the credentials when they do, so writes can fail where reads still work.
  • The redirect is a migration aid, not part of the API contract; the shared host can stop serving your API later.

Client certificates (mTLS) and API keys stay valid on the new hostname: only the base URL changes.

Troubleshooting

"No tables found" when selecting a database connection

  • Verify the connection is working by going to Connections and clicking Test
  • Click Sync on the connection to refresh the table list
  • Ensure your database user has permission to list tables

Custom endpoint returns 404

  • Allow one refresh interval (about 30 seconds by default) while the platform is reachable for a new custom endpoint to appear
  • Verify the Path is spelled correctly, uses {id} as its only parameter, and the method fits the path (see the table under Creating custom endpoints)
  • Ensure the Source Table is part of the API
  • Check that the endpoint is enabled and has not been deleted

Rate limiting or caching not working

  • Verify the endpoint's Rate Limit setting is not 0 (which means unlimited)
  • Verify Cache TTL is greater than 0 for caching to apply
  • Test the endpoint in API Explorer to see live behavior

Regenerate reset my endpoint settings

Re-generate replaces all generated endpoints with fresh ones using the default settings (including re-enabling any you had disabled). Custom endpoints are kept. Re-apply your changes to the generated endpoints afterwards.

Refreshing database schema

Automatic schema re-reflection is off by default for each API. In Edit API, enable Automatically refresh database schema and choose an interval from 1 to 1440 minutes (30 minutes is the suggested interval). This reads database catalogs on a schedule and applies changed tables and columns without restarting the runtime. Turning it off retains the last good schema until an explicit refresh or Generate Endpoints changes the generated table set.

Use Refresh now for a one-time re-read, or call:

HTTP
POST /api/v1/organizations/{orgId}/apis/{apiId}/refresh
Authorization: Bearer <platform-access-token>

A current Contributor, Administrator, or SystemAdmin can refresh an active API. The response is 202 Accepted with a Location pointing to API detail and a requestVersion. Poll that detail until refreshCompletedVersion >= requestVersion; lastRefreshRequestedAt, lastRefreshCompletedAt, and routeGeneration show progress. Acceptance means queued, not yet live. The runtime pulls the marker on its next poll (normally 30 seconds) and acknowledges only after a full reflected schema and route generation are published. Reflection has a 60-second timeout by default (SchemaRefresh:TimeoutSeconds, 1–300 seconds); failures retain the last good generation and retry on subsequent polls.

Triggers use a 60-second pending-request debounce (SchemaRefresh:DebounceSeconds on the control plane). Calls before reflection starts share a marker; calls during reflection queue another read, and calls after completion always request a new read. The trigger is limited to 10 requests per minute per caller and organization. It uses platform bearer-token authentication, including CLI RESTWARD_TOKEN; tenant API keys authenticate data-plane traffic only.

For continuous delivery:

Shell
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f migration.sql
restward api refresh orders --wait --timeout 180

For a newly added table, first generate and enable its endpoint policies (the dashboard's Generate Endpoints, or POST /api/v1/organizations/{orgId}/endpoints/regenerate with {"apiConfigurationId":"<apiId>"}). A refresh updates route handlers and documentation; in configured mode it does not serve tables without enabled policies. Generated table-set changes also trigger reflection on the next poll. All refreshes preserve excluded tables and included-schema restrictions. During an unreachable database or platform outage, routes and documentation retain the last successfully published generation; exclusions apply within one poll while the platform is reachable.

API usage accounting

Each API's detail page shows served requests, request bytes where available, and response payload bytes for the last 30 UTC days, including today, with daily trends. Missing days are zero-filled. Data is attributed to the API and organization; the organization's request trend sums its APIs. Daily rows are retained for 90 days.

The runtime records usage where its existing request counter increments: requests that reach the measured database route operation, including operation errors. Authentication and rate-limit rejections do not count. Responses served entirely from the response cache do not invoke the handler and do not add usage. Pre-operation input/body-limit rejections follow the same existing request-count boundary.

Request bytes use the request's Content-Length when present. Requests without that header (for example, chunked bodies and many GET requests) contribute zero request bytes; the runtime does not read an extra copy of the body to estimate a missing length. This is an available-byte total, not an exact ingress meter.

Response bytes are the UTF-8 bytes emitted by JSON serialization in the handler, including measured operation-error payloads. Empty responses such as a successful update or delete (204) contribute zero response bytes. Serialization streams directly to the response; accounting does not buffer the response or serialize it twice. HTTP headers, TLS framing, and compression overhead are not included.

The runtime aggregates counters in memory and flushes counts and bytes together in a batched additive upsert (normally every 30 seconds). A failed flush restores all counters for retry; graceful shutdown attempts a final flush. These are dashboard-grade statistics: a crash can lose one pending flush interval, and an ambiguous database-write failure can replay a delta. They are not billed or used for quota enforcement. Stored rows from before byte accounting show zero bytes; no historical traffic is inferred. Storage size is not measured.

You can also read the same per-API window using a platform bearer token:

HTTP
GET /api/v1/organizations/{orgId}/apis/{id}/usage
Authorization: Bearer <platform-access-token>

Access follows the API-detail read rules, including read-only organization roles. The response includes from, to, requestCount30d, requestBytesIn30d, responseBytesOut30d, and 30 daily points with day, requests, requestBytesIn, and responseBytesOut. All dates represent UTC buckets.

Reconnecting to server...

Please wait while we restore your connection

Connection lost

Retrying in seconds...

Unable to reconnect

The server connection has been lost.
You may need to log in again.

Session Paused

The server has temporarily paused your session.

Session Expired

Your session could not be resumed.
Please reload the page to continue.