Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/yohangr3/agentelanggrafh/llms.txt

Use this file to discover all available pages before exploring further.

The Instances API provides administrators with full lifecycle control over tenant instances — isolated ECS services paired with dedicated MySQL schemas, each identified by a unique slug. All endpoints in this group are restricted to the primary instance (expected_tenant="*") and require membership in the Cognito admin group. Calling these endpoints from a tenant instance returns 404.
Primary instance only. Tenant stacks do not hold the TenantPanelAccess IAM policy. Even if a tenant user somehow obtained admin Cognito group membership, the IAM guard on the primary instance is the authoritative enforcement layer — the application guard here is an additional safeguard.

What is a tenant instance?

Each customer of the ERP Financial Agent platform runs in a fully isolated tenant instance: a dedicated Amazon ECS service (erp-agent-service-<tenant_id>) inside its own ECS cluster (erp-agent-cluster-<tenant_id>), backed by a dedicated RDS MySQL database (erp-rds-<tenant_id>). Infrastructure is provisioned via a CloudFormation stack named erp-agent-services-<tenant_id>. Every provisioned instance is registered in a shared DynamoDB tenant registry table (erp-agent-tenants), which is the authoritative source of identity for all admin panel operations. Live ECS task counts and RDS status are fetched on-demand and overlaid on registry data — if AWS describe calls fail, the instance is still listed with live_status: "unknown" so no instance is silently hidden.
New instances are always born stopped (desiredCount=0). After provisioning completes (~15 min), use the Start Instance endpoint or run ./scripts/<tenant_id>-up.sh to bring the service online.

Authentication

All /api/admin/instances endpoints require:
  1. A valid Cognito JWT in the Authorization: Bearer <token> header.
  2. Membership in the Cognito admin group.
  3. Requests must be routed through the primary instance — tenant instance deployments return 404 for all routes under this prefix.

Rate limits

EndpointLimit
GET /api/admin/instances30 req / minute
POST /api/admin/instances5 req / minute
POST /api/admin/instances/{tenant_id}/start10 req / minute
POST /api/admin/instances/{tenant_id}/stop10 req / minute

GET /api/admin/instances

List all provisioned tenant instances registered in the DynamoDB erp-agent-tenants table, each enriched with live ECS task state and RDS instance status from AWS.

Response

instances
TenantInstanceSummary[]
required
Ordered list of tenant instance records.
count
integer
required
Total number of instances returned. Equals instances.length.

Example

curl -s https://api.example.com/api/admin/instances \
  -H "Authorization: Bearer $ADMIN_TOKEN"

POST /api/admin/instances

Provision a new tenant instance by dispatching the provision-tenant.yml GitHub Actions workflow. Returns 202 Accepted immediately — provisioning runs asynchronously and takes approximately 15 minutes.
The backend never provisions infrastructure directly. Creating a tenant requires CloudFormation and IAM privileges that the application must not hold. Instead, this endpoint dispatches the GitHub Actions workflow (.github/workflows/provision-tenant.yml) using a fine-grained PAT stored in AWS Secrets Manager. The workflow runs with an OIDC role that has the necessary CloudFormation/IAM access.
The workflow is idempotent — it is safe to re-run if something failed mid-way. Each tenant_id runs in its own concurrency group (provision-tenant-<tenant_id>), so parallel dispatches for the same slug are serialised, never run concurrently.

GitHub token prerequisite

The endpoint reads the GitHub fine-grained PAT from the AWS Secrets Manager secret named by the GITHUB_TOKEN_SECRET_NAME environment variable. The PAT must have Actions: write permission on the repository that hosts the workflow. If the secret is absent or inaccessible, the endpoint returns 503 with an actionable error message that includes the expected secret name.

Request body

tenant_id
string
required
Unique slug for the new tenant. Must match ^[a-z0-9][a-z0-9-]{1,30}$ (lowercase letters, digits, and hyphens; 2–31 characters total). The slugs production and staging are reserved and will be rejected with 400.
admin_email
string
default:"\"\""
Email address for the initial org_admin Cognito user. When provided, the provisioning script creates the user and stores the temporary password in Secrets Manager under erp-agent/tenant-admin-temp-<tenant_id> (expires after 7 days without login). Leave empty to skip admin user creation.
rds_class
string
default:"\"db.t3.medium\""
RDS DB instance class. Accepted values: db.t3.medium, db.t3.small, db.t4g.medium. This controls the cost of the tenant (~80/monthon, 80/month on, ~37/month off for the default class).

