APIs

Endpoints without the scaffolding

Each endpoint is a function with TLS, a verified caller, and a database that already knows what they may read.

api
volcano cloud functions deploy --all  Deployed list-orders  Deployed get-order  Deployed sync-ledgervolcano cloud functions listlist-orders   nodejs22   active  invoke: https://3cd3e058.functions.volcano.run/# list prints the invocation URL; deploy does not# sessions are verified before your handler runs
Overview

Nobody ships an API. They ship the framework around it

The endpoint itself is usually a dozen lines. Around it goes a router, a middleware chain, token verification, a connection pool, request logging, a TLS termination story and a deployment pipeline — none of which is the thing your customers asked for.

On Volcano the endpoint is the unit. Deploy a function and it has a URL with TLS, receives the caller's verified identity on the event, and reaches a database that applies your policies. What is left to write is the part that is actually yours.

Surface

One function, one endpoint

No router to register in and no shared app object to break. Each endpoint deploys, logs and fails independently, so a bad release affects one route rather than all of them.

  • Deploy or roll back one endpoint at a time
  • Per-endpoint build and runtime logs
  • HTTPS with a certificate you never handle
volcano cloud functions list
list-orders   public    nodejs22   2m agoget-order     public    nodejs22   2m agocreate-order  public    nodejs22   2m agosync-ledger   private   nodejs22   2m ago# private ones refuse the anon key a browser ships with
Auth

The caller is verified before you run

Volcano checks the session and puts the user on the event, so your handler starts with a known identity instead of a token to validate. A caller carrying only the anon key arrives with no identity, which is your cue to return a 401.

  • user_id, email, role and project_id on the event
  • No JWT library or key rotation in your code
  • The same identity Postgres sees as auth.uid()
volcano.dev/dashboard/edge-function
Deployed endpoints with their runtime and visibility
Responses

The database decides what comes back

Connect as the caller and row-level policies filter the result before your code serialises it. An authorization bug in one endpoint cannot expose rows the policy already excluded.

  • No per-endpoint ownership checks to forget
  • New endpoints inherit the existing rules
  • Service key stays server-side for admin work
same endpoint, two callers
POST list-orders  { limit: 20 }ada   → 200  [ 3 orders ]cleo  → 200  [ 1 order  ]anon  → 200  [ ]one query · the policy scoped each response
Path to production

How it works

  1. 01

    A function per route

    Name it after what it does. Public if the anon key should reach it, private if a real session is required.

  2. 02

    Read the caller

    Take the identity off the event and connect as that user so policies apply.

  3. 03

    Validate the payload

    Reject bad input with a 400 before touching the database, and return a useful message.

  4. 04

    Deploy and watch it

    Ship the set, then follow runtime logs to see real status codes and latency.

Code

An endpoint, its rules, its client, its deploy

JavaScript
const { Client } = require('pg'); const { databaseConnectionString } = require('@volcano.dev/sdk'); const MAX_LIMIT = 100; exports.handler = async (event) => { const auth = event.__volcano_auth; // A session from an anonymous sign-in has role 'anonymous'. This endpoint // wants a real account, so both that and a missing session are rejected. if (!auth || auth.role === 'anonymous') { return json(401, { error: 'sign in required' }); } const limit = Number(event.limit ?? 20); if (!Number.isInteger(limit) || limit < 1 || limit > MAX_LIMIT) { return json(400, { error: `limit must be an integer between 1 and ${MAX_LIMIT}` }); } // Connect as the caller: this query cannot return anyone else's orders, // whatever the rest of this handler does. Omit userId for admin access. const db = new Client({ connectionString: databaseConnectionString(process.env.DATABASE_URL, { userId: auth.user_id, }), }); await db.connect(); try { const { rows } = await db.query( 'select id, status, total_cents, placed_at from orders order by placed_at desc limit $1', [limit], ); return json(200, { orders: rows }); } finally { await db.end(); } }; function json(statusCode, body) { return { statusCode, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }; }
Return

What you do not build

0lines of token verification

The caller arrives on the event already verified, with their role attached.

1 policyfor every endpoint

Authorization is written next to the data instead of repeated per route.

Per routedeploys and logs

One endpoint can be fixed and shipped without redeploying the rest.

What you get

Smaller handlers

Validation and business logic, with the plumbing removed.

Consistent authorization

New endpoints inherit rules instead of restating them.

Isolated failures

A bad deploy affects one route, not the whole surface.

Platform

Built on Volcano

Functions and agents
  • The endpoints

    Functions in Node, Python or Ruby with HTTPS, public or private, deployed independently.

Authentication
  • Callers

    Verified sessions on the event, with email, password and OAuth sign-in behind them.

Databases and vector
  • Scoping in the database

    Row-level policies the database applies itself, so scoping is not per-endpoint code.

File storage
  • Payloads too big for JSON

    Uploads and exports go to a bucket, with access controlled by policy.

Frequently asked questions

Read the docs
How are endpoints addressed?

Each deployed function gets its own HTTPS hostname, with DNS answering from the closest region. Call it with the SDK, which attaches the session for you, or POST to it from anything that speaks HTTP. Over the wire the body is {"payload": {…}} and a bearer token is always required.

Do I have to verify tokens myself?

No. Volcano validates the session first and attaches the user to the event as __volcano_auth. A caller carrying only the anon key arrives without it, so checking whether that object is there replaces the token handling you would otherwise write.

What does marking an endpoint private do?

It refuses the anon key, so a browser carrying only that key gets a 403. A signed-in user's token and the service key still reach it, so reconciliation and admin routes should also check the caller's role or rely on a policy.

Is there built-in rate limiting?

No — per-caller rate limiting is not a platform feature. Implement it in the endpoint with a counter table if you need it.

How long can a request take?

Up to 180 seconds per invocation. Work that runs longer should be handed to a scheduled function rather than held open, and the ceiling for each plan is on the pricing page.

Can I put my own domain on an endpoint?

Custom domains apply to frontends. API endpoints are served on your project's Volcano host, so front them from your own app if you need a branded path.

Ready to ship your API?

Build, deploy, and scale on Volcano's global platform — free to start, with no infrastructure to manage.

Explore more solutions