Current API Specs

Code-grounded integration reference for the current MaYi's MaaS public API. The page covers authentication, capability grants, request contracts, response shapes, async job polling, error formats, and the source files behind each route.

Production: https://maas.flyingant.winLocal development: http://localhost:3000

Capability Matrix

Capability Key

health.auth-check

Checks that API key, consumer, capability, and permission wiring are valid.

GET /api/v1/health/auth-check

Capability Key

file.upload

Uploads supported files to public Cloudflare R2 through the MaaS server.

POST /api/v1/files/upload

Capability Key

text.polish

Polishes submitted text through the configured chat provider.

POST /api/v1/text/polish

Capability Key

image.generate

Generates images through Doubao Ark or OpenAI image providers.

POST /api/v1/images/generate

Capability Key

video.generate

Creates async Seedance video generation jobs.

POST /api/v1/videos/generate

Capability Key

audio.transcribe

Creates async Doubao ASR transcription jobs.

POST /api/v1/audio/transcriptions

Common Error Response

Protected route failures use a stable JSON error envelope with a trace id. The HTTP status depends on the error code; examples include 401 for missing or invalid API keys, 403 for denied permissions, 429 for quota failures, 502 for upstream provider failures, and 504 for provider timeouts.

{
  "error": {
    "code": "PERMISSION_DENIED",
    "message": "API key does not have permission for this capability."
  },
  "traceId": "9f4d8f4c-7f57-4f4e-a684-7a99a8b4f2a0"
}

Endpoints

GET
/api/health

Basic deployment health check.

Auth

None

Content Type

application/json

Capability

None

Success Response

{
  "ok": true
}

Implementation Sources

src/app/api/health/route.ts

Notes

  • Use this for deployment liveness only. It does not verify Payload or database connectivity.
GET
/api/health/db

Payload and database readiness check.

Auth

None

Content Type

application/json

Capability

None

Success Response

{
  "database": "ready",
  "ok": true
}

Relevant Error Codes

503 database unavailable

Implementation Sources

src/app/api/health/db/route.tssrc/app/api/health/db/health.ts

Notes

  • This route loads Payload and runs a minimal admin-users query.
  • A failed database check returns status 503 with ok: false.
GET
/api/v1/health/auth-check

Verify protected API authentication and permission wiring.

Auth

Bearer API key plus enabled health.auth-check permission

Content Type

application/json

Capability

health.auth-check

Required Headers

Authorization: Bearer <maas_test_or_live_key>

Success Response

{
  "capabilityKey": "health.auth-check",
  "consumerId": 12,
  "ok": true,
  "traceId": "9f4d8f4c-7f57-4f4e-a684-7a99a8b4f2a0"
}

Relevant Error Codes

MISSING_API_KEYINVALID_API_KEYDISABLED_API_KEYCONSUMER_DISABLEDPERMISSION_DENIED

Implementation Sources

src/app/api/v1/health/auth-check/route.tssrc/app/api/v1/health/auth-check/handler.ts

Notes

  • Use this as the first integration smoke test after creating a consumer, credential, capability, and permission grant.
  • The response includes the resolved consumer id and trace id for support.
POST
/api/v1/files/upload

Upload a public integration file to R2.

Auth

Bearer API key plus enabled file.upload permission

Content Type

multipart/form-data

Capability

file.upload

Required Headers

Authorization: Bearer <maas_test_or_live_key>

Request Fields

file

File

Required
Multipart file. Supported images, audio, video, text, PDF, JSON, CSV, XLS, XLSX, and DOCX content types are accepted.
prefix

string

Optional

Default: uploads

Optional storage prefix. Sanitized and nested under maas/.

Request Example

curl -i http://localhost:3000/api/v1/files/upload \
  -H "Authorization: Bearer <api-key>" \
  -F "file=@./sample.pdf;type=application/pdf" \
  -F "prefix=documents/contracts"

Success Response

{
  "success": true,
  "url": "https://cdn.example.test/maas/documents/contracts/2026-05-20T10-00-00-000Z-a1b2c3d4e5f6.pdf"
}

Relevant Error Codes

FILE_REQUIREDFILE_TOO_LARGEUNSUPPORTED_FILE_TYPESTORAGE_NOT_CONFIGUREDSTORAGE_UPLOAD_FAILEDMISSING_API_KEYPERMISSION_DENIED

Implementation Sources

src/app/api/v1/files/upload/route.tssrc/app/api/v1/files/upload/handler.tssrc/platform/storage/upload-policy.tssrc/platform/storage/object-keys.ts