Response

Returns 202 Accepted on success.
tenant_id
string
required
The slug of the tenant being provisioned — mirrors the request body value.
action
string
required
Always "provision_dispatched" for this endpoint.
detail
string
Human-readable status message. Indicates the expected provisioning duration and where to follow progress.
actions_url
string
Direct URL to the GitHub Actions workflow runs page for provision-tenant.yml. Use this to monitor live provisioning progress.

Error responses

StatusCondition
400tenant_id fails the slug validation regex or is a reserved word (production, staging).
409A tenant with this tenant_id already exists in the DynamoDB registry.
503The GitHub PAT secret (GITHUB_TOKEN_SECRET_NAME) is missing or inaccessible in Secrets Manager.
502GitHub API returned an unexpected status code (not 204).

Example

curl -s -X POST https://api.example.com/api/admin/instances \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "acme-corp",
    "admin_email": "admin@acme.com",
    "rds_class": "db.t3.medium"
  }'

POST /api/admin/instances//start

Turn a registered tenant instance on by setting ECS desiredCount to 1 and starting the RDS DB instance. Updates the registry status to "on". The instance takes approximately 3–5 minutes to become fully available after this call returns.

Path parameters

tenant_id
string
required
Slug of the tenant to start. Must pass the same ^[a-z0-9][a-z0-9-]{1,30}$ validation as the create endpoint.

Response

tenant_id
string
required
Slug of the tenant that was acted on.
action
string
required
Always "start" for this endpoint.
detail
string
Human-readable confirmation message.
actions_url
string
Empty string for start/stop actions (only populated by the provision endpoint).

Example

curl -s -X POST https://api.example.com/api/admin/instances/acme-corp/start \
  -H "Authorization: Bearer $ADMIN_TOKEN"

POST /api/admin/instances//stop

Turn a registered tenant instance off by setting ECS desiredCount to 0 and stopping the RDS DB instance. Updates the registry status to "off". The tenant URL will respond with 503 until the instance is started again.

Path parameters

tenant_id
string
required
Slug of the tenant to stop.

Response

tenant_id
string
required
Slug of the tenant that was acted on.
action
string
required
Always "stop" for this endpoint.
detail
string
Human-readable confirmation message.
actions_url
string
Empty string for start/stop actions.

Example

curl -s -X POST https://api.example.com/api/admin/instances/acme-corp/stop \
  -H "Authorization: Bearer $ADMIN_TOKEN"

Provisioning lifecycle

The diagram below shows the complete lifecycle of a tenant instance from initial dispatch through normal operation:
POST /api/admin/instances


GitHub Actions workflow dispatched
(provision-tenant.yml, ~15 min)

        ├── Validate tenant_id slug
        ├── Configure AWS credentials (OIDC)
        ├── Create RDS instance + secret (erp-agent/tenant-admin-temp-<id>)
        ├── Deploy CloudFormation stack (erp-agent-services-<id>)  ← desiredCount=0
        ├── Create Cognito org_admin user (if admin_email provided)
        └── Register entry in DynamoDB erp-agent-tenants


        Instance registered — status: "off", live_status: "off"


POST /api/admin/instances/{tenant_id}/start

        ├── ECS desiredCount → 1
        ├── RDS start_db_instance
        └── Registry status → "on"


        live_status: "starting" → "on"  (~3–5 min)

DynamoDB tenant registry

The erp-agent-tenants table is scanned by GET /api/admin/instances and keyed on tenant_id (string). The table holds the same fields surfaced by TenantInstanceSummary: stack_name, rds_identifier, alb_dns, admin_email, status, created_at, and updated_at. Live ECS/RDS state fields (live_status, running_count, desired_count, rds_status) are not stored — they are fetched from AWS on every list call and overlaid in-memory.
If the erp-agent-tenants table does not yet exist (e.g. before the first tenant is provisioned), GET /api/admin/instances returns an empty list rather than an error.

Build docs developers (and LLMs) love