# EPUB Translator API Reference

## 1. Pre-upload

**POST** `/apis/file/pre-upload`

**Request body:**

```json
{
  "originalName": "book.epub",
  "size": 1024000,
  "mimeType": "application/epub+zip"
}
```

**Response:**

```json
{
  "success": true,
  "fileId": "abc123",
  "status": "PENDING_UPLOAD",
  "createdAt": "2024-01-01T00:00:00.000Z",
  "preSignedUploadUrl": "https://..."
}
```

If `preSignedUploadUrl` is present, upload the file via `PUT` to that URL. Otherwise use multipart upload to `/apis/file/upload`.

---

## 2. Upload (multipart)

**POST** `/apis/file/upload`

**Content-Type:** `multipart/form-data`

**Fields:**

- `fileId`: string
- `file`: the EPUB file

---

## 3. Check upload status

**POST** `/apis/file/check`

**Request body:**

```json
{
  "fileId": "abc123"
}
```

**Response:**

```json
{
  "success": true,
  "fileId": "abc123",
  "status": "COMPLETED",
  "cost": {
    "fileId": "abc123",
    "charCount": 50000,
    "wordCount": 8500
  }
}
```

The `cost` field contains charCount and wordCount. Tell the user in plain language (e.g. "This book has about X characters/words") and ask if they want to continue.

---

## 4. Check balance

**POST** `/apis/epub-translation/check-balance`

**Request body:**

```json
{
  "fileId": "abc123"
}
```

**Response:**

```json
{
  "sufficient": true,
  "fileId": "abc123",
  "requiredChars": 50000,
  "availableChars": 100000
}
```

If `sufficient` is false, politely inform the user that their balance is insufficient and provide the link https://epubtranslator.app so they can top up.

---

## 5. Start translation

**POST** `/apis/epub-translation/start`

**Request body:**

```json
{
  "fileId": "abc123",
  "targetLanguage": "zh"
}
```

**targetLanguage:** ISO 639-1 code (e.g. `zh`, `en`, `ja`, `es`)

**Response:**

```json
{
  "success": true,
  "fileId": "abc123",
  "message": "Translation started successfully"
}
```

---

## 6. Translation status

**POST** `/apis/epub-translation/status`

**Request body:**

```json
{
  "fileId": "abc123"
}
```

**Response:**

```json
{
  "status": "running",
  "fileId": "abc123",
  "totalChunks": 100,
  "completedChunks": 45,
  "percentage": 45
}
```

When status is `failed`, the response may include an optional `reason`:

- `manual_proofing`: Translation failed and requires manual proofreading. Inform the user that the team is reviewing it and will notify them when ready.
- `translate_failed`: Generic translation failure.

**status:** `pending` | `running` | `completed` | `failed` | `not_found`

Poll every 60 seconds until `status` is `completed` or `failed`.

---

## 7. Get download URL

**POST** `/apis/file/download-url`

**Request body:**

```json
{
  "fileId": "abc123"
}
```

**Response:**

```json
{
  "preSignedDownloadUrl": "https://...",
  "useLocalDownload": false,
  "originalName": "book.epub",
  "mimeType": "application/epub+zip",
  "size": 1024000,
  "targetLanguage": "zh"
}
```

If `preSignedDownloadUrl` is present, use it to download the translated EPUB. If `useLocalDownload` is true, use `POST /apis/file/download` with JSON body `{ fileId }` instead.

---

## Error responses

All errors return JSON:

```json
{
  "error": "Error message",
  "statusCode": 401
}
```

Common status codes:

- 401: Unauthorized (invalid or missing API key) — Prompt the user to log in at epubtranslator.app, bind a payment method, and purchase a credit package
- 400: Bad request (invalid body)
- 404: Not found