Notes

  • The file part is required and must use one of the supported content types.
  • Maximum upload size is 4,194,304 bytes.
  • prefix is optional. It is normalized under the maas/ root, so reports/raw becomes maas/reports/raw.
  • Successful uploads return a public R2 URL. File bytes are not stored in Payload.
POST
/api/v1/text/polish

Polish submitted text with the configured chat provider.

Auth

Bearer API key plus enabled text.polish permission

Content Type

application/json

Capability

text.polish

Required Headers

Authorization: Bearer <maas_test_or_live_key>
Content-Type: application/json

Request Fields

text

string

Required
Plain text to polish. Trimmed server side. Maximum 48,000 characters.
provider

doubao | openai | xai

Optional

Default: doubao from code/env

Optional provider override. Accepted values: doubao, openai, xai.

Request Example

{
  "text": "please make this email better",
  "provider": "doubao"
}

Success Response

{
  "success": true,
  "result": {
    "model": "doubao-seed-2-0-lite-260428",
    "provider": "doubao",
    "text": "Please improve this email."
  },
  "usage": {
    "inputTokens": 123,
    "outputTokens": 80,
    "totalTokens": 203
  }
}

Relevant Error Codes

INVALID_JSON_BODYTEXT_REQUIREDTEXT_TOO_LARGEINVALID_LLM_PROVIDERLLM_PROVIDER_NOT_CONFIGUREDLLM_PROVIDER_REQUEST_FAILEDLLM_PROVIDER_TIMEOUTLLM_PROVIDER_UNSUPPORTEDINVALID_MODEL_OUTPUTUSAGE_QUOTA_EXCEEDEDSPEND_BUDGET_EXCEEDEDMISSING_API_KEYPERMISSION_DENIED

Implementation Sources

src/app/api/v1/text/polish/route.tssrc/app/api/v1/text/polish/handler.tssrc/platform/llm/text-polish.tssrc/platform/llm/models.ts

Notes

  • text is trimmed before processing and must be at most 48,000 characters.
  • provider is optional. When omitted, the server uses TEXT_POLISH_PROVIDER or defaults to doubao.
  • Callers cannot submit arbitrary model ids, base URLs, credentials, or system prompts.
  • Successful calls record invocation and usage-ledger rows. Validation and provider failures are not billable usage rows.
POST
/api/v1/images/generate

Generate one or more images.

Auth

Bearer API key plus enabled image.generate permission

Content Type

application/json

Capability

image.generate

Required Headers

Authorization: Bearer <maas_test_or_live_key>
Content-Type: application/json

Request Fields

prompt

string

Required
Image prompt. Maximum 8,000 characters.
provider

doubao | openai

Optional

Default: doubao from code/env

Optional provider override. Accepted values: doubao, openai.
model

string

Optional
Optional model id. It must be the configured image model for the selected provider.
size

string

Optional
Doubao size is normalized to at least 2048x2048. OpenAI accepts 1024x1024, 1024x1536, or 1536x1024 and otherwise normalizes to 1024x1024.
count

number

Optional
Rounded to an integer. Maximum 10 for Doubao and 4 for OpenAI.
responseFormat

url | b64_json

Optional
Doubao only. Accepted values: url, b64_json.
image

string | string[]

Optional
Doubao only. One HTTPS reference image URL or an array of HTTPS reference image URLs.
quality

low | medium | high

Optional
OpenAI only. Accepted values: low, medium, high.
referenceImageUrls

string[]

Optional
OpenAI only. Up to four HTTPS image URLs.
seed

number

Optional
Doubao only. Finite number.
guidanceScale

number

Optional
Doubao only. Finite number.
watermark

boolean

Optional
Doubao only. Boolean.

Request Example

{
  "prompt": "a clean studio photo of a desk lamp",
  "provider": "doubao",
  "size": "2048x2048",
  "count": 1,
  "responseFormat": "url"
}

Success Response

{
  "success": true,
  "result": {
    "images": [
      {
        "url": "https://provider.example.test/image.png"
      }
    ],
    "model": "doubao-seedream-4-5-251128",
    "provider": "doubao"
  },
  "usage": {
    "quantity": 1,
    "source": "generated_image_count",
    "unit": "image"
  }
}

Relevant Error Codes

INVALID_JSON_BODYIMAGE_PROMPT_REQUIREDIMAGE_PROMPT_TOO_LARGEINVALID_LLM_PROVIDERINVALID_IMAGE_PARAMETERLLM_PROVIDER_NOT_CONFIGUREDLLM_PROVIDER_REQUEST_FAILEDLLM_PROVIDER_TIMEOUTLLM_PROVIDER_UNSUPPORTEDINVALID_MODEL_OUTPUTUSAGE_QUOTA_EXCEEDEDSPEND_BUDGET_EXCEEDEDMISSING_API_KEYPERMISSION_DENIED

