Skip to content

Personal Access Tokens (Beta)

Beta A Personal Access Token authenticates API requests as you, without a browser session. Tokens are being released to a limited group of accounts; if you do not see the section described below, it is not yet enabled for yours.

What a token can do

A token carries scopes, and reaches only what its scopes cover:

ScopeGrants
files:uploadUploading files, including in parts, and importing them from a URL
files:readListing the files in a folder, and reading one with its transcript and summary
files:askAsking questions about a file and analysing it with AI

Every scope is deliberately narrow: files:upload cannot read and files:read cannot write. files:ask is separate from files:read because asking spends your account’s AI credits, so reading a file back never silently costs you any. A token cannot change your account, manage your team, touch your subscription, or create further tokens, whatever your own account is permitted to do.

A token reaches only an explicit list of methods and paths. Everything on this page is on it, along with the remaining multipart calls — confirming a part, aborting an upload, and checking its status. Anything else answers 401, even a request your account can make in the app: reading a file is permitted while writing to that same path is not.


Creating a token

  1. Open screenapp.io/app/#/settings/api.
  2. Find Personal Access Tokens and select Add new token.
  3. Give it a name — the application that will use it is a good one — and optionally a description.
  4. Choose a lifetime. The default is 90 days; No expiration creates a token that works until you revoke it.
  5. Select the scopes it needs — files:upload to send files, files:read to read them and their transcripts back, files:ask to analyse them with AI.
  6. Select Create Token, then copy it. It is shown once and never again.

Tokens look like sk1- followed by 40 hexadecimal characters. Only the first 12 characters are stored in a readable form, so we can show you which token is which but cannot recover one you have lost. If you lose a token, rotate it.


Authenticating

Send the token in either header. Do not use Authorization: Bearer — that is for session tokens, and a token sent that way is ignored.

x-screenapp-token: sk1-your-token-here
Authorization: ScreenApp-Token sk1-your-token-here

You need your team ID and the ID of the destination folder. Both appear in the URL when you open that folder in the app.


Uploading a file

For files up to 100 MB, ask for an upload URL, PUT the file to it, then finalize.

1. Request an upload URL

POST /v2/files/upload/urls/{teamId}/{folderId}
Content-Type: application/json
x-screenapp-token: sk1-your-token-here
{
"files": [{ "name": "my-video.mp4", "contentType": "video/mp4" }]
}
{
"success": true,
"data": {
"uploadParams": [
{ "fileId": "file_123", "uploadUrl": "https://s3.amazonaws.com/presigned-url" }
]
}
}

2. Send the bytes

PUT https://s3.amazonaws.com/presigned-url
Content-Type: video/mp4
[binary file data]

The presigned URL carries its own authorization. Do not send your token to it.

3. Finalize

Until you finalize, the file does not appear in your library and is not processed.

POST /v2/files/upload/finalize/{teamId}/{folderId}
Content-Type: application/json
x-screenapp-token: sk1-your-token-here
{
"file": {
"fileId": "file_123",
"contentType": "video/mp4",
"name": "My Video Recording",
"description": "Optional description"
}
}

Uploading a large file in parts

For anything larger, upload in parts. Parts may be sent in parallel, and each must be at least 5 MB except the last.

1. Initialize

PUT /v2/files/upload/multipart/init/{teamId}/{folderId}
Content-Type: application/json
x-screenapp-token: sk1-your-token-here
{ "contentType": "video/mp4" }
{ "success": true, "data": { "fileId": "file_123", "uploadId": "upload_456" } }

2. Get a URL per part

Part numbers start at 1.

PUT /v2/files/upload/multipart/url/{teamId}/{folderId}/{fileId}/{uploadId}/{partNumber}
Content-Type: application/json
x-screenapp-token: sk1-your-token-here
{ "contentType": "video/mp4" }
{ "success": true, "data": { "uploadUrl": "https://s3.amazonaws.com/presigned-url-part-1" } }

3. Send each part, then finalize

PUT /v2/files/upload/multipart/finalize/{teamId}/{folderId}/{fileId}/{uploadId}
Content-Type: application/json
x-screenapp-token: sk1-your-token-here
{
"file": {
"contentType": "video/mp4",
"name": "Large Video File",
"notes": []
}
}

Finalizing compares the parts it recorded issuing against what actually arrived in storage. If any are missing you get 409, and re-uploading them before finalizing again is the fix, rather than publishing a truncated file. Treat this as a safety net and not a guarantee: keep your own list of the parts you sent and check it before you finalize.

