Dashboard
This version implements the corrected hierarchy: Service → Resource → Method → Access Rules. A single method can now have different rules for public clients, authenticated frontend users, and backend service APIs.
Access Rule Evaluation Order
Runtime policy engineReject if the service has no public slug route or is paused.
Find the resource path and HTTP method.
public_client, frontend_user, service_api, or worker.
Select rule by path + method + caller type + priority.
Then create the async job if allowed.
Live Simulation Result
LatestRun a simulation to see rule selection.
Playground
Create one Service and Resource, send mock POST and GET requests from a Client UI, and watch a Worker poll and process the resource live.
Initial Service and Resource Setup
new-user walkthroughClient UI
POST, poll, then GET the resource listCreate the setup, then POST or GET the resource.
Worker
waiting for setupWorker will poll every few seconds after setup.
API Documentation
Complete reference for ServiceBridge: control plane APIs, data-plane invocation, method access rules, keys, rate limits, network controls, workers, jobs, alerts, billing, errors, and SDK usage.
What ServiceBridge Does
Platform overviewServiceBridge is a communication layer for worker-based services. It turns client, backend, and internal-service requests into authorized jobs, routes them to the right worker fleet, tracks leases, events, and results, and gives operators control-plane and IaC surfaces for the workflow. Keeping services off public ingress is one benefit of the worker-polling model.
Client / Backend / Service
↓
ServiceBridge Communication Layer
↓
Policy + Routing
↓
Job Queue + Lease
↓
Worker Service
↓
Events / ResultsCore Hierarchy
Correct modelTenant
└── Service
└── Resource
└── HTTP Method
└── Access Rules
├── public_client rule
├── frontend_user rule
├── service_api rule
└── worker/admin ruleImportant Design Rule
Do not mess this upQuickstart: Create service → resource → rule → invoke
POSTcurl -X POST https://api.servicebridge.com/v1/services \
-H "Authorization: Bearer tenant_admin_token" \
-H "Content-Type: application/json" \
-d '{
"name": "Hello API",
"slug": "hello-api",
"slugEnabled": true
}'curl -X POST https://api.servicebridge.com/v1/resources \
-H "Authorization: Bearer tenant_admin_token" \
-H "Content-Type: application/json" \
-d '{
"service": "Hello API",
"path": "/hello",
"methods": ["GET", "POST"],
"status": "Enabled"
}'curl -X POST https://api.servicebridge.com/v1/access-rules \
-H "Authorization: Bearer tenant_admin_token" \
-H "Content-Type: application/json" \
-d '[
{
"name": "Public Hello Read",
"service": "Hello API",
"path": "/hello",
"method": "GET",
"callerType": "public_client",
"authMode": "public_client_token",
"ratePolicy": "generic_public_read_strict"
},
{
"name": "Public Hello Create",
"service": "Hello API",
"path": "/hello",
"method": "POST",
"callerType": "public_client",
"authMode": "public_client_token",
"ratePolicy": "generic_public_write_strict"
}
]'curl -X GET https://api.servicebridge.com/s/hello-api/hello \
-H "X-ServiceBridge-Client-Key: pk_live_hello_web"
202 Accepted
{
"job_id": "job_get_001",
"status": "pending",
"result_url": "/v1/jobs/job_get_001"
}curl -X POST https://api.servicebridge.com/s/hello-api/hello \
-H "X-ServiceBridge-Client-Key: pk_live_hello_web" \
-H "Content-Type: application/json" \
-d '{
"message": "hello world",
"createdBy": "new-user"
}'
202 Accepted
{
"job_id": "job_post_002",
"status": "pending",
"result_url": "/v1/jobs/job_post_002"
}curl -X POST https://api.servicebridge.com/v1/services/svc_hello_api/jobs/claim \
-H "Authorization: Bearer wk_live_hello_worker" \
-H "Content-Type: application/json" \
-d '{
"worker_id": "hello-worker-1",
"limit": 5,
"lease_seconds": 60
}'
200 OK
{
"jobs": [
{ "id": "job_get_001", "method": "GET", "path": "/hello", "leaseToken": "lease_get" },
{ "id": "job_post_002", "method": "POST", "path": "/hello", "payload": { "message": "hello world" }, "leaseToken": "lease_post" }
]
}curl -X POST https://api.servicebridge.com/v1/jobs/job_post_002/complete \
-H "Authorization: Bearer wk_live_hello_worker" \
-H "X-ServiceBridge-Lease-Token: lease_post" \
-H "Content-Type: application/json" \
-d '{
"status": 201,
"body": {
"id": "hello_001",
"message": "hello world",
"createdBy": "new-user"
}
}'
curl -X POST https://api.servicebridge.com/v1/jobs/job_get_001/complete \
-H "Authorization: Bearer wk_live_hello_worker" \
-H "X-ServiceBridge-Lease-Token: lease_get" \
-H "Content-Type: application/json" \
-d '{
"status": 200,
"body": []
}'curl https://api.servicebridge.com/v1/jobs/job_post_002 \
-H "X-ServiceBridge-Client-Key: pk_live_hello_web"
200 OK
{
"id": "job_post_002",
"status": "completed",
"result": {
"status": 201,
"body": { "id": "hello_001", "message": "hello world" }
}
}
curl -X GET https://api.servicebridge.com/s/hello-api/hello \
-H "X-ServiceBridge-Client-Key: pk_live_hello_web"
202 Accepted
{ "job_id": "job_get_003", "status": "pending" }
// Worker completes job_get_003 with:
{ "status": 200, "body": [{ "id": "hello_001", "message": "hello world" }] }Use Case Examples
Five-level implementation strategyThese demos are intentionally progressive. Start with one worker-backed request path, then add authentication, internal jobs, multi-service orchestration, and finally production-grade GitOps automation. The examples use a realistic e-commerce/bookstore business because it exercises public reads, logged-in writes, internal jobs, payment, inventory, notification, PDF generation, and CI/CD provisioning.
Level 1: Public Product Catalog API
GETNeed: send catalog read requests through a worker-backed service with identity, policy, queueing, and result handling. Anyone using the frontend can browse products, while the database and worker service stay protected by the outbound polling model.
Scenario: Public website lists books/products. Services: Book Store: Slug Enabled Resource: GET /book Caller: public_client Security: public client key origin allowlist strict public rate limit Worker: Bookstore worker polls ServiceBridge and calls local bookstore code.
{
"name": "Public Catalog Read",
"service_id": "svc_bookstore",
"resource_path": "/book",
"method": "GET",
"caller_type": "public_client",
"auth_mode": "public_client_token",
"rate_limit_policy": "public_get_strict",
"allowed_origins": ["https://bookstore.com"]
}GET /s/bookstore/book?search=architecture X-ServiceBridge-Client-Key: pk_live_bookstore_web
1. Resolve /s/bookstore/book 2. Match GET /book + public_client rule 3. Check origin and public client key 4. Apply rate limit by public_client_key_id + IP + origin + resource + method 5. Create Book Store job 6. Bookstore worker claims job and returns product list
Level 2: Authenticated Customer Actions with IAM JWT
POSTNeed: logged-in users can create carts, save wishlists, or place orders. ServiceBridge validates the user JWT from the IAM provider before creating the job.
Scenario: Customer logs in through Auth0, Cognito, Keycloak, Okta, Clerk, Firebase Auth, or custom IAM. Frontend receives a JWT. Frontend calls ServiceBridge with public client key + JWT. Services: Book Store: Slug Enabled Resources: GET /book public POST /cart authenticated user POST /order authenticated user Caller: frontend_user Security: public client key user JWT IAM provider config required scopes user-level rate limit
{
"name": "bookstore-auth",
"issuer": "https://auth.bookstore.com/",
"jwks_uri": "https://auth.bookstore.com/.well-known/jwks.json",
"audiences": ["bookstore-api"],
"allowed_algorithms": ["RS256"],
"claim_mapping": {
"subject": "sub",
"scope": "scope",
"roles": "https://bookstore.com/roles",
"email": "email"
}
}{
"name": "Customer Create Cart",
"resource_path": "/cart",
"method": "POST",
"caller_type": "frontend_user",
"auth_mode": "public_client_plus_user_token",
"jwt_provider_id": "iam_bookstore_auth",
"required_scopes": ["cart:create"],
"rate_limit_policy": "frontend_write_strict"
}POST /s/bookstore/cart
X-ServiceBridge-Client-Key: pk_live_bookstore_web
Authorization: Bearer user_jwt
{
"items": [
{ "sku": "book_001", "quantity": 1 }
]
}{
"caller_type": "frontend_user",
"jwt_provider_id": "iam_bookstore_auth",
"user": {
"sub": "user_456",
"issuer": "https://auth.bookstore.com/",
"audience": "bookstore-api",
"scopes": ["cart:create", "order:create"],
"email": "customer@example.com"
},
"matched_access_rule_id": "rule_customer_create_cart"
}Level 3: Internal Job Only PDF Generation
POSTNeed: after an order is confirmed, generate an invoice PDF. The PDF Generator has no public route and does not need a stable public IP. It receives jobs through ServiceBridge.
Scenario: Customer places order. Bookstore worker creates order. Bookstore worker enqueues internal PDF job. PDF worker claims PDF job from another machine. Services: Book Store: Slug Enabled PDF Generator: Internal Job Only Important: PDF Generator has no /s/pdf-generator/... public URL. Workers communicate through ServiceBridge, not directly.
{
"source_service_id": "svc_bookstore",
"target_service_id": "svc_pdf_generator",
"operation": "generate_invoice_pdf",
"required_scopes": ["pdf:generate"],
"rate_limit_policy": "internal_pdf_generation",
"max_pending_jobs": 5000
}POST /v1/internal/jobs
Authorization: Bearer sk_live_bookstore_service
Idempotency-Key: invoice:order_789
{
"target_service_id": "svc_pdf_generator",
"operation": "generate_invoice_pdf",
"payload": {
"order_id": "order_789",
"customer_id": "cust_456",
"template": "invoice_v1"
}
}POST /v1/services/svc_pdf_generator/jobs/claim
Authorization: Bearer wk_live_pdf_worker
{
"worker_id": "pdf-worker-1",
"limit": 5,
"lease_seconds": 60
}Level 4: Multi-Service E-Commerce Order Workflow
POSTNeed: a real order requires inventory reservation, payment authorization, invoice generation, and notification. Some services are slug-enabled, some are internal job-only, and some are internal M2M.
Scenario: Customer places order from frontend. Book Store creates order. Inventory reserves stock. Payment authorizes charge. PDF Generator creates invoice. Notification sends email. Services: Book Store: Slug Enabled Inventory Service: Internal Job Only Payment Service: Internal M2M Data Plane or Internal Job Only PDF Generator: Internal Job Only Notification Service: Internal Job Only
[
{
"source_service_id": "svc_bookstore",
"target_service_id": "svc_inventory",
"operation": "reserve_stock",
"required_scopes": ["inventory:reserve"]
},
{
"source_service_id": "svc_bookstore",
"target_service_id": "svc_payment",
"operation": "authorize_payment",
"required_scopes": ["payment:authorize"]
},
{
"source_service_id": "svc_bookstore",
"target_service_id": "svc_pdf_generator",
"operation": "generate_invoice_pdf",
"required_scopes": ["pdf:generate"]
},
{
"source_service_id": "svc_bookstore",
"target_service_id": "svc_notification",
"operation": "send_order_confirmation",
"required_scopes": ["notification:send"]
}
]POST /s/bookstore/order → Bookstore job Bookstore worker: → enqueue reserve_stock → enqueue authorize_payment → create order → enqueue generate_invoice_pdf → enqueue send_order_confirmation Internal workers: Inventory worker claims reserve_stock Payment worker claims authorize_payment PDF worker claims generate_invoice_pdf Notification worker claims send_order_confirmation
Level 5: Production GitOps Rollout Across Environments
CLINeed: provision the entire e-commerce integration consistently across dev, staging, and production using YAML, CLI, CI/CD, tenant automation keys, approvals, and drift detection.
Scenario: Engineering team manages ServiceBridge configuration in Git. Pull request changes servicebridge.yaml. CI validates and plans. Production apply happens after approval. Products used: ServiceBridge API SDK CLI / IaC Tenant Automation Keys IAM / JWT Providers Internal Job Permissions Rate Limits Alerts Network / DDoS Controls
name: ServiceBridge Production Apply
on:
push:
branches: [main]
paths:
- servicebridge.yaml
jobs:
apply:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- run: npm install -g @servicebridge/cli
- run: sbctl validate -f servicebridge.yaml
env:
SERVICEBRIDGE_TENANT_KEY: ${{ secrets.SERVICEBRIDGE_TENANT_KEY }}
- run: sbctl plan -f servicebridge.yaml --env prod
env:
SERVICEBRIDGE_TENANT_KEY: ${{ secrets.SERVICEBRIDGE_TENANT_KEY }}
- run: sbctl apply -f servicebridge.yaml --env prod --non-interactive
env:
SERVICEBRIDGE_TENANT_KEY: ${{ secrets.SERVICEBRIDGE_TENANT_KEY }}tenant automation key:
scopes:
- tenant:read
- services:write
- resources:write
- access_rules:write
- rate_limits:write
- iam_providers:write
- internal_permissions:write
- network:write
- alerts:write
allowed_ips:
- 203.0.113.20/32
expires_at: 2027-01-01
pipeline:
validate
plan
approval
apply
audit
drift detectionBonus Scenario: AI Chatbot with Agent Tool Workers
AINeed: logged-in users send prompts, Agent workers claim prompt jobs, and internal tool workers perform RAG, web search, MCP/product search, memory lookup, and LLM inference. The response can stream partial chunks and store the final answer.
Services:
AI Chat API: Slug Enabled
Agent Orchestrator: Internal Job Only
RAG Retrieval Service: Internal Job Only
Web Search Tool: Internal Job Only
MCP Product Search: Internal Job Only
Memory Service: Internal Job Only
LLM Inference Service: Internal Job Only
Slug route:
POST /s/ai-chat/chat
Result channel:
/v1/jobs/{job_id}/events
Internal permissions:
AI Chat API → Agent Orchestrator.run_agent_turn
Agent Orchestrator → RAG.retrieve_context
Agent Orchestrator → Web Search.web_search
Agent Orchestrator → MCP Product Search.product_search
Agent Orchestrator → Memory.get_user_memory
Agent Orchestrator → LLM.generate_responsePlayground
Hands-on Level 1 flowThe Playground is a guided first-run test for the core worker-service communication path. It creates one slug-enabled service, one resource, public GET/POST rules, a mock client, and a mock worker. Use it to verify the basic job lifecycle before moving into the deeper use-case scenarios.
Setup: Service: Hello API Resource: /hello Methods: POST, GET ClientUI: POST /s/hello-api/hello Poll job until completed GET /s/hello-api/hello Worker: Polls pending jobs Creates a Hello world object for POST Returns stored objects for GET
How It Maps to the Use-Case Levels
GUIDEAuthentication Types
Caller identityGenerate Public Client Key
POSTPublic client keys are safe to embed in frontend code, but they are not secrets. Use them for app identity, origin checks, and rate limits.
POST /v1/services/{service_id}/keys/public-client
{
"name": "Bookstore Web",
"allowed_origins": ["https://bookstore.com"],
"scope": ["bookstore:GET:/book"],
"rate_limit_policy": "public_get_strict"
}Generate Service API Key
POSTService API keys are secret. Show once, store hash only. Use for backend-to-backend calls.
POST /v1/services/{service_id}/keys/service-api
{
"name": "Inventory Backend",
"scopes": ["book:read", "book:create"],
"allowed_ips": ["18.141.10.22/32"],
"expires_at": "2027-01-01T00:00:00Z"
}Configuring JWT Authentication with Any IAM Provider
OIDC / JWKS compatibleServiceBridge validates user JWTs at ingress for routes using auth_mode = public_client_plus_user_token or user_token. The backend may still revalidate for defense-in-depth, but the authorization decision should happen before job creation.
1. Create IAM Provider
POSTConfigure issuer, audience, JWKS, accepted algorithms, and claim mapping.
POST /v1/iam-providers
Authorization: Bearer tenant_admin_token
Content-Type: application/json
{
"name": "Bookstore Auth0",
"provider_type": "oidc",
"issuer": "https://auth.bookstore.com/",
"discovery_url": "https://auth.bookstore.com/.well-known/openid-configuration",
"jwks_uri": "https://auth.bookstore.com/.well-known/jwks.json",
"audiences": ["bookstore-api"],
"allowed_algorithms": ["RS256"],
"claim_mapping": {
"subject": "sub",
"scope": "scope",
"roles": "https://bookstore.com/roles",
"tenant": "https://bookstore.com/tenant_id",
"email": "email"
},
"jwks_cache_seconds": 3600,
"clock_skew_seconds": 60,
"status": "active"
}2. Attach IAM Provider to Access Rule
POSTThe access rule tells ServiceBridge which provider to use and what scopes or roles are required.
POST /v1/access-rules
{
"name": "Frontend Book Create",
"service_id": "svc_bookstore",
"resource_path": "/book",
"method": "POST",
"caller_type": "frontend_user",
"auth_mode": "public_client_plus_user_token",
"jwt_provider_id": "iam_auth0_bookstore",
"required_scopes": ["book:create"],
"required_roles": ["seller"],
"rate_limit_policy": "frontend_write_strict",
"allowed_origins": ["https://bookstore.com"]
}3. Frontend Calls ServiceBridge with Public Key + JWT
POSTPOST /s/bookstore/book
X-ServiceBridge-Client-Key: pk_live_xxx
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImtpZF8yMDI2X3ByaW1hcnkifQ...
{
"title": "The Art of War"
}JWT Validation Algorithm
Data plane execution1. Parse Authorization Bearer token 2. Decode JWT header 3. Reject unsupported alg 4. Resolve IAM provider from access rule 5. Fetch/cache JWKS 6. Find public key by kid 7. Verify signature 8. Verify iss exactly equals configured issuer 9. Verify aud contains configured audience 10. Verify exp, nbf, iat with clock skew 11. Extract subject, scopes, roles, tenant claim 12. Check tenant claim if configured 13. Check required scopes/roles from access rule 14. Create normalized auth_context 15. Create job
4. Job Contains Normalized auth_context
JOB{
"job_id": "job_123",
"target_service_id": "svc_bookstore",
"operation": "POST /book",
"authorized_at": "2026-07-04T12:00:00Z",
"auth_context": {
"caller_type": "frontend_user",
"public_client_key_id": "key_public_123",
"jwt_provider_id": "iam_auth0_bookstore",
"user": {
"sub": "user_456",
"issuer": "https://auth.bookstore.com/",
"audience": "bookstore-api",
"scopes": ["book:create", "book:read"],
"roles": ["seller"],
"email": "lucas@example.com"
},
"matched_access_rule_id": "rule_frontend_book_create"
}
}Test IAM Provider Config
POSTPOST /v1/iam-providers/{provider_id}/test-token
{
"jwt": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImtpZF8yMDI2X3ByaW1hcnkifQ..."
}{
"valid": true,
"subject": "user_456",
"issuer": "https://auth.bookstore.com/",
"audience": "bookstore-api",
"scopes": ["book:create", "book:read"],
"roles": ["seller"],
"key_id": "kid_2026_primary"
}Internal Service Authentication & Job Enforcement
source service → target serviceInternal services must never be callable by every service automatically. ServiceBridge derives the source service and tenant from the service API key, then checks explicit Internal Job Permissions before creating a job.
1. Service API Key Binds Caller to Tenant and Source Service
KEY{
"key_id": "key_bookstore_service",
"key_type": "service_api",
"tenant_id": "tenant_123",
"service_id": "svc_bookstore",
"scopes": ["order:create", "pdf:generate"],
"status": "active"
}When this key calls POST /v1/internal/jobs, ServiceBridge derives tenant_123 and svc_bookstore from the key.
2. Create Internal Job Permission
POSTPOST /v1/internal-job-permissions
Authorization: Bearer tenant_admin_token
{
"tenant_id": "tenant_123",
"source_service_id": "svc_bookstore",
"target_service_id": "svc_pdf_generator",
"operation": "generate_invoice_pdf",
"required_scopes": ["pdf:generate"],
"rate_limit_policy": "internal_pdf_generation",
"max_pending_jobs": 5000,
"status": "active"
}This allows Book Store to enqueue only the generate_invoice_pdf operation on PDF Generator. It does not grant access to every operation.
3. Enqueue Internal Job
POSTPOST /v1/internal/jobs
Authorization: Bearer sk_live_bookstore_service
{
"target_service_id": "svc_pdf_generator",
"operation": "generate_invoice_pdf",
"payload": {
"order_id": "order_789",
"customer_id": "cust_456",
"template": "invoice_v1"
}
}The body contains target service and operation. It does not contain source service because ServiceBridge derives source from the key.
Internal Job Authorization Algorithm
Enforcement order1. Validate service API key
2. Derive caller.tenant_id from key
3. Derive source_service_id from key
4. Read target_service_id and operation from request body
5. Load target service
6. Reject if target.tenant_id != caller.tenant_id
7. Reject if target slug mode does not accept internal jobs
8. Find active permission:
tenant_id + source_service_id + target_service_id + operation
9. Reject if permission missing
10. Check key scopes include permission.required_scopes
11. Apply rate limit:
tenant_id + source_service_id + target_service_id + operation
12. Check target max pending jobs
13. Create job with source_service_id and target_service_idAllowed Result
202{
"job_id": "job_pdf_001",
"status": "pending",
"tenant_id": "tenant_123",
"source_service_id": "svc_bookstore",
"target_service_id": "svc_pdf_generator",
"operation": "generate_invoice_pdf"
}Method Access Rules
Most important conceptAccess rules allow the same route and method to have different auth and rate limits depending on caller type.
GET /book + public_client → public_get_strict GET /book + service_api → m2m_get_high POST /book + frontend_user → frontend_write_strict DELETE /book + service_api → admin_destructive_strict
Worker Pool Behavior
Service queue distributionA service can have one worker or many workers. Access rules only decide whether a caller is allowed to create a job; they do not assign that job to a specific worker.
Service: Book Store Workers: bookstore-worker-a, bookstore-worker-b, bookstore-worker-c 1. Client request passes the access rule. 2. ServiceBridge creates one pending job for the Book Store service. 3. Any active Book Store worker may poll and claim the job. 4. The first eligible worker receives a lease token for that job. 5. Other workers cannot complete that same job without the lease token.
If a worker fails, stops heartbeating, or never returns a result, the lease eventually expires. The job can then be retried, claimed by another worker in the same service pool, or moved to a failed/dead-letter state after the retry policy is exhausted.
Create Access Rule
POSTPOST /v1/access-rules
{
"name": "Public Book Read",
"service_id": "svc_bookstore",
"resource_path": "/book",
"method": "GET",
"caller_type": "public_client",
"auth_mode": "public_client_token",
"rate_limit_policy": "public_get_strict",
"required_scopes": [],
"allowed_origins": ["https://bookstore.com"],
"allowed_ips": [],
"blocked_ips": [],
"priority": 100,
"status": "active"
}Backend Rule for Same GET /book
POST{
"name": "Backend Book Read",
"service_id": "svc_bookstore",
"resource_path": "/book",
"method": "GET",
"caller_type": "service_api",
"auth_mode": "service_token",
"rate_limit_policy": "m2m_get_high",
"required_scopes": ["book:read"],
"allowed_ips": ["18.141.10.22/32"],
"priority": 200
}Rate Limiting
Per access ruleRate limits attach to access rules, not just resources. This lets public GET and backend GET have different limits.
Create Rate Limit Policy
POSTPOST /v1/rate-limit-policies
{
"name": "public_get_strict",
"limit": 120,
"window": "1m",
"burst": 20,
"algorithm": "sliding_window",
"dimensions": [
"public_client_key_id",
"ip_address",
"origin",
"resource_id",
"method"
]
}Public Client Dimensions
Strict[ "public_client_key_id", "ip_address", "origin", "resource_id", "method" ]
Service API Dimensions
Looser[ "service_key_id", "service_id", "resource_id", "method" ]
Control Plane APIs
Admin/configurationControl Plane APIs create and manage services, resources, access rules, rate limits, keys, network controls, alerts, and tenant settings.
Services
POSTPOST /v1/services
GET /v1/services
GET /v1/services/{service_id}
PATCH /v1/services/{service_id}
DELETE /v1/services/{service_id}Resources
POSTPOST /v1/services/{service_id}/resources
GET /v1/services/{service_id}/resources
PATCH /v1/resources/{resource_id}
DELETE /v1/resources/{resource_id}Access Rules
POSTPOST /v1/access-rules
GET /v1/access-rules?service_id=svc_bookstore
GET /v1/access-rules/{rule_id}
PATCH /v1/access-rules/{rule_id}
DELETE /v1/access-rules/{rule_id}Keys
POSTPOST /v1/services/{service_id}/keys/public-client
POST /v1/services/{service_id}/keys/service-api
POST /v1/services/{service_id}/keys/worker
GET /v1/keys
POST /v1/keys/{key_id}/rotate
POST /v1/keys/{key_id}/revokeData Plane Invocation
Client trafficThe data plane receives public or backend traffic, evaluates access rules, creates jobs, and returns a job ID.
Invoke Any Resource
ANYANY /s/{service_slug}/{resource_path...}GET /s/bookstore/book X-ServiceBridge-Client-Key: pk_live_xxx
HTTP/1.1 202 Accepted
{
"job_id": "job_123",
"status": "pending",
"result_url": "/v1/jobs/job_123"
}Rule Evaluation
Runtime order1. Resolve service by slug 2. Check service slug routing 3. Resolve resource path 4. Resolve HTTP method 5. Detect caller type 6. Match access rule 7. Validate credential and scopes 8. Check origin/IP allowlist/blocklist 9. Apply rate limit policy 10. Apply tenant quota 11. Create job
Worker Plane APIs
Private executionWorkers live near private services. They poll ServiceBridge, claim jobs, execute locally, and return results.
Claim Jobs
POSTPOST /v1/services/{service_id}/jobs/claim
Authorization: Bearer wk_live_xxx
{
"worker_id": "worker-book-1",
"limit": 5,
"lease_seconds": 60
}Complete Job
POSTPOST /v1/jobs/{job_id}/complete
Authorization: Bearer wk_live_xxx
{
"status_code": 201,
"headers": { "content-type": "application/json" },
"body": { "book_id": "book_123" }
}Fail Job
POSTPOST /v1/jobs/{job_id}/fail
{
"error_code": "PRIVATE_SERVICE_TIMEOUT",
"message": "Book service did not respond",
"retryable": true
}Get Job Result
GETGET /v1/jobs/{job_id}{
"job_id": "job_123",
"status": "completed",
"status_code": 201,
"body": { "book_id": "book_123" },
"trace_id": "trace_abc"
}Job States
Lifecyclepending claimed processing completed failed expired cancelled dead_letter
Network & DDoS Controls
Defense in depthUpdate Tenant Network Policy
PATCHPATCH /v1/tenant/network-policy
{
"waf_mode": "challenge",
"bot_protection": true,
"tenant_denylist": ["203.0.113.10", "198.51.100.0/24"],
"tenant_global_rpm": 10000
}Create Alert Rule
POSTPOST /v1/alerts
{
"severity": "critical",
"signal": "DLQ jobs",
"condition": "DLQ > 5 for 5m",
"channel": "Slack #ops"
}Recommended Alerts
Minimum viable opsQueue backlog too high DLQ jobs increasing Worker heartbeat missing p95 job completion latency breached Public-client 429 rate spike Service API key nearing expiry Tenant quota nearing limit
Queue, Jobs, and Results Observability
operator workflowInspect Job Runtime State
GETGET /v1/jobs/{job_id}{
"job_id": "job_123",
"status": "completed",
"request": {
"method": "POST",
"route": "/s/ai-chat/chat",
"headers": { "origin": "https://chat.example.com" },
"body": { "message": "Summarize this order" }
},
"response": {
"status_code": 200,
"body": { "answer": "Order summary..." }
},
"events": [
{ "type": "job.accepted" },
{ "type": "job.claimed" },
{ "type": "result.chunk" },
{ "type": "job.completed" }
]
}Subscribe to Result Events
GETGET /v1/jobs/{job_id}/events
Accept: text/event-streamevent: result.chunk
data: {"sequence":42,"delta":"The next step is..."}
event: job.completed
data: {"status_code":200,"trace_id":"trace_ai_abc"}Billing & Usage
credits and sandbox grantsClaim Monthly Sandbox Credit
POSTPOST /api/billing/sandbox-credit/claim
{
"tenantId": "tenant_123"
}
{
"sandboxCredit": {
"amount": 10,
"claimMonth": "2026-07",
"status": "active",
"expiresAt": "2026-07-31T23:59:59.999Z"
}
}Usage API
GETGET /v1/usage?from=2026-07-01&to=2026-07-31
{
"requests": 1200000,
"jobs": 890000,
"storage_gb": 34,
"estimated_total_usd": 53.20
}Error Format
Consistent response model{
"error": {
"code": "NO_MATCHING_ACCESS_RULE",
"message": "No access rule matched GET /book for caller_type=anonymous",
"request_id": "req_abc",
"trace_id": "trace_abc"
}
}Webhook: Job Completed
POST{
"event": "job.completed",
"job_id": "job_123",
"trace_id": "trace_abc",
"status_code": 201,
"created_at": "2026-07-04T12:00:00Z"
}ServiceBridge SDK Overview
Developer productThe ServiceBridge SDK helps developers build job-based integrations without manually implementing polling, leases, retries, completion calls, failure handling, heartbeats, and internal job dispatch. Developers focus on business functions; the SDK adapts those functions into ServiceBridge workers.
Without SDK:
write polling loop
claim jobs
manage leases
route operations
call local functions
serialize responses
complete/fail jobs
heartbeat workers
retry safely
handle shutdown
With SDK:
bridge.on("POST /book", createBook)
bridge.on("generate_invoice_pdf", generatePdf)
bridge.start()Developer SDK
Build worker job handlers quicklyThe SDK lets developers register local functions as ServiceBridge job handlers. It handles polling, claiming, leases, heartbeats, retries, completion, failure, shutdown, and internal job dispatch.
import { ServiceBridgeWorker } from "@servicebridge/node";
const worker = new ServiceBridgeWorker({
serviceId: "svc_bookstore",
workerKey: process.env.WORKER_KEY
});
worker.on("POST /order", async (job, ctx) => {
return createOrder(job.payload);
});
worker.start();Worker SDK
Private servicesRuns beside private services. Polls ServiceBridge, claims jobs, executes handlers, and completes or fails jobs.
Client SDK
Frontend/backend callersInvokes ServiceBridge routes and waits for results. Handles job polling, timeout, cancellation, and result parsing.
Internal Jobs SDK
Service-to-service jobsLets a service enqueue internal jobs to allowed target services using Internal Job Permissions.
SDK Package Layout
SDK@servicebridge/node ServiceBridgeClient // invoke public slug routes and get job results ServiceBridgeWorker // poll, claim, handle, complete jobs InternalJobClient // enqueue internal jobs source→target createExpressAdapter // optional Express integration createFastifyAdapter // optional Fastify integration createNextRouteAdapter // optional Next.js route integration types // Job, Context, AuthContext, Result, Error types
Install
NPMnpm install @servicebridge/node
pnpm add @servicebridge/node
yarn add @servicebridge/node
Worker SDK
Polling adapter for private servicesThe Worker SDK connects a private machine to ServiceBridge. It only needs outbound HTTPS. It claims jobs assigned to a service, calls local handlers, and reports results back to ServiceBridge.
Minimal Worker
CODEimport { ServiceBridgeWorker } from "@servicebridge/node";
const worker = new ServiceBridgeWorker({
serviceId: process.env.SERVICEBRIDGE_SERVICE_ID,
workerKey: process.env.SERVICEBRIDGE_WORKER_KEY,
endpoint: "https://api.servicebridge.com",
workerId: "bookstore-worker-1"
});
worker.on("POST /book", async (job, ctx) => {
const book = await createBook(job.payload);
return {
statusCode: 201,
body: book
};
});
await worker.start();Worker Config
CONFIGconst worker = new ServiceBridgeWorker({
endpoint: "https://api.servicebridge.com",
serviceId: "svc_bookstore",
workerKey: "wk_live_xxx",
workerId: "bookstore-worker-prod-1",
concurrency: 10,
pollIntervalMs: 1000,
maxBatchSize: 5,
leaseSeconds: 60,
heartbeatIntervalMs: 15000,
autoExtendLease: true,
gracefulShutdownTimeoutMs: 30000,
logLevel: "info"
});What the SDK Does Internally
FLOWwhile running:
send heartbeat
claim jobs from /v1/services/{service_id}/jobs/claim
match each job to a registered handler
create execution context
run handler
serialize handler result
POST /v1/jobs/{job_id}/complete
if handler throws:
POST /v1/jobs/{job_id}/fail
if shutdown:
stop claiming new jobs
finish or safely release active jobsJob Handlers
Turn functions into ServiceBridge operationsHandlers map ServiceBridge operations to local code. A handler can represent a slug route such as POST /book or an internal operation such as generate_invoice_pdf.
Route Handler
CODEworker.on("GET /book", async (job, ctx) => {
const books = await bookstore.listBooks({
limit: job.query.limit,
search: job.query.search
});
return {
statusCode: 200,
body: { books }
};
});
worker.on("POST /book", async (job, ctx) => {
ctx.requireScope("book:create");
const book = await bookstore.createBook({
title: job.payload.title,
author: job.payload.author,
createdBy: ctx.auth.user?.sub
});
return {
statusCode: 201,
body: book
};
});Internal Operation Handler
CODEworker.operation("generate_invoice_pdf", async (job, ctx) => {
const pdf = await pdfGenerator.generateInvoice({
orderId: job.payload.order_id,
customerId: job.payload.customer_id,
template: job.payload.template
});
return {
body: {
pdf_id: pdf.id,
pdf_url: pdf.url
}
};
});Error Handling
CODEimport { RetryableError, PermanentError } from "@servicebridge/node";
worker.on("POST /book", async (job, ctx) => {
try {
return await createBook(job.payload);
} catch (err) {
if (err.code === "DB_TIMEOUT") {
throw new RetryableError("Database timeout", {
retryAfterSeconds: 30
});
}
throw new PermanentError("Invalid book payload", {
statusCode: 400,
details: err.message
});
}
});Internal Jobs SDK
Service-to-service async dispatchThe Internal Jobs SDK lets one service enqueue a job to another service without direct network access. ServiceBridge enforces same tenant, source service identity, explicit Internal Job Permission, scopes, rate limits, and queue quotas.
Bookstore Worker Enqueues PDF Job
CODEimport { InternalJobClient } from "@servicebridge/node";
const internalJobs = new InternalJobClient({
endpoint: "https://api.servicebridge.com",
serviceKey: process.env.BOOKSTORE_SERVICE_API_KEY
});
worker.on("POST /order", async (job, ctx) => {
const order = await bookstore.createOrder(job.payload);
const pdfJob = await internalJobs.enqueue({
targetServiceId: "svc_pdf_generator",
operation: "generate_invoice_pdf",
payload: {
order_id: order.id,
customer_id: order.customerId,
template: "invoice_v1"
},
idempotencyKey: `invoice:${order.id}`
});
return {
statusCode: 201,
body: {
order_id: order.id,
invoice_job_id: pdfJob.jobId,
invoice_status: "generating"
}
};
});Equivalent Raw API
POSTPOST /v1/internal/jobs
Authorization: Bearer sk_live_bookstore_service
Idempotency-Key: invoice:order_789
{
"target_service_id": "svc_pdf_generator",
"operation": "generate_invoice_pdf",
"payload": {
"order_id": "order_789",
"customer_id": "cust_456",
"template": "invoice_v1"
}
}Wait for Internal Job Result
CODEconst pdfJob = await internalJobs.enqueue({
targetServiceId: "svc_pdf_generator",
operation: "generate_invoice_pdf",
payload: { order_id: order.id }
});
const result = await internalJobs.waitForResult(pdfJob.jobId, {
timeoutMs: 120000,
pollIntervalMs: 2000
});
await bookstore.attachInvoice(order.id, result.body.pdf_url);Internal Permission Required
CONFIG{
"source_service_id": "svc_bookstore",
"target_service_id": "svc_pdf_generator",
"operation": "generate_invoice_pdf",
"required_scopes": ["pdf:generate"],
"rate_limit_policy": "internal_pdf_generation",
"max_pending_jobs": 5000
}SDK Demo Strategy
Five progressive implementationsThese SDK demos mirror the API use cases. Each level adds one capability so developers can adopt ServiceBridge gradually: first a simple worker, then authenticated users, then internal jobs, then multi-service orchestration, then production-grade worker operations.
Level 1 SDK: Simple Public Catalog Worker
CODEA private bookstore worker handles public catalog reads. The developer only writes the business function; the SDK handles polling, claiming, completion, failure, and heartbeats.
import { ServiceBridgeWorker } from "@servicebridge/node";
import { books } from "./bookstore-db";
const worker = new ServiceBridgeWorker({
endpoint: process.env.SERVICEBRIDGE_ENDPOINT,
serviceId: "svc_bookstore",
workerKey: process.env.BOOKSTORE_WORKER_KEY,
workerId: "bookstore-catalog-worker-1",
concurrency: 10
});
worker.on("GET /book", async (job, ctx) => {
const result = await books.search({
search: job.query.search,
limit: Number(job.query.limit || 20)
});
return {
statusCode: 200,
body: { books: result }
};
});
await worker.start();Level 2 SDK: Authenticated Cart and Order Actions
CODEServiceBridge validates the JWT at ingress. The worker receives normalized auth_context and can enforce application-level business rules using ctx.requireScope().
worker.on("POST /cart", async (job, ctx) => {
ctx.requireScope("cart:create");
const cart = await carts.create({
userId: ctx.auth.user.sub,
items: job.payload.items
});
return {
statusCode: 201,
body: cart
};
});
worker.on("POST /order", async (job, ctx) => {
ctx.requireScope("order:create");
const order = await orders.createDraft({
userId: ctx.auth.user.sub,
cartId: job.payload.cart_id
});
return {
statusCode: 202,
body: {
order_id: order.id,
status: "processing"
}
};
});{
"callerType": "frontend_user",
"user": {
"sub": "user_456",
"scopes": ["cart:create", "order:create"],
"roles": ["customer"],
"email": "customer@example.com"
},
"matchedAccessRuleId": "rule_customer_create_order"
}Level 3 SDK: Enqueue Internal PDF Job
CODEThe Bookstore worker creates an order and enqueues a PDF job. The PDF worker is on another machine and does not need a public endpoint.
import {
ServiceBridgeWorker,
InternalJobClient
} from "@servicebridge/node";
const worker = new ServiceBridgeWorker({
endpoint: process.env.SERVICEBRIDGE_ENDPOINT,
serviceId: "svc_bookstore",
workerKey: process.env.BOOKSTORE_WORKER_KEY
});
const internalJobs = new InternalJobClient({
endpoint: process.env.SERVICEBRIDGE_ENDPOINT,
serviceKey: process.env.BOOKSTORE_SERVICE_API_KEY
});
worker.on("POST /order", async (job, ctx) => {
ctx.requireScope("order:create");
const order = await orders.confirm({
userId: ctx.auth.user.sub,
cartId: job.payload.cart_id
});
const invoice = await internalJobs.enqueue({
targetServiceId: "svc_pdf_generator",
operation: "generate_invoice_pdf",
payload: {
order_id: order.id,
customer_id: order.customerId,
template: "invoice_v1"
},
idempotencyKey: `invoice:${order.id}`,
parentJobId: job.id,
traceId: ctx.traceId
});
return {
statusCode: 201,
body: {
order_id: order.id,
status: "confirmed",
invoice_status: "generating",
invoice_job_id: invoice.jobId
}
};
});
await worker.start();const pdfWorker = new ServiceBridgeWorker({
endpoint: process.env.SERVICEBRIDGE_ENDPOINT,
serviceId: "svc_pdf_generator",
workerKey: process.env.PDF_WORKER_KEY,
workerId: "pdf-worker-1",
concurrency: 4
});
pdfWorker.operation("generate_invoice_pdf", async (job, ctx) => {
const pdf = await renderInvoicePdf(job.payload);
const uploaded = await storage.upload(pdf);
return {
body: {
pdf_url: uploaded.url,
pdf_id: uploaded.id
}
};
});
await pdfWorker.start();Level 4 SDK: Multi-Service Order Orchestration
CODEA realistic order workflow fans out to inventory, payment, PDF, and notification services. Each internal call is checked by Internal Job Permissions.
worker.on("POST /order", async (job, ctx) => {
ctx.requireScope("order:create");
const order = await orders.createPending({
userId: ctx.auth.user.sub,
items: job.payload.items
});
const inventoryJob = await internalJobs.enqueue({
targetServiceId: "svc_inventory",
operation: "reserve_stock",
payload: {
order_id: order.id,
items: job.payload.items
},
idempotencyKey: `reserve:${order.id}`,
parentJobId: job.id,
traceId: ctx.traceId
});
const paymentJob = await internalJobs.enqueue({
targetServiceId: "svc_payment",
operation: "authorize_payment",
payload: {
order_id: order.id,
amount: order.total,
currency: "USD",
payment_method_id: job.payload.payment_method_id
},
idempotencyKey: `payment:${order.id}`,
parentJobId: job.id,
traceId: ctx.traceId
});
return {
statusCode: 202,
body: {
order_id: order.id,
status: "processing",
jobs: {
inventory: inventoryJob.jobId,
payment: paymentJob.jobId
}
}
};
});// When payment and inventory complete,
// ServiceBridge workflow or Bookstore worker can enqueue:
await internalJobs.enqueue({
targetServiceId: "svc_notification",
operation: "send_order_confirmation",
payload: {
order_id: order.id,
email: ctx.auth.user.email
},
idempotencyKey: `confirmation:${order.id}`
});Level 5 SDK: Production Worker Runtime
CODEThe production worker config adds concurrency, leases, retries, graceful shutdown, idempotency, structured logs, tracing, and schema validation.
import { z } from "zod";
import {
ServiceBridgeWorker,
RetryableError,
PermanentError
} from "@servicebridge/node";
const CreateOrder = z.object({
items: z.array(z.object({
sku: z.string(),
quantity: z.number().int().positive()
})),
payment_method_id: z.string()
});
const worker = new ServiceBridgeWorker({
endpoint: process.env.SERVICEBRIDGE_ENDPOINT,
serviceId: "svc_bookstore",
workerKey: process.env.BOOKSTORE_WORKER_KEY,
workerId: process.env.HOSTNAME,
concurrency: 20,
maxBatchSize: 10,
leaseSeconds: 90,
autoExtendLease: true,
heartbeatIntervalMs: 15000,
handlerTimeoutMs: 60000,
gracefulShutdownTimeoutMs: 30000,
retryPolicy: {
initialDelayMs: 1000,
maxDelayMs: 60000,
multiplier: 2,
jitter: true
}
});
worker.use(async (job, ctx, next) => {
ctx.logger.info({
trace_id: ctx.traceId,
job_id: job.id,
operation: job.operation || `${job.method} ${job.path}`
}, "job_started");
return next();
});
worker.on("POST /order", async (job, ctx) => {
const input = CreateOrder.parse(job.payload);
try {
return await createOrderWorkflow(input, ctx);
} catch (err) {
if (err.code === "PAYMENT_TIMEOUT") {
throw new RetryableError("Payment provider timeout", {
retryAfterSeconds: 30
});
}
throw new PermanentError("Order creation failed", {
statusCode: 400,
details: err.message
});
}
});
await worker.start();AI Chat SDK Example: Agent Worker with Tool Fan-Out
CODEconst agentWorker = new ServiceBridgeWorker({
endpoint: process.env.SERVICEBRIDGE_ENDPOINT,
serviceId: "svc_agent_orchestrator",
workerKey: process.env.AGENT_WORKER_KEY,
concurrency: 8
});
const internalJobs = new InternalJobClient({
endpoint: process.env.SERVICEBRIDGE_ENDPOINT,
serviceKey: process.env.AGENT_SERVICE_API_KEY
});
agentWorker.operation("run_agent_turn", async (job, ctx) => {
const ragJob = await internalJobs.enqueue({
targetServiceId: "svc_rag",
operation: "retrieve_context",
payload: {
conversation_id: job.payload.conversation_id,
query: job.payload.prompt
},
parentJobId: job.id,
traceId: ctx.traceId
});
const webJob = await internalJobs.enqueue({
targetServiceId: "svc_web_search",
operation: "web_search",
payload: {
query: job.payload.prompt,
max_results: 5
},
parentJobId: job.id,
traceId: ctx.traceId
});
const rag = await internalJobs.waitForResult(ragJob.jobId);
const web = await internalJobs.waitForResult(webJob.jobId);
const llmJob = await internalJobs.enqueue({
targetServiceId: "svc_llm",
operation: "generate_response",
payload: {
prompt: job.payload.prompt,
context: rag.body.documents,
web_results: web.body.results,
stream: true,
result_channel_id: job.result_channel_id
},
parentJobId: job.id,
traceId: ctx.traceId
});
return {
body: {
status: "answer_generating",
llm_job_id: llmJob.jobId
}
};
});SDK Reliability Features
Production behaviorThe SDK should implement correct job execution behavior by default so developers do not accidentally create duplicate side effects, stuck jobs, or broken shutdown paths.
Reliability Config
CONFIGconst worker = new ServiceBridgeWorker({
serviceId: "svc_bookstore",
workerKey: process.env.WORKER_KEY,
concurrency: 10,
leaseSeconds: 60,
autoExtendLease: true,
handlerTimeoutMs: 45000,
maxHandlerRetries: 3,
retryPolicy: {
initialDelayMs: 1000,
maxDelayMs: 60000,
multiplier: 2,
jitter: true
},
deadLetterOnPermanentError: true,
gracefulShutdownTimeoutMs: 30000
});Idempotent Handler Example
CODEworker.operation("generate_invoice_pdf", async (job, ctx) => {
const existing = await db.invoices.findByIdempotencyKey(ctx.idempotencyKey);
if (existing) {
return { body: existing };
}
const pdf = await generatePdf(job.payload);
await db.invoices.insert({
idempotencyKey: ctx.idempotencyKey,
orderId: job.payload.order_id,
pdfUrl: pdf.url
});
return { body: { pdf_url: pdf.url } };
});SDK Security Model
Safe defaultsThe SDK should make the secure path easy. It should never ask developers to manually trust caller-supplied service IDs, raw JWTs, or unverified source identities.
Worker Key Scope
KEY{
"key_type": "worker",
"tenant_id": "tenant_123",
"service_id": "svc_pdf_generator",
"permissions": [
"jobs:claim",
"jobs:complete",
"jobs:fail",
"heartbeat:write"
]
}Accessing auth_context
CODEworker.on("POST /book", async (job, ctx) => {
// This was validated by ServiceBridge at ingress
const userId = ctx.auth.user.sub;
const scopes = ctx.auth.user.scopes;
ctx.requireScope("book:create");
return createBook({
...job.payload,
createdBy: userId
});
});SDK API Reference
Proposed TypeScript interfaceThis is the proposed public API for the Node SDK. Other languages should keep equivalent concepts.
ServiceBridgeWorker
TYPEclass ServiceBridgeWorker {
constructor(config: WorkerConfig)
on(route: string, handler: RouteJobHandler): void
operation(name: string, handler: OperationJobHandler): void
use(middleware: WorkerMiddleware): void
start(): Promise
stop(options?: StopOptions): Promise
heartbeat(): Promise
claim(): Promise
complete(jobId: string, result: JobResult): Promise
fail(jobId: string, error: JobError): Promise
} InternalJobClient
TYPEclass InternalJobClient {
constructor(config: {
endpoint: string
serviceKey: string
})
enqueue(input: {
targetServiceId: string
operation: string
payload: unknown
idempotencyKey?: string
priority?: "low" | "normal" | "high"
delayUntil?: string
parentJobId?: string
traceId?: string
}): Promise<{ jobId: string; status: "pending" }>
getResult(jobId: string): Promise
waitForResult(
jobId: string,
options?: {
timeoutMs?: number
pollIntervalMs?: number
}
): Promise
} ServiceBridgeClient
TYPEclass ServiceBridgeClient {
constructor(config: {
endpoint: string
serviceSlug: string
publicClientKey?: string
serviceKey?: string
getUserToken?: () => Promise | string
})
get(path: string, options?: RequestOptions): Promise
post(path: string, body?: unknown, options?: RequestOptions): Promise
put(path: string, body?: unknown, options?: RequestOptions): Promise
patch(path: string, body?: unknown, options?: RequestOptions): Promise
delete(path: string, options?: RequestOptions): Promise
getResult(jobId: string): Promise
waitForResult(jobId: string, options?: WaitOptions): Promise
cancel(jobId: string): Promise
} Types
TYPEtype Job = {
id: string
tenantId: string
targetServiceId: string
sourceServiceId?: string
method?: string
path?: string
operation?: string
payload: unknown
query: Record
headers: Record
authContext: AuthContext
traceId: string
idempotencyKey?: string
}
type AuthContext = {
callerType: "public_client" | "frontend_user" | "service_api" | "worker"
publicClientKeyId?: string
serviceKeyId?: string
jwtProviderId?: string
user?: {
sub: string
issuer: string
audience: string
scopes: string[]
roles?: string[]
email?: string
}
matchedAccessRuleId?: string
}
type JobResult = {
statusCode?: number
headers?: Record
body?: unknown
} ServiceBridge CLI Overview
sbctlThe ServiceBridge CLI, proposed as sbctl, lets developers and machines provision ServiceBridge deterministically. It is the control-plane automation product for creating services, resources, access rules, IAM providers, internal job permissions, rate limits, worker groups, alerts, network policies, and tenant automation keys.
Declarative
YAML desired stateDefine the full ServiceBridge tenant configuration in servicebridge.yaml.
Deterministic
Plan/applyPreview changes, detect drift, and apply the exact intended config.
Automatable
CI/CD friendlyUse tenant automation keys in GitHub Actions, GitLab CI, Jenkins, or shell scripts.
CLI Quickstart
CLInpm install -g @servicebridge/cli export SERVICEBRIDGE_TENANT_KEY=tk_live_xxx sbctl whoami sbctl init bookstore sbctl validate -f servicebridge.yaml sbctl plan -f servicebridge.yaml sbctl apply -f servicebridge.yaml
What the CLI Manages
SCOPEservices resources method access rules rate limit policies public client keys service API keys worker keys tenant automation keys IAM / JWT providers internal job permissions network and DDoS policy worker groups alerts billing usage reads environment promotion
Tenant Automation Keys
Machine access for the control planeTenant automation keys authenticate the CLI and CI/CD systems. These keys are different from public client keys, service API keys, and worker keys. They are allowed to manage tenant configuration, not invoke business routes or claim jobs.
Create Tenant Automation Key
POSTPOST /v1/tenant/automation-keys
Authorization: Bearer tenant_admin_token
{
"name": "github-actions-prod",
"environment": "prod",
"scopes": [
"tenant:read",
"services:write",
"resources:write",
"access_rules:write",
"rate_limits:write",
"iam_providers:write",
"internal_permissions:write",
"network:write",
"alerts:write"
],
"allowed_ips": ["203.0.113.20/32"],
"expires_at": "2027-01-01T00:00:00Z"
}{
"key_id": "tak_123",
"prefix": "tk_live_github_prod",
"secret": "tk_live_github_prod_7wUj...",
"warning": "This secret is shown only once. Store it in your CI secret manager."
}Tenant Automation Key Enforcement
FLOW1. Validate tk_live key hash 2. Derive tenant_id from key 3. Reject if expired or revoked 4. Check optional IP allowlist 5. Check requested control-plane scope 6. Apply tenant automation rate limit 7. Audit every create/update/delete 8. Execute config mutation or dry-run plan
Install & Authenticate
Developer and machine setupThe CLI should support local developer login, environment variables, and non-interactive CI/CD authentication.
Install
NPMnpm install -g @servicebridge/cli # or brew install servicebridge/tap/sbctl # or curl -fsSL https://install.servicebridge.com | sh
Local Developer Auth
CLIsbctl login # Opens browser OAuth login # Stores a short-lived developer session locally # Useful for humans, not CI/CD
Machine / CI Auth
CLIexport SERVICEBRIDGE_TENANT_KEY=tk_live_xxx sbctl whoami
sbctl config set endpoint https://api.servicebridge.com sbctl config set tenant-key tk_live_xxx sbctl whoami
YAML Configuration
servicebridge.yamlThe CLI should support a declarative YAML file as the primary IaC format. YAML is readable, reviewable in pull requests, and easy to generate from scripts.
Recommended File Structure
YAMLapiVersion: servicebridge.io/v1
kind: TenantConfig
metadata:
name: bookstore-prod
environment: prod
spec:
iamProviders: []
rateLimitPolicies: []
services: []
internalJobPermissions: []
networkPolicy: {}
alerts: []Full Bookstore YAML
YAMLapiVersion: servicebridge.io/v1
kind: TenantConfig
metadata:
name: bookstore-prod
environment: prod
spec:
iamProviders:
- name: bookstore-auth
type: oidc
issuer: https://auth.bookstore.com/
discoveryUrl: https://auth.bookstore.com/.well-known/openid-configuration
jwksUri: https://auth.bookstore.com/.well-known/jwks.json
audiences:
- bookstore-api
allowedAlgorithms:
- RS256
claimMapping:
subject: sub
scope: scope
roles: https://bookstore.com/roles
tenant: https://bookstore.com/tenant_id
email: email
rateLimitPolicies:
- name: public_get_strict
limit: 120
window: 1m
burst: 20
dimensions:
- public_client_key_id
- ip_address
- origin
- resource_id
- method
- name: frontend_write_strict
limit: 30
window: 1m
burst: 5
dimensions:
- public_client_key_id
- user_id
- ip_address
- resource_id
- method
- name: internal_pdf_generation
limit: 600
window: 1m
burst: 100
dimensions:
- tenant_id
- source_service_id
- target_service_id
- operation
services:
- name: Book Store
slug: bookstore
slugRouting: "Slug Enabled"
resources:
- path: /book
version: v1
methods:
- GET
- POST
- PUT
- PATCH
- DELETE
accessRules:
- name: Public Book Read
method: GET
callerType: public_client
authMode: public_client_token
rateLimitPolicy: public_get_strict
allowedOrigins:
- https://bookstore.com
- name: Frontend Book Create
method: POST
callerType: frontend_user
authMode: public_client_plus_user_token
jwtProvider: bookstore-auth
requiredScopes:
- book:create
rateLimitPolicy: frontend_write_strict
allowedOrigins:
- https://bookstore.com
- name: PDF Generator
slug: pdf-generator
slugRouting: "No slug: internal jobs"
operations:
- generate_invoice_pdf
- generate_receipt_pdf
internalJobPermissions:
- sourceService: Book Store
targetService: PDF Generator
operation: generate_invoice_pdf
requiredScopes:
- pdf:generate
rateLimitPolicy: internal_pdf_generation
maxPendingJobs: 5000
networkPolicy:
wafMode: challenge
botProtection: true
tenantGlobalRpm: 10000
alerts:
- severity: critical
signal: DLQ jobs
condition: DLQ > 5 for 5m
channel: Slack #opsCLI Commands
Command surfaceThe CLI should support both declarative IaC commands and direct imperative commands for quick scripting.
Plan Output Example
CLIsbctl plan -f servicebridge.yaml Plan: + create iamProvider bookstore-auth + create rateLimit public_get_strict + create service Book Store + create resource Book Store /book + create accessRule Public Book Read + create service PDF Generator + create internalJobPermission Book Store → PDF Generator generate_invoice_pdf ~ update networkPolicy wafMode: monitor → challenge No destructive changes. Run sbctl apply -f servicebridge.yaml to apply.
Imperative Scripting Example
BASH#!/usr/bin/env bash set -euo pipefail export SERVICEBRIDGE_TENANT_KEY="$SB_TENANT_KEY" sbctl services create \ --name "Book Store" \ --slug bookstore \ --slug-enabled true sbctl resources create \ --service bookstore \ --path /book \ --methods GET,POST,PUT,PATCH,DELETE sbctl apply -f servicebridge.yaml
CLI Demo Strategy
Five provisioning examplesThese CLI demos show how teams move from a single public endpoint to a production multi-service e-commerce configuration managed by YAML, tenant automation keys, plan/apply, and CI/CD.
Level 1 CLI: Provision Public Catalog
YAMLapiVersion: servicebridge.io/v1
kind: TenantConfig
metadata:
name: bookstore-level-1
environment: dev
spec:
rateLimitPolicies:
- name: public_get_strict
limit: 120
window: 1m
burst: 20
dimensions:
- public_client_key_id
- ip_address
- origin
- resource_id
- method
services:
- name: Book Store
slug: bookstore
slugRouting: "Slug Enabled"
resources:
- path: /book
version: v1
methods: [GET]
accessRules:
- name: Public Catalog Read
method: GET
callerType: public_client
authMode: public_client_token
rateLimitPolicy: public_get_strict
allowedOrigins:
- https://bookstore.comsbctl validate -f servicebridge.level1.yaml sbctl plan -f servicebridge.level1.yaml sbctl apply -f servicebridge.level1.yaml
Level 2 CLI: Add IAM and Authenticated Customer Actions
YAMLspec:
iamProviders:
- name: bookstore-auth
type: oidc
issuer: https://auth.bookstore.com/
jwksUri: https://auth.bookstore.com/.well-known/jwks.json
audiences: [bookstore-api]
allowedAlgorithms: [RS256]
claimMapping:
subject: sub
scope: scope
roles: https://bookstore.com/roles
email: email
services:
- name: Book Store
slug: bookstore
slugRouting: "Slug Enabled"
resources:
- path: /cart
methods: [POST]
accessRules:
- name: Customer Create Cart
method: POST
callerType: frontend_user
authMode: public_client_plus_user_token
jwtProvider: bookstore-auth
requiredScopes: [cart:create]
rateLimitPolicy: frontend_write_strict
- path: /order
methods: [POST]
accessRules:
- name: Customer Create Order
method: POST
callerType: frontend_user
authMode: public_client_plus_user_token
jwtProvider: bookstore-auth
requiredScopes: [order:create]
rateLimitPolicy: frontend_write_strictLevel 3 CLI: Add Internal PDF Generator
YAMLspec:
services:
- name: Book Store
slug: bookstore
slugRouting: "Slug Enabled"
- name: PDF Generator
slug: pdf-generator
slugRouting: "No slug: internal jobs"
operations:
- generate_invoice_pdf
- generate_receipt_pdf
rateLimitPolicies:
- name: internal_pdf_generation
limit: 600
window: 1m
burst: 100
dimensions:
- tenant_id
- source_service_id
- target_service_id
- operation
internalJobPermissions:
- sourceService: Book Store
targetService: PDF Generator
operation: generate_invoice_pdf
requiredScopes: [pdf:generate]
rateLimitPolicy: internal_pdf_generation
maxPendingJobs: 5000Level 4 CLI: Multi-Service E-Commerce Workflow
YAMLspec:
services:
- name: Book Store
slug: bookstore
slugRouting: "Slug Enabled"
- name: Inventory Service
slug: inventory
slugRouting: "No slug: internal jobs"
operations: [reserve_stock, release_stock]
- name: Payment Service
slug: payment
slugRouting: "No slug: internal jobs"
operations: [authorize_payment, capture_payment, refund_payment]
- name: PDF Generator
slug: pdf-generator
slugRouting: "No slug: internal jobs"
operations: [generate_invoice_pdf]
- name: Notification Service
slug: notification
slugRouting: "No slug: internal jobs"
operations: [send_order_confirmation, send_refund_notice]
internalJobPermissions:
- sourceService: Book Store
targetService: Inventory Service
operation: reserve_stock
requiredScopes: [inventory:reserve]
rateLimitPolicy: internal_inventory
- sourceService: Book Store
targetService: Payment Service
operation: authorize_payment
requiredScopes: [payment:authorize]
rateLimitPolicy: internal_payment
- sourceService: Book Store
targetService: PDF Generator
operation: generate_invoice_pdf
requiredScopes: [pdf:generate]
rateLimitPolicy: internal_pdf_generation
- sourceService: Book Store
targetService: Notification Service
operation: send_order_confirmation
requiredScopes: [notification:send]
rateLimitPolicy: internal_notificationLevel 5 CLI: Production GitOps Rollout
YAML# .github/workflows/servicebridge-prod.yml
name: ServiceBridge Production Apply
on:
push:
branches: [main]
paths:
- servicebridge.yaml
jobs:
servicebridge:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- run: npm install -g @servicebridge/cli
- name: Validate
run: sbctl validate -f servicebridge.yaml --env prod
env:
SERVICEBRIDGE_TENANT_KEY: ${{ secrets.SERVICEBRIDGE_TENANT_KEY }}
- name: Plan
run: sbctl plan -f servicebridge.yaml --env prod --format json > plan.json
env:
SERVICEBRIDGE_TENANT_KEY: ${{ secrets.SERVICEBRIDGE_TENANT_KEY }}
- name: Apply
run: sbctl apply -f servicebridge.yaml --env prod --non-interactive
env:
SERVICEBRIDGE_TENANT_KEY: ${{ secrets.SERVICEBRIDGE_TENANT_KEY }}{
"name": "github-actions-prod",
"environment": "prod",
"scopes": [
"tenant:read",
"services:write",
"resources:write",
"access_rules:write",
"rate_limits:write",
"iam_providers:write",
"internal_permissions:write",
"network:write",
"alerts:write"
],
"allowed_ips": ["203.0.113.20/32"],
"expires_at": "2027-01-01T00:00:00Z"
}CI/CD & GitOps
Apply from pipelinesThe CLI is designed for pull-request reviewed infrastructure changes. Developers change YAML, CI validates and plans, then production apply happens after approval.
GitHub Actions Example
YAMLname: ServiceBridge Apply
on:
push:
branches: [main]
paths:
- servicebridge.yaml
jobs:
apply:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ServiceBridge CLI
run: npm install -g @servicebridge/cli
- name: Validate
run: sbctl validate -f servicebridge.yaml
env:
SERVICEBRIDGE_TENANT_KEY: ${{ secrets.SERVICEBRIDGE_TENANT_KEY }}
- name: Plan
run: sbctl plan -f servicebridge.yaml --env prod
env:
SERVICEBRIDGE_TENANT_KEY: ${{ secrets.SERVICEBRIDGE_TENANT_KEY }}
- name: Apply
run: sbctl apply -f servicebridge.yaml --env prod --non-interactive
env:
SERVICEBRIDGE_TENANT_KEY: ${{ secrets.SERVICEBRIDGE_TENANT_KEY }}Recommended PR Workflow
FLOWpull request: sbctl validate sbctl plan comment plan output on PR merge to main: sbctl apply --non-interactive production: require approval for destructive changes require tenant automation key with IP allowlist audit every apply
CLI Security
Provisioning safelyA tenant automation key can change production configuration. Treat it as a powerful control-plane credential.
Least-Privilege Key for CI
JSON{
"name": "github-actions-prod",
"environment": "prod",
"scopes": [
"tenant:read",
"services:write",
"resources:write",
"access_rules:write",
"rate_limits:write",
"iam_providers:write",
"internal_permissions:write"
],
"denied_scopes": [
"keys:write",
"billing:write"
],
"allowed_ips": ["203.0.113.20/32"],
"expires_at": "2027-01-01T00:00:00Z"
}CLI Reference
Proposed command referenceThe CLI should offer a compact command surface for both declarative and imperative workflows.
Global Options
CLIsbctl [command] [options] Global options: --endpointServiceBridge API endpoint --tenant-key Tenant automation key --env Environment name --format json|table|yaml Output format --non-interactive Disable prompts --yes Auto-confirm safe prompts --debug Verbose debug logs
Declarative Commands
CLIsbctl init [name] sbctl validate -f servicebridge.yaml sbctl plan -f servicebridge.yaml sbctl apply -f servicebridge.yaml sbctl diff -f servicebridge.yaml sbctl export --env prod sbctl destroy -f servicebridge.yaml --confirm
Imperative Commands
CLIsbctl services list sbctl services create --name "Book Store" --slug bookstore sbctl resources create --service bookstore --path /book --methods GET,POST sbctl rules create --service bookstore --path /book --method GET --caller public_client sbctl iam create --issuer https://auth.bookstore.com/ sbctl internal-permissions create --source bookstore --target pdf-generator --operation generate_invoice_pdf sbctl keys create tenant-automation --name github-actions-prod sbctl jobs tail --service bookstore sbctl workers list
Services
Slug routing only controls whether the /s/{slug}/... namespace exists. It is not endpoint authorization. Endpoint authorization belongs in access rules.
| Name | Slug | Slug Routing | Base URL | Status | Actions |
|---|
Resources
Resources define paths and methods. They do not decide who can call them. That is now handled by Method Access Rules.
| Service | Path | Version | Methods | Status | Actions |
|---|
Method Access Rules
Multiple rules can exist for the same method. Example: GET /book can have a public-client rule with strict limits and a service-API rule with higher limits.
| Rule | Route | Caller Type | Auth Mode | Rate Limit | Scopes | Origin/IP Policy | Priority | Actions |
|---|
Rule Matrix
This view explains the effective access model per resource and method. Use it to audit whether public, frontend-user, and service-api access are separated properly.
Rate Limits
Rate limits are applied by access rule. Public client rules should include IP and origin dimensions. Service API rules can be looser and should often include IP allowlists.
| Name | Limit | Window | Burst | Dimensions | Best For | Actions |
|---|
Access Keys
Keys identify caller type. Public client keys are copyable and should never be treated as real user authentication.
| Type | Name | Prefix | Tenant / Service | Scope | Allowed Origins/IPs | Status | Actions |
|---|
IAM / JWT Providers
Configure how ServiceBridge validates user JWTs from any IAM provider before creating jobs. This lets frontend-user access rules enforce issuer, audience, scopes, roles, and tenant boundaries at ingress.
JWT Validation Pipeline
Ingress authorizationRequest contains public client key plus user JWT.
Use tenant/service/access-rule configuration to choose issuer and JWKS.
Verify signature, kid, alg, issuer, audience, expiry, nbf, and claims.
Check required scopes/roles before job creation.
Store normalized user identity and authorization decision on the job.
JWT Test Console
Mock validatorRun mock JWT validation.
| Name | Issuer | Audience | JWKS URI | Algorithms | Claim Mapping | Mapped Services | Status | Actions |
|---|
Internal Job Permissions
Control which source service can enqueue which operation on which internal target service. Same-tenant is required, but same-tenant alone is not enough — every internal call needs an explicit permission.
Internal Job Enforcement
Source → target authorization1. Validate service API key 2. Derive tenant_id from key 3. Derive source_service_id from key 4. Read target_service_id and operation from body 5. Check target service belongs to same tenant 6. Check target accepts internal jobs 7. Check Internal Job Permission exists 8. Check required scopes 9. Apply internal rate limit 10. Apply target queue quota 11. Create job
Internal Enqueue Simulator
Mock authorizationRun internal job simulation.
| Source Service | Target Service | Operation | Required Scopes | Rate Limit | Max Pending | Status | Actions |
|---|
Tenant Automation Keys
Machine-level control-plane keys used by the ServiceBridge CLI, CI/CD pipelines, and infrastructure scripts. These keys can create services, resources, access rules, IAM providers, internal job permissions, rate limits, and other tenant configuration deterministically.
Recommended Key Type
Control plane automationkey_type: tenant_automation prefix: tk_live_... used_by: - ServiceBridge CLI - CI/CD pipelines - Terraform-style scripts - GitOps deploys
Scope Model
Least privilegetenant:read services:write resources:write access_rules:write rate_limits:write iam_providers:write internal_permissions:write keys:write network:write alerts:write
Security Controls
Strongly recommendedshow secret once store hash only optional IP allowlist expiry date rotation audit logs dry-run support approval required for destructive apply
CLI Auth Preview
Environment variableexport SERVICEBRIDGE_TENANT_KEY=tk_live_xxx sbctl whoami sbctl apply -f servicebridge.yaml
Permission Check Simulator
Mock authorizationSelect a key and action.
| Name | Prefix | Environment | Scopes | Allowed IPs | Expires | Status | Actions |
|---|
E-Commerce Sanity Test
End-to-end product setup test for a realistic e-commerce client using ServiceBridge. This page verifies that the UI has the right objects, fields, and flows to configure public pages, authenticated customer actions, internal workers, payment services, PDF generation, notifications, CLI provisioning, and production controls.
Target E-Commerce Architecture
Client goalPublic website: GET /book GET /catalog GET /product/:id Authenticated customer: POST /cart POST /order GET /order/:id Internal services: Inventory Service Payment Service PDF Generator Notification Service Fulfillment Service Automation: SDK workers CLI YAML Tenant automation key CI/CD plan → apply
Object Model Verdict
What must existRequired objects: Service Resource Access Rule Rate Limit Policy IAM/JWT Provider Access Key Internal Operation Internal Job Permission Worker Group Tenant Automation Key Network Policy Alert Rule Required enforcement: JWT validation at ingress source service derived from service key same-tenant check explicit source→target→operation permission route-level caller type matching
Step 1 — Public pages and product catalog
Step 2 — Customer login and JWT-authenticated actions
Step 3 — Internal payment, inventory, PDF, notification jobs
Step 4 — Worker runtime setup
Step 5 — Production provisioning and operations
Commerce Scenario Data Model
Applied by buttonSlug-Enabled Service
Book Store slug routing: enabled routes: GET /book GET /catalog POST /cart POST /order
Internal Services
Inventory Service Payment Service PDF Generator Notification Service Fulfillment Service slug routing: disabled; internal jobs only
Internal Permissions
Book Store → Inventory.reserve_stock Book Store → Payment.authorize_payment Book Store → PDF.generate_invoice_pdf Book Store → Notification.send_order_confirmation Book Store → Fulfillment.create_shipment
Commerce Scenario YAML
AI Chatbot Sanity Test
End-to-end setup test for an AI chatbot product using ServiceBridge as the relayer. The frontend uses Google login/JWT, sends prompts as jobs, Agent workers claim jobs, and tool workers perform RAG, web search, MCP/product search, memory, and model inference through internal job permissions.
Target AI Chat Architecture
Client goalFrontend: Google login JWT received POST /s/ai-chat/chat subscribe to result stream Slug-Enabled Service: AI Chat API Internal Services: Agent Orchestrator RAG Retrieval Web Search Tool MCP Product Search Memory Service LLM Inference Runtime: prompt job tool jobs result chunks final answer
Sanity Verdict
Patched modelRequired additions: Result Channels conversation_id / message_id in payload parent_job_id / trace_id for tool jobs internal tool permissions token/user rate limits AI worker keys tool worker keys streaming chunk events Status: UI can now configure all critical pieces.
End-to-End Flow
Google JWT → chat job → agent → tools → streamed answerStep 1 — Google login and JWT validation
Step 2 — Chat prompt as slug-routed job
Step 3 — Agent worker fans out to tool workers
Step 4 — Result streaming and final response
Step 5 — Production controls
AI Chat Scenario YAML
ServiceBridge CLI / IaC
Provision ServiceBridge deterministically from YAML. Developers can define services, resources, access rules, IAM providers, internal job permissions, rate limits, tenant automation keys, workers, alerts, and network policy in source control.
CLI Flow
Infrastructure as configurationUse a tenant automation key locally or inside CI/CD.
Write servicebridge.yaml with services, resources, rules, IAM, and internal permissions.
Check schema, missing references, invalid scopes, and destructive operations.
Preview create/update/delete changes before applying.
Idempotently converge ServiceBridge to the desired config.
Quickstart
Bookstore examplenpm install -g @servicebridge/cli export SERVICEBRIDGE_TENANT_KEY=tk_live_xxx sbctl whoami sbctl init bookstore sbctl validate -f servicebridge.yaml sbctl plan -f servicebridge.yaml sbctl apply -f servicebridge.yaml
Generated YAML Preview
YAMLservicebridge.yaml
Network & DDoS Controls
Application rate limits are not real DDoS protection by themselves. Use edge/WAF controls, bot protection, IP deny lists, and service-key IP allowlists.
Tenant Network Policy
Mock editableDDoS Readiness
not checkedWorkers
Workers poll and execute jobs after the data plane accepts requests.
| Worker | Service | Heartbeat | Concurrency | Status | Actions |
|---|
Queue & Jobs
Monitor accepted jobs, current worker state, request payloads, progress events, and final responses.
| Job ID | Route | Caller | Rule | Status | Retries | Actions |
|---|
Live Job Monitor
select a jobSelect a job to inspect its lifecycle.
Request
payload, query, headersSelect a job to inspect its request.
Response
result, error, eventsSelect a job to inspect its response.
Result Channels
Configure how job results are returned to callers. Most APIs can use polling, but AI chat benefits from streaming partial chunks, stored final results, and traceable result channels linked to a conversation or job.
Polling
Client receives job ID and polls GET /v1/jobs/{job_id}.
SSE Streaming
Client subscribes to a text/event-stream for partial LLM tokens or progress events.
Webhook
ServiceBridge sends completed result to a configured callback endpoint.
Stored Final Result
ServiceBridge stores final response with retention, audit, and trace metadata.
Why this exists
AI chatbot requirementPOST /s/ai-chat/chat → returns job_id and result_channel_id Frontend can: poll job result or subscribe to SSE stream or receive final result later Agent worker can: emit progress events emit token chunks emit tool-call events complete final answer
Result Event Shape
Streaming chunks{
"event": "result.chunk",
"job_id": "job_chat_001",
"conversation_id": "conv_123",
"sequence": 42,
"delta": "The best option is...",
"trace_id": "trace_ai_abc"
}| Name | Service | Mode | Route | Chunking | Retention | Auth | Status | Actions |
|---|
Alerts
Alert on queue backlog, DLQ growth, public-client abuse, WAF challenges, and stale workers.
| Severity | Signal | Condition | Channel | Status | Actions |
|---|
Security
Security controls shared across the tenant.
Controls
MockedSecurity Findings
not scannedBilling & Credits
Each tenant has its own prepaid wallet. For credit purchases, please contact your Account Manager.
Monthly Sandbox Credit
ready to claimClaim a monthly test credit for local experiments. It expires at the end of the calendar month, then the tenant can claim the next month's grant.
Claim the monthly sandbox credit for this tenant.
Credit Top-Up
account-managedCreate a hosted Checkout Session, redirect the tenant admin to Stripe, and credit the wallet only from the signed webhook event.
Credit Settlement
account-managedStripe Checkout stores payment details and sends signed webhook events to settle credits.
SuperAdmin
A separate platform dashboard for users, tenants, credit collection, Stripe checkout configuration, system logs, and service-call telemetry.
First-Run SuperAdmin Onboarding
TOTP requiredCreate the first platform SuperAdmin, enroll an authenticator app, and then use this account to configure Stripe without editing environment variables.
Authenticator Setup
scan or enter manuallyGenerate a TOTP setup QR code, scan it with your authenticator app, then enter the 6-digit code.
Verify Setup
6 digitsSuperAdmin Login
TOTP protectedTenant Credit Snapshot
balances and collection| Tenant | Credits | Collected | Last Credit |
|---|
Platform Telemetry
system-wideLog in as SuperAdmin to view telemetry.
Tenant Credit Details
all wallets| Tenant | Region | Credits | Collected | Stripe Customer | Action |
|---|
Manual Credit Adjustment
SuperAdmin onlyChoose a tenant and amount to add credits manually.
Tenant Credit Ledger
latest platform-wide entries| Time | Tenant | Amount | Source | Note | Created By |
|---|
Stripe Integration
tenant credit checkoutSet test or live Stripe credentials here. Tenants use these settings to open hosted Checkout Sessions for credit purchases. Secret values are never shown again; leave secret fields blank to keep existing values.
Log in as SuperAdmin to manage Stripe.
Service Calls
system-wide job telemetry| Time | Call | Service | Caller | Status | Worker | Events |
|---|
System Logs
audit trail| Time | Actor | Action | Tenant |
|---|
Stripe Webhook Events
latest settlement events| Time | Event | Status | Detail |
|---|
Users
all console accounts| Name | Status | Created | Last Login |
|---|