Actions & Execution
Actions are start/stop operations executed against cloud resources — either triggered automatically by schedules or manually through the API.
How Execution Works
- An action intent is created (by scheduler or manual API call)
- The intent is queued in Redis for processing
- The executor picks up the intent and calls the cloud provider API
- The result (success/failure) is recorded as an execution log
- State transitions are tracked in the state history
Idempotent Actions
Action Statuses
| Status | Description |
|---|---|
pending | Action is queued, waiting to be processed |
running | Action is being executed against the cloud provider |
succeeded | Action completed successfully |
failed | Action failed — check errorMessage for details |
Manual Action
Trigger a start or stop action on a specific resource outside of any schedule.
/actionsSubmit a manual start or stop action.
curl -X POST https://zopnight.com/api/actions \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"type": "stop",
"resourceUID": "i-0abc123def456",
"provider": "aws",
"resourceType": "aws-ec2",
"cloudAccountID": "ca_abc123",
"region": "us-east-1"
}'{
"data": {
"actionID": "act_xyz789",
"status": "queued"
}
}Bulk Action
Start or stop all resources in a resource group with a single request. Resources are processed according to their execution tier and order.
/actions/bulkSubmit a bulk action for a resource group.
curl -X POST https://zopnight.com/api/actions/bulk \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"type": "start",
"groupID": "grp_abc123"
}'{
"data": {
"bulkActionID": "bulk_xyz789",
"status": "queued",
"total": 4
}
}Get Action Status
/actions/{actionID}Check the status of a submitted action.
{
"data": {
"id": "act_xyz789",
"resourceUID": "i-0abc123def456",
"provider": "aws",
"cloudAccountID": "ca_abc123",
"region": "us-east-1",
"action": "stop",
"reason": "manual",
"status": "succeeded",
"startedAt": "2025-01-20T10:00:05Z",
"completedAt": "2025-01-20T10:00:12Z",
"createdAt": "2025-01-20T10:00:00Z"
}
}Get Bulk Action Status
/actions/bulk/{bulkActionID}Check the status of a bulk action.
{
"data": {
"id": "bulk_xyz789",
"groupID": "grp_abc123",
"type": "start",
"status": "completed",
"total": 4,
"completed": 4,
"failed": 0,
"createdAt": "2025-01-20T10:00:00Z"
}
}Latest Bulk Action
Returns the most recent bulk action for the org. Useful for "is there still something running?" indicators that don't already have a bulk ID to look up.
/actions/bulk/latestGet the most recent bulk action submitted by this org.
{
"data": {
"id": "bulk_xyz789",
"groupID": "grp_abc123",
"type": "start",
"status": "running",
"total": 12,
"completed": 7,
"failed": 0,
"createdAt": "2026-04-29T10:00:00Z"
}
}State History
Query the state transition history for resources. This provides an audit trail of when resources were started or stopped and why.
/state-historyGet resource state transition history with pagination.
Query Parameters
| Parameter | Description |
|---|---|
resource_uid | Filter by specific resource |
changed_by_type | Filter by source: schedule, manual, bulk, override, override_expired |
page | Page number |
limit | Items per page |
{
"data": {
"items": [
{
"id": "sh_001",
"resourceUid": "i-0abc123def456",
"state": "stopped",
"changedAt": "2025-01-20T18:00:00Z",
"changedBy": "schedule:nightly-shutdown:cron_xyz",
"scheduleId": "sch_abc123",
"executionState": { "step": "stop-instance", "status": "succeeded" }
},
{
"id": "sh_002",
"resourceUid": "i-0abc123def456",
"state": "failed",
"changedAt": "2025-01-21T08:00:00Z",
"changedBy": "schedule:nightly-shutdown:cron_xyz",
"scheduleId": "sch_abc123",
"errorMessage": "InsufficientCapacity: m6i.large not available in us-east-1a"
}
],
"total": 2,
"page": 1,
"limit": 50
}
}changedBy Values
The changedBy field is a structured colon-delimited string:
schedule:<name>:<cronId>— triggered by a schedulemanual:<email>— manually triggered via API or UIbulk:<email>:<bulkId>— bulk start/stop actionoverride:<action>— triggered by an active overrideoverride_expired:<action>— triggered when an override expired
errorMessage is populated only on failures; executionState is a free-form map of step-level status that the executor records during multi-step transitions (e.g. for k8s namespaces or container apps).