Abandoning or checking an upload

Abort releases the parts already sent, so a run you have given up on does not sit around:

POST /v2/files/upload/multipart/abort/{teamId}/{folderId}/{fileId}/{uploadId}
x-screenapp-token: sk1-your-token-here

Status reports what storage has received so far, which is useful when resuming:

GET /v2/files/upload/multipart/status/{fileId}
x-screenapp-token: sk1-your-token-here

There is also a confirm call per part, which reports a part as landed and helps us spot uploads that lose one. It is optional and its absence never fails an upload.


Importing from a URL

POST /v2/files/import/{teamId}/{folderId}
Content-Type: application/json
x-screenapp-token: sk1-your-token-here
{
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"options": { "intent": "transcribe" }
}

YouTube, Vimeo, Twitter/X and direct media URLs are supported. Importing is asynchronous: the response identifies the file, and transcription continues after it returns.


Reading files and transcripts

Requires files:read.

List the files in a folder. Paginated with page and limit, defaulting to page 1 and 10 per page. Folders are not returned, so take the folder id from the app URL:

GET /v2/files?page=1&limit=50
x-screenapp-token: sk1-your-token-here

Read one file. The transcript and summary come back on this response, so there is no separate transcript call:

GET /v2/files/{fileId}
x-screenapp-token: sk1-your-token-here

Transcription runs after an upload or import finishes, so poll this until the transcript is present rather than expecting it in the finalize response.


Asking a question about a file

Requires files:ask.

Ask anything about a file that has finished processing, and get an answer back on the same response. This is the endpoint behind Ask AI in the app, so it draws on the file’s transcript and, when you ask for it, the video itself.

POST /v2/files/{fileId}/ask/multimodal
Content-Type: application/json
x-screenapp-token: sk1-your-token-here
{
"promptText": "Summarise the customer's objections and the commitments we made."
}
{
"success": true,
"data": {
"answer": {
"role": "assistant",
"content": "The customer raised three objections…",
"partial": false,
"refusal": ""
},
"sessionId": "session_123"
}
}

Answers accumulate into a conversation per file, identified by sessionId, so follow-up questions build on the ones before them.

To analyse the picture rather than only the words, pass mediaAnalysisOptions. Video analysis is metered separately from text questions and costs more of your allowance:

{
"promptText": "What is shown on screen when pricing is discussed?",
"mediaAnalysisOptions": {
"video": { "segments": [{ "start": 0, "end": 600 }] }
}
}

Every question spends your account’s AI allowance. Once it runs out the endpoint answers 403 until the allowance resets, so ask against a finished transcript rather than polling with questions.

Wait for transcription to finish before asking. Asking too early answers against an incomplete transcript rather than failing.


Webhook notifications

Webhooks need no token and no scope. Configure the destination URL in your settings in the app, and ScreenApp posts to it as work completes. A token cannot read or change webhook settings.


Errors

StatusMeaning
401 with code: INVALID_PERSONAL_ACCESS_TOKENThe token is unknown, expired, revoked, not enabled for the account, or used on an endpoint not listed on this page. Check you copied it whole and that it has not expired.
403The token is valid but not permitted. Usually a scope it lacks, though it can also be the underlying file or team permission, exactly as it would be in the app, or an exhausted AI allowance when asking a question.
404 on a token management routePersonal Access Tokens are not enabled for this account.
409 on multipart finalizeParts are missing. Re-upload them and finalize again.

A 401 always concerns the token itself — unknown, expired, revoked, disabled, or used somewhere tokens may not go. A 403 means authenticated but not allowed, so check the token’s scopes first and then whether the account itself may do it.


Managing tokens

From the same settings page you can:

  • Edit a token — change its name, description or scopes without changing its value. Whatever already uses the token keeps working, so this is how to widen or narrow an integration’s access without a redeploy. A token’s lifetime cannot be changed; rotate or replace it instead.
  • Rotate a token — replaces its value while keeping its name, scopes and lifetime. The old value stops working immediately, so update whatever uses it first.
  • Revoke a token — stops it permanently.

The list shows when each token was last used, which is the quickest way to find one nothing is using any more.


Keeping tokens safe

  1. Treat a token like a password. Keep it out of version control and out of logs.
  2. Give a token only the scopes its job needs.
  3. Prefer an expiring token. Reach for No expiration only where nothing can rotate it.
  4. Rotate on a schedule, and immediately if a token may have leaked.
  5. Revoke tokens you have stopped using — the last-used column shows which.

Need help? See the API overview or write to support@screenapp.io.