API Reference

Learn how to use the Periodic Intel API to programmatically manage your jobs, reports, and notifications.

Overview

The Periodic Intel API allows you to programmatically manage your data collection jobs, retrieve generated reports, and configure notifications. The API is a RESTful interface that uses JSON for requests and responses.

Versioning: The current API has no version prefix in the path (e.g., /v1/). If breaking changes are introduced in the future, a versioned path will be adopted. You will be notified in advance of any such changes.

Authentication

Most endpoints accept either an API key or a user-session Bearer token. However, API key management (/api-keys) requires a logged-in user session.

  1. Open the API Keys screen in your dashboard.
  2. Click Create to generate a new API Key.
  3. Make sure to copy the temporary secret (e.g., msk_xxxx) shown immediately after creation. You won't be able to view it again.

When using an API key, you can send it in either of these formats:

X-API-Key: msk_your_api_key_here
Authorization: ApiKey msk_your_api_key_here

Inside the dashboard, the web client uses Firebase ID-token Bearer authentication.

Keep your API keys secure. Do not share them in publicly accessible areas such as GitHub, client-side code, etc.

Authentication error behavior:

  • If no authentication credential is provided, a 401 Unauthorized response is returned.
  • If the API key is invalid, disabled, or expired, the current implementation returns 400 Bad Request.
  • If the key is valid but you do not have permission to access the requested resource (e.g., accessing another user's resource), a 403 Forbidden response is returned.

Base URL

https://api.stratum-flow.com

Error Handling

Common Error Format

When an error occurs, the response body will be in the following format:

{
  "ok": false,
  "message": "A description of the error"
}

HTTP Status Codes

Code Meaning Common Causes
400 Bad Request Invalid request Missing required fields, validation errors, invalid/disabled API key, some plan-gated option errors
401 Unauthorized Authentication failed No authentication credential provided
403 Forbidden Access denied Accessing another user's resource, or hitting endpoints that require Starter or above
404 Not Found Resource not found The specified job, report, or config ID does not exist
429 Too Many Requests Rate limit exceeded Sending too many requests in a short period
500 Internal Server Error Server error Internal failure such as a job enqueueing error

Endpoints

Jobs

Jobs define the data collection instructions, trigger frequency, and conditions for automatic generation.

GET /jobs

List your configured jobs. Returns 10 items per page (default) with cursor-based pagination.

Query Parameters:

Parameter Type Description
cursor string Document ID of the last item on the previous page (value of pagination.nextCursor). Omit to start from the beginning.
limit number Items per page. Default: 10, Max: 100

Response (200 OK):

Name Type Description
ok boolean Indicates if the request was successful
data array An array of Job Objects
pagination.nextCursor string | null Cursor for the next page. null means this is the last page.
pagination.hasMore boolean Whether more items are available

Example:

{
  "ok": true,
  "data": [
    {
      "id": "b0DoFn4h9TKNWHsjdsEd",
      "name": "競合SaaSの動向リサーチi",
      "sourceUrl": "",
      "promptInstruction": "競合・市場・技術トレンドを横断的に調査し、重要な変化とインパクトを要約してください。",
      "intervalMinutes": 1440,
      "timezone": "UTC",
      "status": "paused",
      "running": false,
      "notificationConfigId": null,
      "nextRunAt": "2026-03-29T11:49:00.000Z"
    },
    /* …etc… */
  ],
  "pagination": {
    "nextCursor": "X8ikRFjvXA0U6imnW7X4",
    "hasMore": true
  }
}

POST /jobs

Create a new job.

Body (JSON):

Field Type Required Description
name string Yes Identifier for the job
promptInstruction string Yes AI instructions for collection and analysis
sourceUrl string No URL of the source (http/https)
intervalMinutes number No Run interval in minutes. Default: 60, Minimum: 60
timezone string No Timezone (e.g., Asia/Tokyo). Default: UTC
researchMode string No "normal" or "extended". Default: "normal". Extended mode expands search and page traversal for deeper investigation. Each run costs 3x the normal usage. Requires Pro plan or above.
researchModelProfile string No "standard" or "precision". Default: "standard". precision prioritizes better factual accuracy and higher report quality, and adds +4 credits on top of the research depth cost. Requires Pro plan or above.
notificationConfigId string | null No ID of the notification config (Starter plan or above)
nextRunAt string No First scheduled run time (ISO8601). Defaults to the current time (runs immediately).

Response (200 OK):

Name Type Description
ok boolean true
data object The newly created Job Object

PATCH /jobs/:id

Update an existing job's parameters. Only the fields you provide will be updated.

Body (JSON):

Field Type Required Description
name string No Identifier for the job
promptInstruction string No AI instructions for collection and analysis
sourceUrl string No URL of the source (http/https). Use an empty string to clear.
intervalMinutes number No Run interval in minutes. Minimum: 60. Changing this does not recalculate nextRunAt. To also update the next run time, include nextRunAt in the same request.
timezone string No Timezone (e.g., Asia/Tokyo)
researchMode string No "normal" or "extended". Extended mode expands search and page traversal. Requires Pro plan or above.
researchModelProfile string No "standard" or "precision". precision prioritizes better factual accuracy and higher report quality, and adds +4 credits on top of the research depth cost. Requires Pro plan or above.
notificationConfigId string | null No ID of the notification config (Starter plan or above). Use null to detach.
nextRunAt string No Next scheduled run time (ISO8601). No change if not specified.

Response (200 OK):

Name Type Description
ok boolean true
data object The updated Job Object

POST /jobs/:id/status

Set a job's execution status to active or paused.

Body (JSON):

Field Type Required Description
status string Yes "active" or "paused"

Response (200 OK):

Name Type Description
ok boolean true
data object The updated Job Object

DELETE /jobs/:id

Deactivates a job. The job is set to paused and its next run schedule is cleared. This is a soft delete — the job record is not permanently removed.

Response (200 OK):

Name Type Description
ok boolean true
data object The deactivated Job Object

POST /jobs/:id/run

Trigger a job to run immediately (manual trigger). The run is enqueued and processed asynchronously.

Body (JSON):

Field Type Required Description
tbs string No Search time range filter (internal use). Omit in most cases.

Response (202 Accepted):

Name Type Description
ok boolean true
data.runId string The ID assigned to this run
data.started boolean true indicates successful enqueue

Error (409 Conflict):

{ "ok": false, "message": "Job is already running" }

Poll GET /jobs/:jobid/reports or GET /runs?jobId=:id to check the result.


GET /jobs/:id/running

Retrieve whether the job is currently running.

Response (200 OK):

Name Type Description
ok boolean true
data.jobId string Target job ID
data.running boolean true when the job is currently executing
data.runningStartedAt string | null Execution start time (ISO8601)
data.lockAgeMs number | null Elapsed milliseconds since execution started

Reports

Intelligence reports generated by your jobs.

GET /jobs/:jobid/reports

Fetch reports generated by a specific job, newest first. Returns 10 items per page (default) with cursor-based pagination.

Query Parameters:

Parameter Type Description
cursor string Document ID of the last item on the previous page (value of pagination.nextCursor). Omit to start from the beginning.
limit number Items per page. Default: 10, Max: 100

Response (200 OK):

Name Type Description
ok boolean true
data array An array of Report Objects
pagination.nextCursor string | null Cursor for the next page. null means this is the last page.
pagination.hasMore boolean Whether more items are available

Example:

{
  "ok": true,
  "data": [
    {
      "id": "rpt_xyz001",
      "jobId": "job_abc123",
      "status": "success",
      "subject": "Report 1",
      "summary": "...",
      "abstract": null,
      "createdAt": "2026-03-29T12:00:00.000Z"
    }
    /* … */
  ],
  "pagination": {
    "nextCursor": "gU3Ed...",
    "hasMore": true
  }
}

GET /jobs/:jobid/reports/:reportid

Fetch detailed information for a single, specific report.

Response (200 OK):

Name Type Description
ok boolean true
data object A Report Object

GET /runs

Fetch the run log. Returns up to 1200 runs, newest first.

Query Parameters:

Parameter Type Description
jobId string Filter by a specific job ID

Response (200 OK):

Name Type Description
ok boolean true
data array An array of Run Objects

Notifications

GET /notifications

Fetch notification history. Returns up to 50 notifications, newest first.

Response (200 OK):

Name Type Description
ok boolean true
data array An array of notification objects

POST /notifications/read-all

Mark all unread notifications as read.

Response (200 OK):

{ "ok": true, "data": { "success": true } }

Trend Analysis

Fetch and generate AI-powered timeline analysis reports for a specific job.

Permissions: Starter plan or above

GET /jobs/:jobid/timeline-report

Fetch the latest trend analysis report for a specific job. Returns data: null if no report has been generated yet.

Response (200 OK):

Name Type Description
ok boolean true
data object | null A Timeline Report Object, or null if not yet generated

POST /jobs/:jobid/timeline-report/generate

Asynchronously trigger the generation of a new trend analysis report. At least 2 successful reports must exist for the target job.

Response (202 Accepted):

{ "ok": true, "data": { "generating": true } }

Poll GET /jobs/:jobid/timeline-report to check completion. The report is ready when data.status transitions from "generating" to a completed state.


Notification Configs

Manage external integrations for Slack, Microsoft Teams, a generic webhook, or email. Requires Starter plan or above.

GET /notification-configs

List all your notification configurations.

Response (200 OK):

Name Type Description
ok boolean true
data array An array of Notification Config Objects

POST /notification-configs

Create a new notification destination.

Body (JSON):

Field Type Required Description
provider string Yes "slack", "teams", "webhook", or "email"
name string Yes Display name for the config
webhookUrl string Required when provider is "slack", "teams", or "webhook" Webhook URL (https)
email string Required when provider is "email" Destination email address
isActive boolean No Whether the config is active. Default: true

Response (200 OK):

Name Type Description
ok boolean true
data object The newly created Notification Config Object

PATCH /notification-configs/:id

Update an existing notification configuration. Only the fields you provide will be updated.

Body (JSON):

Field Type Required Description
name string No Display name
webhookUrl string No Webhook URL (https)
email string No Email destination (only for provider: "email")
isActive boolean No Whether the config is active

Response (200 OK):

Name Type Description
ok boolean true
data object The updated Notification Config Object

DELETE /notification-configs/:id

Delete a notification configuration. Any jobs referencing this config will be automatically unlinked.

Response (200 OK):

{ "ok": true, "data": { "deleted": true } }

POST /notification-configs/:id/test

Send a test message to the notification destination. Returns 400 if the config is set to isActive: false.

Response (200 OK):

{ "ok": true, "data": { "sent": true } }

API Keys

API key management operations can only be performed using a user session (dashboard login). You cannot use an API key to manage other API keys. Requires Pro plan or above.

GET /api-keys

List your registered API keys. Returns up to 50.

Response (200 OK):

Name Type Description
ok boolean true
data array An array of API key objects

POST /api-keys

Create a new API key. The secret is only included in this response and cannot be retrieved again.

Body (JSON):

Field Type Required Description
name string Yes Identifier for the key
expiration string No Expiration date (ISO8601). No expiration if omitted.

Response (200 OK):

Name Type Description
ok boolean true
data.apiKey object Metadata of the created API key
data.secret string One-time secret (e.g., msk_xxxx). Store it securely — it will not be shown again.

POST /api-keys/:id/disable

Disable an API key. A disabled key is immediately rejected for authentication, but can be enabled again later.

Response (200 OK):

{ "ok": true, "data": { "disabled": true, "apiKey": { "id": "...", "disabledAt": "2026-03-02T10:00:00.000Z" } } }

POST /api-keys/:id/enable

Re-enable a previously disabled API key. If the key is already expired, enabling it does not extend the expiration.

Response (200 OK):

{ "ok": true, "data": { "enabled": true, "apiKey": { "id": "...", "disabledAt": null } } }

DELETE /api-keys/:id

Physically delete an API key. This cannot be undone.

Response (200 OK):

{ "ok": true, "data": { "deleted": true } }

Account

GET /account/usage

Retrieve your current account usage (monthly report count, plan tier, etc.).

Response (200 OK):

{
  "ok": true,
  "data": {
    "monthlyReportsGenerated": 42,
    "tier": "starter",
    "usageStartAt": "2026-03-01T00:00:00Z",
    "usageEndAt": "2026-03-31T23:59:59Z"
  }
}

Data Models

Job Object

{
  "id": "job_abc123",
  "name": "Competitor Analysis",
  "sourceUrl": "https://example.com/news",
  "promptInstruction": "Analyze major competitor developments",
  "intervalMinutes": 1440,
  "timezone": "Asia/Tokyo",
  "status": "active",
  "running": false,
  "researchMode": "normal",
  "researchModelProfile": "standard",
  "notificationConfigId": "cfg_xyz456",
  "lastRunAt": "2026-03-02T10:00:00.000Z",
  "nextRunAt": "2026-03-03T10:00:00.000Z"
}
Field Type Description
id string Unique job ID
name string Job identifier
sourceUrl string Source URL (empty string if not set)
promptInstruction string AI instructions
intervalMinutes number Run interval in minutes
timezone string Timezone (default UTC)
status string "active" or "paused"
running boolean Whether the job is currently executing
researchMode string "normal" or "extended". "extended" deepens search and page traversal
researchModelProfile string "standard" or "precision". precision prioritizes better factual accuracy and higher report quality
notificationConfigId string | null Linked notification config ID
lastRunAt string | null Last run time (ISO8601)
nextRunAt string | null Next scheduled run time (ISO8601)

Report Object

{
  "id": "rpt_def456",
  "jobId": "job_abc123",
  "status": "success",
  "subject": "Competitor Analysis Report 2026-03-02",
  "summary": "Key highlights this week include...",
  "abstract": "Brief summary text (if available)",
  "sources": [
    {
      "index": 1,
      "url": "https://example.com/source"
    }
  ],
  "createdAt": "2026-03-02T10:05:00.000Z"
}
Field Type Description
id string Unique report ID
jobId string Source job ID
status string "success", "failed", etc.
subject string Report title
summary string Full report content
abstract string | null Short summary (if available)
sources array Array of cited source records
createdAt string Generation time (ISO8601)

Run Object

{
  "id": "job_abc123-1709380000000",
  "jobId": "job_abc123",
  "status": "success",
  "startedAt": "2026-03-02T10:00:00.000Z",
  "finishedAt": "2026-03-02T10:04:58.000Z",
  "durationMs": 298000,
  "triggeredBy": "manual",
  "errorCategory": null,
  "errorMessage": null
}
Field Type Description
id string Unique run ID
jobId string Source job ID
status string "success", "failed", "running", etc.
startedAt string | null Run start time (ISO8601)
finishedAt string | null Run end time (ISO8601)
durationMs number | null Duration in milliseconds
triggeredBy string "manual" or "schedule"
errorCategory string | null Error category (on failure)
errorMessage string | null Error message (on failure)

Notification Config Object

{
  "id": "cfg_xyz456",
  "provider": "slack",
  "name": "Dev Team Alerts",
  "webhookUrlMasked": "https://hooks.slack.com/...****",
  "destinationMasked": "https://hooks.slack.com/...****",
  "isActive": true,
  "createdAt": "2026-02-01T00:00:00.000Z",
  "updatedAt": "2026-02-15T12:30:00.000Z"
}
Field Type Description
id string Unique config ID
provider string "slack", "teams", "webhook", or "email"
name string Display name
webhookUrlMasked string Masked webhook URL (end obscured for security). For email destinations this mirrors emailMasked.
emailMasked string Masked email address (when provider: "email")
destinationMasked string Preferred masked destination (email or webhook)
isActive boolean Whether the config is active
createdAt string Creation time (ISO8601)
updatedAt string Last update time (ISO8601)

Timeline Report Object

{
  "id": "job_abc123",
  "jobId": "job_abc123",
  "subject": "Competitor Trend Timeline",
  "body": "Analysis of the past N reports shows...",
  "status": "done",
  "reportCount": 12,
  "createdAt": "2026-03-01T08:00:00.000Z",
  "updatedAt": "2026-03-02T09:00:00.000Z"
}
Field Type Description
id string Document ID (same as the job ID)
jobId string Source job ID
subject string | null Report title
body string | null Report content
status string "generating" while in progress; a completion value when done
reportCount number Number of reports used for analysis
createdAt string | null First generation time (ISO8601)
updatedAt string | null Last update time (ISO8601)

Still need help?

If you couldn't find an answer to your question, please contact us.