Base URL: https://api.nexflowapp.app/v1/pulse
All endpoints require authentication via API key.
Include your API key in every request:
Authorization: Bearer YOUR_API_KEYOr:
X-API-Key: YOUR_API_KEY| Method | Path | Description |
|---|---|---|
POST |
/jobs |
Create a new scheduled job |
GET |
/jobs |
List all jobs |
GET |
/jobs/{id} |
Get a specific job |
PATCH |
/jobs/{id} |
Update a job |
DELETE |
/jobs/{id} |
Delete a job |
GET |
/jobs/{id}/runs |
List job executions |
POST |
/jobs/{id}/test-run |
Trigger immediate test execution |
POST |
/jobs/{id}/resume |
Resume an errored job |
GET |
/billing |
Get billing statistics |
GET |
/health |
Health check (no auth required) |
Create a new scheduled HTTP job.
POST /v1/pulse/jobs{
"name": "My Webhook Job",
"targetUrl": "https://api.example.com/webhook",
"method": "POST",
"headers": {
"X-Custom-Header": "value"
},
"body": {
"message": "Hello from Pulse!"
},
"scheduleType": "interval",
"intervalSeconds": 60,
"maxRetries": 3,
"retryBackoffSeconds": 30,
"timeoutMs": 10000
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | No | null | Human-readable job name |
targetUrl |
string | Yes | – | URL to call (must be HTTPS in production) |
method |
string | No | POST |
HTTP method: GET, POST, PUT, PATCH, DELETE |
headers |
object | No | null | Custom HTTP headers |
body |
any | No | null | Request body (for POST/PUT/PATCH) |
scheduleType |
string | Yes | – | interval or cron |
intervalSeconds |
number | Conditional | – | Required if scheduleType is interval |
cronExpression |
string | Conditional | – | Required if scheduleType is cron |
maxRetries |
number | No | 3 | Max retry attempts (0-10) |
retryBackoffSeconds |
number | No | 30 | Base backoff for retries |
timeoutMs |
number | No | 10000 | Request timeout in milliseconds |
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"ownerId": "user-123",
"name": "My Webhook Job",
"targetUrl": "https://api.example.com/webhook",
"method": "POST",
"headers": { "X-Custom-Header": "value" },
"body": { "message": "Hello from Pulse!" },
"scheduleType": "interval",
"intervalSeconds": 60,
"cronExpression": null,
"nextRunAt": "2026-01-09T22:01:00.000Z",
"status": "active",
"maxRetries": 3,
"retryBackoffSeconds": 30,
"timeoutMs": 10000,
"currentRetryCount": 0,
"lastError": null,
"lastRunAt": null,
"billableExecutions": 0,
"estimatedCostUsdc": 0,
"createdAt": "2026-01-09T22:00:00.000Z",
"updatedAt": "2026-01-09T22:00:00.000Z"
}| Code | Description |
|---|---|
| 201 | Job created successfully |
| 400 | Invalid request body |
| 401 | Missing or invalid API key |
| 429 | Rate limit exceeded (max jobs reached) |
Retrieve all jobs for the authenticated account.
GET /v1/pulse/jobs| Parameter | Type | Default | Description |
|---|---|---|---|
status |
string | – | Filter by status: active, paused, error |
scheduleType |
string | – | Filter by type: interval, cron |
limit |
number | 20 | Results per page (max 100) |
offset |
number | 0 | Pagination offset |
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Webhook Job",
"status": "active",
"nextRunAt": "2026-01-09T22:01:00.000Z",
...
}
],
"pagination": {
"total": 42,
"limit": 20,
"offset": 0,
"hasMore": true
}
}Retrieve a specific job by ID.
GET /v1/pulse/jobs/{id}Returns the full job object (same as create response).
| Code | Description |
|---|---|
| 200 | Success |
| 404 | Job not found |
Update a job's configuration.
PATCH /v1/pulse/jobs/{id}All fields are optional. Only include fields you want to change:
{
"name": "Updated Job Name",
"status": "paused",
"intervalSeconds": 120,
"maxRetries": 5
}| Field | Description |
|---|---|
name |
Job name |
targetUrl |
Target URL |
method |
HTTP method |
headers |
Custom headers |
body |
Request body |
scheduleType |
Schedule type (interval/cron) |
intervalSeconds |
Interval in seconds |
cronExpression |
Cron expression |
status |
Job status (active, paused) |
maxRetries |
Max retry attempts |
retryBackoffSeconds |
Retry backoff |
timeoutMs |
Request timeout |
- Setting
status: "active"on an errored job resetscurrentRetryCountto 0 - Changing schedule recalculates
nextRunAt
Permanently delete a job.
DELETE /v1/pulse/jobs/{id}{
"message": "Job deleted successfully"
}Retrieve execution history for a job.
GET /v1/pulse/jobs/{id}/runs| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
number | 20 | Results per page (max 100) |
offset |
number | 0 | Pagination offset |
{
"data": [
{
"id": "run-123",
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"startedAt": "2026-01-09T22:00:00.000Z",
"finishedAt": "2026-01-09T22:00:00.142Z",
"status": "success",
"httpStatus": 200,
"errorMessage": null,
"latencyMs": 142,
"responseBody": "{\"status\":\"ok\"}",
"retryAttempt": 0,
"createdAt": "2026-01-09T22:00:00.000Z"
}
],
"pagination": {
"total": 100,
"limit": 20,
"offset": 0,
"hasMore": true
}
}| Status | Description |
|---|---|
success |
Request completed with 2xx response |
failed |
Request failed (non-2xx, network error) |
timeout |
Request exceeded timeout |
Trigger an immediate execution of a job without affecting its schedule.
POST /v1/pulse/jobs/{id}/test-run{
"testRun": true,
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"result": {
"status": "success",
"httpStatus": 200,
"latencyMs": 142,
"responseBody": "{\"status\":\"ok\"}",
"errorMessage": null
},
"executedAt": "2026-01-09T22:00:00.000Z",
"note": "Test run executed immediately. Regular schedule not affected."
}Resume an errored job by resetting its retry count and reactivating it.
POST /v1/pulse/jobs/{id}/resume{
"message": "Job resumed successfully",
"job": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "active",
"currentRetryCount": 0,
...
}
}Get billing statistics for your account.
GET /v1/pulse/billing{
"ownerId": "user-123",
"totalExecutions": 12500,
"totalCostUsdc": 18.75,
"jobCount": 25,
"costPerExecution": 0.0015,
"currency": "USDC"
}Check API and worker status (no authentication required).
GET /v1/pulse/health{
"status": "ok",
"timestamp": "2026-01-09T22:00:00.000Z",
"database": {
"connected": true
},
"workers": {
"active": 3,
"lastHeartbeat": "2026-01-09T21:59:55.000Z"
},
"queue": {
"lagMs": 250,
"activeJobs": 1500,
"pausedJobs": 50,
"errorJobs": 5
}
}| Status | HTTP Code | Description |
|---|---|---|
ok |
200 | All systems operational |
degraded |
503 | Some issues detected |
error |
503 | Critical issues |
All errors follow this format:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": { ... }
}
}| Code | HTTP Status | Description |
|---|---|---|
UNAUTHORIZED |
401 | Missing or invalid API key |
JOB_NOT_FOUND |
404 | Job does not exist |
VALIDATION_ERROR |
400 | Invalid request data |
RATE_LIMIT_EXCEEDED |
429 | Too many jobs or requests |
PAYLOAD_TOO_LARGE |
400 | Headers or body exceeds size limit |
INTERNAL_ERROR |
500 | Server error |
For the complete machine-readable API specification, see openapi.yaml.