Implementation Sources

src/app/api/v1/images/generate/route.tssrc/app/api/v1/images/generate/handler.tssrc/platform/llm/image-generation.tssrc/platform/llm/models.ts

Notes

  • prompt is trimmed and must be at most 8,000 characters.
  • provider is optional. Accepted values are doubao and openai.
  • model is optional but must match the configured model for the resolved provider.
  • Doubao accepts responseFormat, image, watermark, seed, and guidanceScale. OpenAI accepts quality and referenceImageUrls.
  • Generated image URLs or base64 values are returned to the caller but are not persisted to Payload or copied to R2 by this route.
POST
/api/v1/videos/generate

Create an async video generation job.

Auth

Bearer API key plus enabled video.generate permission

Content Type

application/json

Capability

video.generate

Required Headers

Authorization: Bearer <maas_test_or_live_key>
Content-Type: application/json
Idempotency-Key: <8-128 printable characters>

Request Fields

prompt or text

string

Required
Required prompt string. Maximum 8,000 characters.
duration or dur

number

Required
Required duration. Accepted values: -1, or an integer from 4 to 15.
provider

doubao

Optional

Default: doubao

Optional. Only doubao is currently accepted.
model

string

Optional

Default: VOLCENGINE_ARK_VIDEO_MODEL or Seedance 2.0 Fast

Optional. Accepted values: doubao-seedance-2-0-260128, doubao-seedance-2-0-fast-260128.
resolution

480p | 720p

Optional

Default: 720p

Optional. Accepted values: 480p, 720p.
ratio

string

Optional
Optional provider ratio string, such as 16:9.
seed

number | string integer

Optional

Default: -1

Optional integer from -1 to 4294967295.
generateAudio

boolean

Optional

Default: true in provider body when omitted

Optional boolean.
imageItems

array

Optional
Optional explicit reference image objects. Max 9. Each item has url, role, and detail. role is first_frame, last_frame, or reference_image. detail is auto, low, or high.
imageUrls, imageUrl, extraImageUrls, referenceImageUrls

string | string[]

Optional
Optional compatibility aliases for HTTPS image URLs. The first image defaults to first_frame unless using referenceImageUrls.
videoItems, videoUrls, videoUrl

array | string[] | string

Optional
Optional HTTPS reference video inputs. Max 3. videoItems also accepts fps, startTime/start_time, and endTime/end_time.
audioItems, audioUrls, audioUrl

array | string[] | string

Optional
Optional HTTPS reference audio inputs. Max 3. Requires at least one reference image or reference video.
callbackUrl

string

Optional
Optional HTTPS callback URL passed to Ark.
imageBeforeText, returnLastFrame, watermark

boolean

Optional
Optional booleans.

Request Example

{
  "prompt": "A clean product video of a matte black desk lamp rotating on a white table.",
  "model": "doubao-seedance-2-0-fast-260128",
  "duration": 5,
  "resolution": "720p",
  "ratio": "16:9",
  "seed": -1,
  "watermark": false,
  "generateAudio": true,
  "imageUrls": [
    "https://cdn.example.test/lamp.png"
  ],
  "imageRole": "first_frame",
  "primaryImageDetail": "high",
  "returnLastFrame": true
}

Success Response

{
  "success": true,
  "job": {
    "capabilityKey": "video.generate",
    "createdAt": "2026-05-20T10:00:00.000Z",
    "jobId": "job_video123",
    "status": "submitted"
  }
}

Relevant Error Codes

MISSING_IDEMPOTENCY_KEYINVALID_IDEMPOTENCY_KEYIDEMPOTENCY_CONFLICTINVALID_JSON_BODYINVALID_VIDEO_REQUESTINVALID_LLM_PROVIDERLLM_PROVIDER_NOT_CONFIGUREDLLM_PROVIDER_REQUEST_FAILEDLLM_PROVIDER_TIMEOUTLLM_PROVIDER_UNSUPPORTEDINVALID_MODEL_OUTPUTMISSING_API_KEYPERMISSION_DENIED

Implementation Sources

src/app/api/v1/videos/generate/route.tssrc/app/api/v1/videos/generate/handler.tssrc/platform/llm/video-generation.tssrc/platform/async-jobs/create-async-job.ts

Notes

  • This is an async create route. Poll the returned jobId with GET /api/v1/jobs/{jobId}.
  • Reusing the same Idempotency-Key with the same normalized request returns the existing job. Reusing it with a different request returns IDEMPOTENCY_CONFLICT.
  • duration must be -1 or an integer from 4 to 15 seconds.
  • Only Seedance 2.0 and Seedance 2.0 Fast are supported. draft and draftTaskId are intentionally rejected.
  • Reference audio requires at least one reference image or reference video.
