#327 App HTTP Gateway - Direct API invocation of app actions
Description
Edit## Summary
Add ability to invoke app actions directly via HTTP API without creating a workflow.
## HTTP Methods
### GET - For Email Approval Links & Simple Queries
```
GET /api/v1/apps/invoke/{installation_id}/{action_name}?param1=value1¶m2=value2
Authorization: Bearer <token> (or via signed URL token)
```
**Use Cases:**
- Email approval links: `<a href="/api/v1/apps/invoke/{id}/approve?token=xyz&decision=yes">Approve</a>`
- Simple status checks
- Idempotent read operations
### POST - For API Integrations & Complex Data
```
POST /api/v1/apps/invoke/{installation_id}/{action_name}
Authorization: Bearer <token>
Content-Type: application/json
{
"param1": "value1",
"param2": "value2"
}
```
### Version-Specific Endpoints
```
GET /api/v1/apps/invoke/version/{version_id}/{action_name}?params...
POST /api/v1/apps/invoke/version/{version_id}/{action_name}
```
**Why UUIDs, not names:**
- Guaranteed uniqueness across 1000s of apps
- Version-specific targeting (v1.0.0 vs v2.0.0 behavior)
- No name collision between publishers
- Immutable reference - URL always points to same code
## Response Formats
### Standard JSON Response
```json
{
"status": "success",
"data": {
"result": { ... },
"execution_id": "uuid",
"app_id": "uuid",
"version_id": "uuid",
"duration_ms": 123
}
}
```
### HTML Response (for email links)
When `Accept: text/html` header or `?format=html` query param:
```html
<!DOCTYPE html>
<html><body>
<h1>Thank You</h1>
<p>Your decision has been recorded.</p>
</body></html>
```
### Redirect Response
When action returns `{"_redirect": "https://..."}`:
```
HTTP/1.1 302 Found
Location: https://app.example.com/approval-confirmed?id=123
```
### Error Response
```json
{
"status": "error",
"error": {
"code": "ACTION_FAILED",
"message": "Human readable error",
"details": { ... }
},
"execution_id": "uuid"
}
```
## Email Approval Flow
1. Workflow sends approval email with links:
```
Approve: https://highway.example.com/api/v1/apps/invoke/{id}/approve?token=abc&decision=yes&format=html
Reject: https://highway.example.com/api/v1/apps/invoke/{id}/approve?token=abc&decision=no&format=html
```
2. User clicks link → GET request
3. App validates token, processes decision
4. Returns HTML page OR redirects to confirmation page
## Security Considerations
### For GET Requests (Email Links)
- Use **signed tokens** instead of JWT in URL (shorter, single-use)
- Token includes: action_id, expiry, decision, HMAC signature
- Tokens tracked in `highway.action_tokens` table (consumed on use)
- Short expiry (24-72 hours)
- No sensitive data in URL params
### Token Consumption Table
```sql
CREATE TABLE highway.action_tokens (
token_id UUID PRIMARY KEY,
installation_id UUID NOT NULL,
action_name VARCHAR(100) NOT NULL,
params_hash VARCHAR(64),
expires_at TIMESTAMPTZ NOT NULL,
consumed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
### For POST Requests
- Standard JWT authentication
- CORS policy: Same-origin by default, configurable per installation
- Request body validation against action schema
## Gateway Context (vs Workflow Context)
HTTP Gateway executions get a simplified context:
| Feature | AppContext (Workflow) | GatewayContext (HTTP) |
|---------|----------------------|----------------------|
| Secrets | ✅ | ✅ |
| Config | ✅ | ✅ |
| HTTP requests | ✅ | ✅ |
| Logging | ✅ | ✅ |
| Checkpoints | ✅ | ❌ (single call) |
| Events/wait | ✅ | ❌ |
| Sleep | ✅ | ❌ |
| State vars | ✅ | ❌ |
| DB connection | ✅ | ✅ (separate tx) |
## Rate Limiting
| Scope | Default Limit | Configurable |
|-------|--------------|--------------|
| Per tenant | 1000 req/min | Yes |
| Per installation | 100 req/min | Yes |
| Per action | 50 req/min | Yes |
| Burst | 10 req/sec | Yes |
## Async Execution (Future)
For long-running actions:
```
POST /api/v1/apps/invoke/{installation_id}/{action_name}?async=true
Response:
{
"status": "accepted",
"job_id": "uuid",
"poll_url": "/api/v1/apps/jobs/{job_id}"
}
```
## Webhook Registration
Apps declare webhooks in manifest:
```json
{
"webhooks": {
"github_push": {
"path": "github/push",
"method": "POST",
"signature_header": "X-Hub-Signature-256",
"signature_algorithm": "hmac-sha256"
}
}
}
```
Webhook URL: `POST /api/v1/webhooks/{version_id}/github/push`
## URL Structure
| Use Case | Method | URL Pattern |
|----------|--------|-------------|
| Email approval link | GET | `/api/v1/apps/invoke/{installation_id}/{action_name}?token=...&format=html` |
| API integration | POST | `/api/v1/apps/invoke/{installation_id}/{action_name}` |
| Specific version (GET) | GET | `/api/v1/apps/invoke/version/{version_id}/{action_name}?params...` |
| Specific version (POST) | POST | `/api/v1/apps/invoke/version/{version_id}/{action_name}` |
| Webhook receiver | POST | `/api/v1/webhooks/{version_id}/{webhook_path}` |
| Async job status | GET | `/api/v1/apps/jobs/{job_id}` |
## Use Cases
- **Email approvals** - User clicks link in email, records decision
- GitHub webhook triggers app action (version-pinned)
- Slack slash commands invoke app
- External API integrations
- Simple automations without full workflow
- CI/CD pipelines calling specific app versions
Comments
Loading comments...
Context
Loading context...
Audit History
View AllLoading audit history...