deploy-app

Deploy a project from a git repository on a pod: frontend built to static files, backend as a process, both behind one domain.

# Deploying an app on AgentsPodium

One pod runs both halves of a web project: the frontend build is served as

static files, the backend runs as an ordinary process next to it, and one

proxy inside the pod puts them behind a single domain with TLS. The disk

survives rebuilds. There is no split into functions and no per-service bill.

Status, 2026-09-13. Verified on live pods: a private GitLab repository and

a public GitHub monorepo, both Expo web builds inside a small pod, served

over HTTPS on their own hostname. node and static output are the tested

paths; python, go and docker runtimes are written but not yet proven, so

check GET /agents/:id/build rather than assuming.

Base URL for everything below:

`

https://agentspodium.com/api

`

Errors are always {"error":"CODE","message":"..."}.

1. Get a key once

Ask your operator for an API key from https://agentspodium.com/account

("API keys for agents"). It looks like ak_live_… and goes on every call:

`

Authorization: Bearer ak_live_…

`

An e-mail code also works (POST /auth/request, then POST /auth/verify),

but it needs a mailbox. The key does not.

2. Describe the project

Everything the pod needs to build and run the project goes in one app

object. Only repo is required; the rest has defaults or is detected.

field — meaning — default

repo — https git URL. SSH remotes are not supported — required

branch — branch to build — main

rootDir — directory the build runs in, for a monorepo — repository root

runtimenode, python, go, static, docker — detected from the repo

buildCommand — how to build — default for the detected runtime

outputDir — static output, relative to rootDir — none

startCommand — backend process — none

appPort — port the backend listens on inside the pod — 3000

apiPrefix — paths routed to the backend; the rest is served static — /api

env — environment variables for the app — {}

repoToken — token for a private repository — none

repoUser — username paired with the token — what the host expects

Set outputDir, startCommand, or both. A pod with neither serves nothing,

and the API says so rather than creating it.

3. Create it

engine is app, and the smallest plan is small: the build runs inside

the pod, so the plan is also the build machine, and npm ci on 1 GB does not

finish.

A real example — an Expo web app in a monorepo, static only, private repo on

a self-hosted Forgejo:

`bash

curl -s -X POST https://agentspodium.com/api/agents \

-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{

"engine": "app",

"tier": "small",

"personaId": "personal-assistant",

"name": "hq-app",

"app": {

"repo": "https://git.defispace.com/hq/app",

"branch": "main",

"rootDir": "app",

"buildCommand": "npm ci && npx expo export -p web",

"outputDir": "dist",

"repoToken": "…"

}

}'

`

A fullstack example — React frontend and a Node API in the same repository:

`json

{

"engine": "app", "tier": "small", "personaId": "personal-assistant",

"app": {

"repo": "https://github.com/owner/project",

"buildCommand": "npm ci && npm run build",

"outputDir": "dist",

"startCommand": "node server/index.js",

"appPort": 3000,

"apiPrefix": "/api",

"env": { "NODE_ENV": "production" }

}

}

`

The reply is {"agent":{…}}. Keep agent.id. The pod answers at

agent.endpointUrl; agent.app shows the configuration as stored, and

agent.appRepoTokenEnc is "set" or null — the token itself never comes

back.

4. Watch the build, not the pod

`bash

curl -s https://agentspodium.com/api/agents/$ID/build -H "Authorization: Bearer $TOKEN"

# {"build":{"state":"building|ok|failed|unknown","commit":"abc1234",

# "startedAt":"…","finishedAt":"…","logTail":"last lines"}}

`

A pod can be alive and still serving the previous version while a new build

fails, so pod health is not build health. logTail carries the reason.

Poll every five seconds; a first build with a cold cache takes minutes.

5. Your own domain

Point an A record at 138.199.136.33, then send domain on create or set it

later on the agent page. GET /api/domains/check?domain=<name>&https=1 says

whether DNS points here and whether HTTPS already answers. The certificate is

issued automatically once the record resolves. Names under agentspodium.com

are refused: every pod already gets one.

6. Ship a new version of an app that already exists

This is the common case: the project is already deployed, you pushed a commit,

now make the pod serve it. Two things are needed and nothing else — the API

key, and the id of the instance.

If you do not have the id, list what the key can see:

`bash

curl -s https://agentspodium.com/api/agents -H "Authorization: Bearer $TOKEN"

# {"agents":[{"id":"agt_…","name":"hq-app","engine":"app","status":"running",

# "endpointUrl":"https://…","app":{"repo":"…","branch":"main",…}}]}

`

Match on engine: "app" and the app.repo you just pushed to. Then:

`bash

curl -s -X POST https://agentspodium.com/api/agents/$ID/rebuild -H "Authorization: Bearer $TOKEN"

curl -s https://agentspodium.com/api/agents/$ID/build -H "Authorization: Bearer $TOKEN"

`

rebuild fetches the latest commit on the configured branch, runs the build

again and reloads the pod's routing. The disk is kept, so node_modules and

framework caches survive and the second build is much faster than the first.

Poll /build until state is ok or failed; on failed, logTail says

why, and the site keeps serving the previous version in the meantime.

Nothing else is required. The token, the branch and the build command are

already stored on the instance.

7. Change the configuration, then rebuild

`bash

# point at another branch, fix the build command, replace the token

curl -s -X PATCH https://agentspodium.com/api/agents/$ID/app \

-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \

-d '{"branch":"release","buildCommand":"npm ci && npm run build:prod"}'

# apply it: rebuild from the latest commit, keeping the disk

curl -s -X POST https://agentspodium.com/api/agents/$ID/rebuild -H "Authorization: Bearer $TOKEN"

`

The PATCH answers "applied":"on the next rebuild" because the pod reads the

configuration when it starts. Nothing changes until you rebuild.

8. Private repositories

Send repoToken with a token that can read the repository. It is encrypted

at rest, handed to the pod at deploy time, and never returned.

repoUser you can leave out. Forges disagree about what goes next to a token

— GitHub takes x-access-token, GitLab oauth2, Bitbucket x-token-auth,

Gitea and Forgejo the token alone — and a self-hosted GitLab is

indistinguishable from a self-hosted Gitea by its URL. The pod tries the forms

in turn and keeps the one the server accepts; the build log names it. Send

repoUser only to skip that.

Know what you are agreeing to: the token lives in the pod's environment, and

the code you deploy runs in that pod. It is your own repository token, but

anything you deploy can read it. Use a token scoped to that one repository.

9. Instead of polling

Send webhookUrl on create and the platform POSTs signed events instead:

agent.running, agent.stopped, agent.failed, agent.deleted,

payment.confirmed, deletion.warning. The signing secret comes back once

as webhookSecret. See https://hosting.defispace.com/docs/webhooks.md

10. What goes wrong

object. The two travel together.

in the pod; 1 GB is not enough to install a frontend's dependencies.

.. segment. Paths are relative to rootDir.

to run. One of them has to be there.

accepted. Use the https URL and a token for private repositories.

before dying, usually out of memory. Move to a bigger plan and rebuild.

read it, or it has expired. The log shows the attempt with the token

replaced by ***; git prints the URL it tried on an auth failure, so it is

masked on the way out rather than trusted not to appear.

build did not produce. Check the build log for where the output went.

11. Everything else

An app instance is an instance like any other: GET /agents/:id for status,

/liveness, /usage, /term for when it expires, pause, resume, delete,

export, and the payment endpoints. See

https://hosting.defispace.com/docs/quickstart.md