POST
/api/v1/audio/transcriptions

Create an async audio transcription job.

Auth

Bearer API key plus enabled audio.transcribe permission

Content Type

application/json

Capability

audio.transcribe

Required Headers

Authorization: Bearer <maas_test_or_live_key>
Content-Type: application/json
Idempotency-Key: <8-128 printable characters>

Request Fields

audioUrl

string

Required
Required HTTPS audio URL.
format

string

Required
Required provider audio format string, for example m4a, mp3, wav, or webm.
duration

number

Required
Required positive number in seconds.
provider

doubao

Optional
Optional. Only doubao is currently accepted.
codec

string

Optional
Optional codec hint.
language

string

Optional
Optional language hint.

Request Example

{
  "audioUrl": "https://cdn.example.test/audio/meeting.m4a",
  "format": "m4a",
  "codec": "aac",
  "duration": 31.4,
  "language": "zh-CN"
}

Success Response

{
  "success": true,
  "job": {
    "capabilityKey": "audio.transcribe",
    "createdAt": "2026-05-20T10:00:00.000Z",
    "jobId": "job_audio123",
    "status": "submitted"
  }
}

Relevant Error Codes

MISSING_IDEMPOTENCY_KEYINVALID_IDEMPOTENCY_KEYIDEMPOTENCY_CONFLICTINVALID_JSON_BODYINVALID_AUDIO_TRANSCRIPTION_REQUESTAUDIO_DURATION_REQUIREDINVALID_LLM_PROVIDERLLM_PROVIDER_NOT_CONFIGUREDLLM_PROVIDER_REQUEST_FAILEDLLM_PROVIDER_TIMEOUTMISSING_API_KEYPERMISSION_DENIED

Implementation Sources

src/app/api/v1/audio/transcriptions/route.tssrc/app/api/v1/audio/transcriptions/handler.tssrc/platform/llm/audio-transcription.tssrc/platform/async-jobs/create-async-job.ts

Notes

  • This is an async create route. Poll the returned jobId with GET /api/v1/jobs/{jobId}.
  • audioUrl must be HTTPS.
  • duration is required in seconds and is rounded to at least one second for request metadata and fallback usage.
  • DOUBAO_ASR_API_KEY is preferred. If unset, the server falls back to DOUBAO_API_KEY.
GET
/api/v1/jobs/{jobId}

Poll an async video or audio transcription job.

Auth

Bearer API key; job must belong to the resolved consumer and caller must still have permission for the job capability

Content Type

application/json

Capability

None

Required Headers

Authorization: Bearer <maas_test_or_live_key>

Request Fields

jobId

string

Required
Path parameter returned by an async create route. Public ids start with job_.

Success Response

{
  "success": true,
  "job": {
    "capabilityKey": "video.generate",
    "finishedAt": "2026-05-20T10:02:00.000Z",
    "jobId": "job_video123",
    "result": {
      "providerVideoUrl": "https://provider.example.test/video.mp4",
      "videoKey": "maas/video-results/job_video123.mp4",
      "videoUrl": "https://cdn.example.test/maas/video-results/job_video123.mp4"
    },
    "status": "succeeded",
    "usage": {
      "quantity": 42,
      "source": "provider",
      "unit": "provider_unit"
    }
  }
}

Relevant Error Codes

JOB_NOT_FOUNDPERMISSION_DENIEDCONSUMER_DISABLEDJOB_PROVIDER_TASK_MISSINGJOB_PROVIDER_QUERY_FAILEDJOB_RESULT_PERSIST_FAILEDMISSING_API_KEYINVALID_API_KEYDISABLED_API_KEY

Implementation Sources

src/app/api/v1/jobs/[jobId]/route.tssrc/app/api/v1/jobs/[jobId]/handler.tssrc/platform/async-jobs/poll-async-job.ts

Notes

  • Unknown jobs and jobs owned by another consumer both return JOB_NOT_FOUND.
  • The route checks the saved job capability key, so a video job still requires video.generate permission and an audio job still requires audio.transcribe permission.
  • Terminal jobs are returned from the database without provider polling. Non-terminal jobs refresh provider state.
  • Successful video jobs are copied from the provider URL to R2 before returning succeeded. Successful audio jobs return transcript text from the provider snapshot.
  • Usage is recorded once when a job reaches succeeded.

Admin-Only API

POST/api/api-credentials/generate

Authenticated Payload super-admin session only. Creates a new raw API key or rotates an existing credential.

src/components/admin/api-credential-generate-form.tsdocs/api/api-key-generation.md