Skip to content

Recordings

Capture user workflows from a browser (or any client you build), upload the events + screenshots, and let SOPFlow's AI pipeline draft SOP steps. Powers the SOPFlow Chrome extension; same surface is open to your own clients.

tRPC, not REST

The recording surface lives on POST /trpc/recording.<procedure> rather than /api/v1/*. Same Bearer-key auth, just a different base path. The screenshot upload uses regular multipart at POST /api/v1/recordings/:id/screenshot/:seq.

Lifecycle

  1. create — get a recording id and the session starts.
  2. uploadEvents — POST batches as the user interacts (max 100 per call).
  3. screenshot — multipart POST for any sequence number.
  4. finalize — server flips status to processing and runs the AI pipeline.
  5. getStatus — poll until ready (or failed); generated steps are ready.
  6. importToSOP — convert selected drafts into sop_steps.
POST/trpc/recording.create

Open a new recording session. Returns the recordingId you'll use for every subsequent call.

Body fields

NameTypeRequiredDescription
sourcestringrequiredchrome_extension | desktop_app — for analytics & display only.

Example response

Json
{
  "result": {
    "data": {
      "recordingId": "31ab37ce-dce6-4590-a640-b175a1454055"
    }
  }
}
POST/trpc/recording.uploadEvents

Append an ordered batch of events. sequenceNumber must strictly increase across the recording (and within each batch). Max 100 events per call.

Body fields

NameTypeRequiredDescription
recordingIduuidrequired—
eventsEvent[]required1–100 events.

Event

NameTypeRequiredDescription
sequenceNumberintegerrequiredStrictly increasing per recording.
eventTypestringrequiredclick | input | select | navigation | keyboard_shortcut | scroll | form_submit | context_menu | double_click | drag_drop | tab_switch | app_switch | file_upload
urlstringoptional—
pageTitlestringoptional—
targetobjectrequiredElement metadata: cssSelector, xpath, textContent, ariaLabel, elementType, etc.
eventDataobjectoptionalType-specific payload (input value, key combo, scroll delta…).
screenshotKeystringoptionalSet if you uploaded a screenshot for this seq via the multipart endpoint.
timestampintegerrequiredUnix ms.

Example response

Json
{ "result": { "data": { "inserted": 5 } } }
POST/api/v1/recordings/:recordingId/screenshot/:seq

Multipart upload of a single image/webp ≤ 5 MB for one event. The screenshot is linked to the matching event row when (or if) it arrives.

Multipart fields

NameTypeRequiredDescription
fileimage/webprequiredMax 5 MB, webp only.

Example response

Json
{ "objectKey": "recording_screenshots/<org>/<rec>/0.webp", "sizeBytes": 12480 }
POST/trpc/recording.finalize

Stop accepting events and kick off AI processing. Returns a job id. API-key clients must poll recording.getStatus; the session-only SSE endpoint does not expose API-key-owned jobs.

Body fields

NameTypeRequiredDescription
recordingIduuidrequired—
durationMsintegeroptionalTotal recording duration in milliseconds.

Example response

Json
{ "result": { "data": { "status": "processing", "jobId": "..." } } }
GET/trpc/recording.getStatus

Poll for processing completion. Pass input via query string (URL-encoded JSON).

Query parameter

NameTypeRequiredDescription
inputJSONrequiredURL-encoded {"recordingId":"<uuid>"}

Example response

Json
{
  "result": {
    "data": {
      "recording": {
        "id": "31ab37ce-...",
        "status": "ready",
        "eventCount": 42,
        "screenshotCount": 18,
        "durationMs": 65234
      },
      "generatedSteps": [
        {
          "id": "...",
          "stepNumber": 1,
          "title": "Navigate to the Login page",
          "description": "Open the SOPFlow login URL.",
          "screenshotKey": "recording_screenshots/<org>/<rec>/0.webp",
          "sourceEventIds": ["..."]
        }
      ]
    }
  }
}
POST/trpc/recording.importToSOP

Append selected generated steps to a kanban phase as real sop_steps. The recording is auto-archived on success.

Body fields

NameTypeRequiredDescription
recordingIduuidrequired—
sopVersionIduuidrequiredThe version to append into (server validates ownership).
phaseIduuidrequired—
stepsStep[]required1–50 generated steps to import.

Step

NameTypeRequiredDescription
generatedStepIduuidrequired—
titlestringrequiredEditable — server uses what you send, not the original.
descriptionstring | nulloptional—

Example response

Json
{ "result": { "data": { "createdSteps": [{ "id": "...", "title": "..." }] } } }

Provisioning a key for your client

For server-to-server use, mint an API key in Settings → API keys with the read + write scopes and keep it on your trusted server. Never embed a shared service key in public browser code.

For browser extensions and desktop clients that act on behalf of an end-user, use the post-OAuth bridge:

POST/trpc/apiKeys.createForExtension

Mint a fresh sk_live_… key in the calling user's workspace, named 'Chrome extension (<browser>)'. Editor-procedure (eligible signed-in editors and admins can connect their browser); skips the api_access plan gate. The web app's /extension/connect page calls this after the user signs in, then redirects back to your client with the key in the URL fragment so it never lands in a server access log.

Body fields

NameTypeRequiredDescription
clientNamestringrequiredDisplay label — shown in Settings → API keys (e.g. 'Chrome', 'My Recorder').

Example response

Json
{ "result": { "data": { "key": "sk_live_…", "prefix": "sk_live_abcd" } } }

End-to-end example

# 1. Create a new recording session
curl -X POST https://sopflow.io/trpc/recording.create \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"source":"chrome_extension"}'

# 2. Stream events as you capture them (max 100 per call)
curl -X POST https://sopflow.io/trpc/recording.uploadEvents \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recordingId":"<from step 1>",
    "events":[
      {"sequenceNumber":0,"eventType":"click","url":"https://example.com",
       "pageTitle":"Home","target":{"cssSelector":"button.cta",
       "elementType":"BUTTON","textContent":"Sign in"},"timestamp":1730000000000}
    ]
  }'

# 3. Optionally POST a screenshot for any sequenceNumber
curl -X POST \
  https://sopflow.io/api/v1/recordings/<id>/screenshot/0 \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -F "file=@frame.webp;type=image/webp"

# 4. Finalize — kicks off the AI pipeline asynchronously
curl -X POST https://sopflow.io/trpc/recording.finalize \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"recordingId":"<id>","durationMs":65000}'

# 5. Poll for the result (status flips to "ready")
curl "https://sopflow.io/trpc/recording.getStatus?input=%7B%22recordingId%22%3A%22<id>%22%7D" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

Notes

  • Privacy is the client's responsibility. The server stores whatever eventData.value you send. The Chrome extension masks password fields and credit-card autocomplete fields before they leave the page; if you build your own client, do the same. The pipeline does a regex sweep for cards / SSNs / emails as a last-line defense, but don't rely on it.
  • Rate limits. tRPC requests are subject to the general API limit (300 requests per minute per IP), not the REST per-key budgets. Batch up to 100 events per call and handle 429 responses.
  • Restart recovery. If the API restarts mid-processing, the recording is auto-marked failed on the next boot. Call recording.reprocess to retry.

Walk through capture to reviewed import

Follow the create, event upload, optional screenshot and finalize sequence documented above. Keep the recording ID and event sequence numbers so the draft can be checked against its evidence.

Use the required authorized transport for each endpoint; these recording operations are not interchangeable with the REST API-key surface. Review the draft and destination before importing or replacing steps.