API Documentation
UU Studio の UUScribe API を使って、文字起こしタスクの作成、監視、エクスポートができます。
Base URL
https://scribe.uustudio.cc
Authentication
Third-party integrations must send a paid account API key in the Authorization header.
Authorization Header
Authorization: Bearer {token}Create and revoke API keys from the API Keys page in account settings. App authentication endpoints are reserved for first-party clients.
Error Responses
All errors return a JSON body with a message field.
Standard Error
{
"message": "Description of the error"
}Validation Error (422)
{
"message": "The name field is required.",
"errors": {
"name": ["The name field is required."]
}
}| Status | Description |
|---|---|
| 401 | Not authenticated (missing or invalid token) |
| 403 | Forbidden or plan limit exceeded |
| 404 | Resource not found |
| 422 | Validation failed |
| 429 | Rate limited or too many concurrent tasks |
| 500 | Internal server error |
Rate Limits
Authenticated API endpoints are limited to 10 requests per minute per token.
Usage Limits
API availability
API アクセスは有料プランで利用でき、無料プランでは利用できません。
- Max file size
- 2 GB
- Concurrent tasks
- Max 3
- Max retries per task
- 3
Paid plan comparison
| Feature | Pay as you go | Pro | Max |
|---|---|---|---|
| Daily uploads | Unlimited | Unlimited | Unlimited |
| Export formats | All | All | All |
| Task priority | Medium | Medium | High |
Workflows
Upload Audio/Video File
POST /api/uploads/sign→ Get upload_id and part infoPUT {presigned_url}→ Upload each part to storagePOST /api/uploads/complete→ Finish upload, auto-create taskGET /api/tasks/{id}→ Poll status (pending -> scribing -> finished)GET /api/tasks/{id}/download/srt→ Export (optional)
Create Task Manually
POST /api/tasks→ Create with disk, path, nameGET /api/tasks/{id}→ Poll statusGET /api/tasks/{id}→ Get segments, summary, mindmap
Auth
/api/loginAuthenticate with email and password. Returns a Sanctum token.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | User email (max 255) | |
| password | string | Yes | User password |
Response 200
{
"token": "1|abc123...",
"user": {
"id": 1,
"name": "Zhang San",
"email": "[email protected]"
}
}Throttled to 5 attempts per minute per email.
/api/registerCreate a new account. Returns a Sanctum token.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Display name (max 255) |
| string | Yes | Unique email (max 255) | |
| password | string | Yes | Must be confirmed |
| password_confirmation | string | Yes | Password confirmation |
Response 201
{
"token": "1|abc123...",
"user": {
"id": 1,
"name": "Zhang San",
"email": "[email protected]"
}
}/api/logoutRevoke the current access token.
Response 204
Returns no body.
Tasks
/api/tasksCreate a transcription task. Max 3 concurrent tasks per user.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| disk | string | Yes | r2 / remote / youtube Storage source identifier |
| name | string | Yes | Task name (max 255) |
| path | string | Yes | File path or source URL |
| file | string | No | Original file name (max 255) |
| size | integer | No | File size in bytes |
| duration | integer | No | Duration in seconds |
| cost | integer | No | Cost in seconds |
| segments | array | No | Transcript segments |
| speaker_diarization | boolean | No | app.tasks.speaker_diarization_api_description |
Response 201
{
"id": 1,
"name": "Meeting Recording",
"status": "pending",
"speaker_diarization": true,
"created_at": "2026-03-02T10:30:00+08:00"
}Errors
| Status | Description |
|---|---|
| 403 | Free users cannot submit YouTube links via the API. |
| 429 | Max 3 concurrent tasks reached |
/api/tasks/{id}Get full task details including transcription results.
Response
{
"id": 1,
"name": "Meeting Recording",
"file": "meeting.mp3",
"path": "2026-03-02/01HQX...mp3",
"disk": "r2",
"size": 50545869,
"duration": 1965,
"cost": 33,
"status": "finished",
"attempts": 1,
"quality": 3,
"created_at": "2026-03-02T10:30:00+08:00",
"updated_at": "2026-03-02T10:45:00+08:00",
"summary": "The meeting discussed three topics...",
"mindmap": "# Topic\n## Sub-topic 1",
"folder": "Work",
"tags": ["Work"],
"url": "https://youtube.com/watch?v=...",
"segments": [
{
"id": 1,
"start": 0,
"end": 5000,
"speaker": "Speaker 1",
"tokens": ["Okay", "so let's", "begin"],
"text": "Okay, so let's begin..."
}
],
"export": {
"allowed_formats": ["txt", "srt", "vtt", "csv", "pdf", "docx"],
"heavy_formats": ["pdf", "docx"],
"version": "20260302104500"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
| disk | string|null | Storage disk: r2 / remote / youtube |
| size | int|null | File size in bytes |
| cost | int|null | Cost in seconds |
| attempts | int | Retry attempt count |
| quality | int|null | Quality score (0-5) |
| summary | string|null | AI-generated summary |
| mindmap | string|null | AI-generated mind map |
| folder | string|null | First tag name (folder) |
| tags | array | All tag names |
| url | string|null | Source URL (for YouTube tasks) |
| segments | array|null | Transcript segments |
| segments[].start | int | Start time (ms) |
| segments[].end | int | End time (ms) |
| segments[].text | string | Segment text |
| segments[].speaker | string|null | Speaker identifier |
| segments[].tokens | array|null | Word token array |
| export | object | Export metadata (allowed_formats, heavy_formats, version) |
/api/tasksQuery Parameters
| Param | Type | Default | Description |
|---|---|---|---|
| status | string | all | Filter by status |
| search | string | — | Search by name |
| folder | string | — | Filter by folder (or Uncategorized) |
| page | int | 1 | Page number |
| per_page | int | 25 | Items per page (max 100) |
Response
{
"data": [
{
"id": 1,
"name": "Meeting Recording",
"file": "meeting.mp3",
"disk": "r2",
"size": 50545869,
"duration": 1965,
"cost": 33,
"status": "finished",
"attempts": 1,
"quality": 3,
"folder": "Work",
"created_at": "2026-03-02T10:30:00+08:00"
}
],
"current_page": 1,
"last_page": 1,
"per_page": 25,
"total": 1
}/api/tasks/{id}/retryRetry a failed task. Sets status to pending (R2) or waiting (remote/YouTube). Max 3 retries.
Response 200
{
"id": 1,
"status": "pending",
"attempts": 2
}/api/tasks/{id}/download/{format}Export transcript. Light formats return the file directly. Heavy formats (pdf/docx) may return 202 while processing.
Path Parameters
| Param | Description |
|---|---|
| format | txt / srt / vtt / csv / pdf / docx |
Responses
200 - File ready (light formats)
Returns a binary file.
200 - File ready (heavy formats, JSON request)
{
"status": "ready",
"url": "https://scribe.uustudio.cc/api/tasks/1/download/pdf"
}202 - Processing heavy format
{
"status": "processing",
"message": "Your export is being generated. Please try again shortly."
}/api/tasks/{id}/audioStream the original audio or video file directly from storage (R2 only).
Response
200 - Binary stream of the audio or video file. Returns 404 if the file is missing or not stored on the R2 disk.
/api/tasks/{id}/refresh-summaryRefresh and return the latest AI-generated summary and mind map.
Response
{
"summary": "The meeting discussed three topics...",
"mindmap": "# Topic\n## Sub-topic 1"
}/api/tasks/{id}Update task fields. All fields are optional.
Request Body
| Field | Type | Description |
|---|---|---|
| name | string | New name (max 255) |
| folder | string|null | Folder name (null removes the task from a folder) |
| duration | integer | Duration in seconds |
| cost | integer | Cost in seconds |
| segments | array | Full segment array to replace |
| text | string | Full transcript text |
| quality | integer | Quality score (0-5) |
| index | integer | Task order index |
Response 200
Returns the full task object (same as Task Detail).
/api/tasks/{id}Response 200
{
"message": "Task deleted successfully"
}/api/tasks/bulkDelete multiple tasks at once. Only tasks belonging to the authenticated user will be deleted. IDs that do not belong to the user are silently ignored.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| ids | array | Yes | Array of task IDs to delete (min 1) |
Response 200
{
"message": "2 task(s) deleted successfully",
"deleted_count": 2
}/api/tasks/bulk/moveMove multiple tasks to a folder at once. Only tasks belonging to the authenticated user will be moved.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| ids | array | Yes | Array of task IDs to move (min 1) |
| folder | string | Yes | Target folder name (max 255) |
Response 200
{
"message": "2 task(s) moved to Work",
"moved_count": 2
}Uploads
Multipart Upload/api/uploads/signRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| file | string | Yes | File name (must use a supported format) |
| content_type | string | Yes | MIME type (must match the file extension) |
| size | integer | Yes | File size in bytes (max 2,147,483,648 / 2 GB) |
| duration | integer | No | Audio duration in seconds |
Response
{
"path": "2026-03-02/01HQX...mp3",
"upload_id": "abc123",
"part_size": 5242880,
"part_count": 10,
"expires_at": "2026-03-02T10:40:00+08:00"
}/api/uploads/sign-partRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| path | string | Yes | Upload path (max 2048) |
| upload_id | string | Yes | Upload ID (max 2048) |
| part_number | integer | Yes | Part number (1-10000) |
Response
{
"url": "https://storage.example.com/...?X-Amz-...",
"headers": {
"Content-Type": "audio/mpeg"
}
}Use PUT with the returned URL and headers to upload the part.
/api/uploads/completeComplete a multipart upload. This auto-creates a transcription task and returns 403 when API access is unavailable or a plan limit is exceeded.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| path | string | Yes | Upload path (max 2048) |
| upload_id | string | Yes | Upload ID (max 2048) |
| original_name | string | Yes | Original file name (must use a supported format) |
| content_type | string | Yes | MIME type (must match the file extension) |
| size | integer | Yes | File size in bytes (max 2 GB) |
| name | string | No | Task name (defaults to the filename without extension) |
| duration | integer | No | Duration in seconds (min 1) |
| speaker_diarization | boolean | No | app.tasks.speaker_diarization_api_description |
Response 201
{
"message": "File uploaded to the upload server successfully.",
"task": {
"id": 1,
"name": "meeting",
"path": "2026-03-02/01HQX...mp3",
"size": 50545869,
"status": "pending",
"speaker_diarization": true
}
}/api/uploads/abortRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| path | string | Yes | Upload path (max 2048) |
| upload_id | string | Yes | Upload ID (max 2048) |
Response
{
"message": "Multipart upload cancelled successfully."
}Folders
Tag-based/api/foldersList all folders with task counts.
Response
{
"folders": [
{"id": 1, "name": "Work", "count": 5},
{"id": 2, "name": "Personal", "count": 3}
],
"uncategorized_count": 2,
"total_count": 10
}/api/foldersRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Folder name (max 14 chars / 7 Chinese chars, unique per user) |
Response 201
{
"id": 1,
"name": "Work"
}/api/folders/{name}Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | New folder name (same constraints as create) |
Response 200
{
"id": 1,
"name": "New Name"
}/api/folders/{name}Response 200
{
"message": "Folder deleted successfully"
}User
/api/userResponse
{
"id": 1,
"name": "Zhang San",
"email": "[email protected]",
"avatar": "https://...",
"balance": {
"used_seconds": 9000,
"remaining_seconds": 36000,
"allowance_remaining_seconds": 30000,
"top_up_remaining_seconds": 6000,
"total_seconds": 45000,
"usage_percent": 20
},
"subscription": {
"plan": "year",
"plan_key": "max_yearly",
"tier": "max",
"billing_interval": "yearly",
"active": true,
"access_tier": "max"
},
"queue": {
"pending_count": 1,
"running_count": 1,
"failed_count": 0
}
}Balance Fields
| Field | Type | Description |
|---|---|---|
| used_seconds | int | Seconds used since the last monthly grant |
| remaining_seconds | int | Remaining seconds |
| total_seconds | int | Total seconds |
| usage_percent | int | Usage percentage (0-100) |
/api/userRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | No | Display name (max 255) |
| string | No | New email (must be unique) | |
| avatar | file | No | Image file (max 5 MB) |
Response 200
{
"id": 1,
"name": "New Name",
"email": "[email protected]",
"avatar": "https://..."
}Notifications
/api/notificationsGet the 10 most recent notifications.
Response
[
{
"id": "abc123",
"title": "Task Completed",
"message": "Meeting Recording has been transcribed.",
"read_at": null,
"created_at": "2026-03-02T10:45:00+08:00"
}
]/api/notifications/mark-all-as-readMark all unread notifications as read.
Response 200
{
"success": true
}Checkout
/api/checkout/{plan}Get a Paddle checkout URL for a subscription plan.
Path Parameters
| Param | Description |
|---|---|
| plan | test / month / year |
Response
Returns a Paddle checkout options object. Returns 404 for an invalid plan.
/api/healthPublic health check endpoint. No authentication required.
Response 200
{
"status": "ok"
}
/api/auth/social-loginAuthenticate via Google OAuth. Creates an account if it does not exist.
Request Body
googlesupported providersResponse 200