Authentication
API key authentication flow
The NoLang API uses API key authentication. Include the following header in every request.
Authorization: Bearer YOUR_API_KEYManaging API keys
- Generation In the sidebar, open “NoLang API” → “API Key Management” and click “New API Key”
- Permission An API key has the same permissions as your user account
- Deletion Delete keys promptly once you no longer use them
Security best practices
- Store it in an environment variable Avoid hard-coding it
- HTTPS only All API traffic goes over HTTPS
- Rotate your keys regularly
# Enter the key without echoing itread -rsp "Enter your NoLang API key: " NOLANG_API_KEY && echo
# Call the API with the variablecurl -X POST https://api.no-lang.com/v1/videos/generate/ \ -H "Authorization: Bearer $NOLANG_API_KEY" \ -F "video_setting_id=$VIDEO_SETTING_ID" \ -F "text=Hello, this is a test of the NoLang API."
# Clear the variable when you are done, just in caseunset NOLANG_API_KEYCommon specifications
Base URL and version
- Production:
https://api.no-lang.com/v1 - Versioning: The URL path includes the version (currently v1)
Request format
Headers
Authorization: Bearer YOUR_API_KEYContent-Type: multipart/form-data # For file uploadsContent-Type: application/json # For JSON requestsPagination
List endpoints use the following query parameters.
-
pagePage number (starts at 1) - Fixed at 50 items per page
curl "https://api.no-lang.com/v1/videos/?page=2" \ -H "Authorization: Bearer YOUR_API_KEY"Rate limits and concurrency limits
Rate Limit
| Endpoint | Limit | When exceeded |
|---|---|---|
POST /videos/generate/POST /videos/{video_id}/conversions/ | Up to 2 requests per 10 seconds | 429 error |
| Other endpoints | Up to 5 requests per 10 seconds (1 per 2 seconds) | 429 error |
Concurrency limits
- Video generation: up to 2 videos can be generated in parallel per user account. Exceeding this returns a 503 error.
- Video conversion is subject to the same concurrency limit as video generation. Exceeding it returns a 503 error.
- Note: The limit applies per user account, not per API key. Issuing multiple API keys does not increase the number of concurrent generations.
Error handling
Error response format
{ "error_code": "ERROR_CODE", "error": "Detailed error description"}Retry strategy
- 5xx errors: Retry up to 3 times with exponential backoff
- 503 error: Wait until server load decreases (recommended: 30 seconds to 1 minute)
- 429 error: Wait until the rate limit resets
- Other: No retry needed
Endpoint
POST /videos/generate/
Requests generation of a new video.
Parameters
| Name | Type | Personal Plan | Business Plan | Required | Description | ||
|---|---|---|---|---|---|---|---|
| Supported formats | Size | Supported formats | Size | ||||
video_setting_id | string (UUID) | Required | ID of the video setting to use | ||||
text | string | Conditional | Text for video generation (required in generate-from-question/instruction mode) | ||||
pdf_file | file | 100MB | 180MB | Conditional | PDF file (required in generate-from-documents mode) | ||
pptx_file | file | .pptx | 100MB | .pptx | 180MB | Conditional | PPTX file (required in generate-from-documents mode) |
audio_file | file | .mp3, .wav, .m4a, .aac | 50MB | .mp3, .wav, .m4a, .aac | 180MB | Conditional | Audio file (required in generate-from-audio mode) |
video_file | file | .mp4 | 50MB | .mp4, .mov, .webm | 180MB | Conditional | Video file (required in generate-from-video mode) |
image_files | list of file | .png, .jpg, .jpeg, .webp | 10MB x 10 | .png, .jpg, .jpeg, .webp | 10MB x 10 | Optional | List of image files (can be specified in generate-from-question/instruction mode) |
Example response
{ "video_id": "550e8400-e29b-41d4-a716-446655440000"}Request examples by video mode
curl -X POST https://api.no-lang.com/v1/videos/generate/ \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "video_setting_id=YOUR_VIDEO_SETTING_ID" \ -F "text=What is machine learning? Please explain it briefly"curl -X POST https://api.no-lang.com/v1/videos/generate/ \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "video_setting_id=YOUR_VIDEO_SETTING_ID" \ -F "text=NoLang is a service developed by Mavericks, Inc. that generates videos in real time."curl -X POST https://api.no-lang.com/v1/videos/generate/ \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "video_setting_id=YOUR_VIDEO_SETTING_ID" \ -F "pdf_file=@company_presentation.pdf"curl -X POST https://api.no-lang.com/v1/videos/generate/ \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "video_setting_id=YOUR_VIDEO_SETTING_ID" \ -F "pptx_file=@annual_report.pptx"curl -X POST https://api.no-lang.com/v1/videos/generate/ \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "video_setting_id=YOUR_VIDEO_SETTING_ID" \ -F "text=Analyze this company's strengths and weaknesses in comparison with its competitors" \ -F "pdf_file=@company_report_2024.pdf"curl -X POST https://api.no-lang.com/v1/videos/generate/ \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "video_setting_id=YOUR_VIDEO_SETTING_ID" \ -F "audio_file=@lecture_recording.mp3"curl -X POST https://api.no-lang.com/v1/videos/generate/ \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "video_setting_id=YOUR_VIDEO_SETTING_ID" \ -F "video_file=@original_video.mp4" GET /videos/
Retrieves a list of the videos you have generated.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
page | integer | Optional | Page number (default: 1) |
Example response
{ "results": [ { "video_id": "550e8400-e29b-41d4-a716-446655440000", "created_at": "2024-01-15T09:30:00Z", "prompt": "Explain the evolution of AI in 5 minutes." }, { "video_id": "660e8400-e29b-41d4-a716-446655440001", "created_at": "2024-01-15T08:20:00Z", "prompt": "Marketing strategy basics" } ], "has_next": false, "total_count": 5, "page": 1, "items_per_page": 50} GET /videos/{video_id}/
Retrieves the generation status and download URL of a specific video.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
video_id | string (UUID) | Required | Video ID |
Status values
-
running— Generating -
completed— Generation complete (available for download) -
failed— Generation failed -
expired— Expired
Example response
{ "video_id": "550e8400-e29b-41d4-a716-446655440000", "status": "running", "download_url": "", "copyright": []}{ "video_id": "550e8400-e29b-41d4-a716-446655440000", "status": "completed", "download_url": "https://s3.no-lang.com/asset/example.mp4?X-Amz-Algorithm=...", "copyright": [...]}-
completedOnly videos in this status can be downloaded -
download_urlis a temporary presigned URL (it expires)
GET /videos/{video_id}/conversions/
Retrieves whether a specific video supports language and aspect ratio conversion, along with the list of values you can specify as the conversion target.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
video_id | string (UUID) | Required | ID of the source video. You can specify only videos you own |
Response fields
-
is_convertible— Whether this video supports conversion. false when there is no generated video data or when the video includes a real avatar -
current_language— Current language of the source video -
available_languages— List of language codes you can specify as the conversion target (varies by video) -
current_aspect_ratio— Current aspect ratio of the source video -
available_aspect_ratios— List of aspect ratios you can specify as the conversion target (always all 7 for convertible videos)
Example response
{ "is_convertible": true, "current_language": "ja", "available_languages": ["ja", "en"], "current_aspect_ratio": "16:9", "available_aspect_ratios": ["16:9", "9:16", "4:3", "1:1", "4:5", "2:3", "21:9"]} POST /videos/{video_id}/conversions/
Asynchronously generates a new video by converting an existing video into another language or aspect ratio. The source video is left unchanged. Poll the new video_id returned in the response with GET /videos/{video_id}/ and confirm completion in the same way as for video generation.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
language | string | Conditional | Language code after conversion. At least one of this and aspect_ratio must be specified. The same value as the source video cannot be specified |
aspect_ratio | string | Conditional | Aspect ratio after conversion. At least one of this and language must be specified. The same value as the source video cannot be specified |
Values you can specify for aspect_ratio
16:9 9:16 4:3 1:1 4:5 2:3 21:9
Values you can specify for language (all 34 languages)
- Japanese
ja - English
en - Chinese (Simplified)
zh-Hans - Chinese (Traditional)
zh-Hant - Korean
ko - Spanish
es - French
fr - German
de - Italian
it - Portuguese
pt - Russian
ru - Hindi
hi - Bengali
bn - Indonesian
id - Thai
th - Vietnamese
vi - Tagalog
tl - Malay
ms - Burmese
my - Nepali
ne - Mongolian
mn - Turkish
tr - Swedish
sv - Danish
da - Finnish
fi - Polish
pl - Czech
cs - Slovak
sk - Dutch
nl - Romanian
ro - Croatian
hr - Bulgarian
bg - Ukrainian
uk - Greek
el
Example response
{ "video_id": "550e8400-e29b-41d4-a716-446655440000"}-
video_idis the ID of the new video created by the conversion (different from the source video ID)
Error code
| error_code | HTTP | Condition |
|---|---|---|
CONVERT_TARGET_REQUIRED | 400 | Neither language nor aspect_ratio is specified |
INVALID_LANGUAGE | 400 | language is set to a value that is not a supported language code |
INVALID_ASPECT_RATIO | 400 | aspect_ratio is set to an unsupported value |
LANGUAGE_NOT_SUPPORTED_BY_VOICES | 400 | The language you specified is not included in the available_languages of the source video |
CONVERT_NO_CHANGE | 400 | Every value you specified is identical to the source video (nothing changes) |
SOURCE_VIDEO_NOT_CONVERTIBLE | 400 | The source video does not support conversion (is_convertible is false) |
UNSUPPORTED_HEAVY_AVATAR | 400 | The source video contains a real avatar |
NOT_FOUND | 404 | video_id does not exist, or the video is not one you own |
INSUFFICIENT_CREDIT | 429 / 403 | Insufficient credit balance (429), or a plan below Standard / Premium (403) |
SIMULTANEOUS_GENERATE_LIMIT | 503 | The concurrency limit shared with video generation was exceeded |
UNKNOWN_ERROR | 500 | Internal server error |
- If authentication fails, a 401 / 403 error is returned separately from the errors above
Example request
curl https://api.no-lang.com/v1/videos/YOUR_VIDEO_ID/conversions/ \ -H "Authorization: Bearer YOUR_API_KEY"curl -X POST https://api.no-lang.com/v1/videos/YOUR_VIDEO_ID/conversions/ \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"language": "en"}'curl -X POST https://api.no-lang.com/v1/videos/YOUR_VIDEO_ID/conversions/ \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"aspect_ratio": "9:16"}' GET /video-settings/
Retrieves a list of available video settings.
Example response
{ "results": [ { "video_setting_id": "123e4567-e89b-12d3-a456-426614174000", "updated_at": "2024-01-15T10:00:00Z", "created_at": "2024-01-10T10:00:00Z", "title": "Educational content settings", "request_fields": ["text"] }, { "video_setting_id": "223e4567-e89b-12d3-a456-426614174001", "updated_at": "2024-01-14T09:00:00Z", "created_at": "2024-01-09T09:00:00Z", "title": "Presentation conversion settings", "request_fields": ["pdf_file"] } ], "has_next": false, "total_count": 5, "page": 1, "items_per_page": 50}Sample code
import osimport timeimport requestsfrom typing import Optional
class NoLangAPI: def __init__(self, api_key: str): self.api_key = api_key self.base_url = "https://api.no-lang.com/v1" self.headers = {"Authorization": f"Bearer {api_key}"}
def generate_video_from_text(self, video_setting_id: str, text: str) -> dict: """Generate a video from text""" url = f"{self.base_url}/videos/generate/" data = { "video_setting_id": video_setting_id, "text": text } response = requests.post(url, headers=self.headers, data=data) response.raise_for_status() return response.json()
def generate_video_from_pdf(self, video_setting_id: str, pdf_path: str) -> dict: """Generate a video from a PDF""" url = f"{self.base_url}/videos/generate/" data = {"video_setting_id": video_setting_id} files = {"pdf_file": open(pdf_path, "rb")} response = requests.post(url, headers=self.headers, data=data, files=files) response.raise_for_status() return response.json()
def get_video_status(self, video_id: str) -> dict: """Retrieve the status of a video""" url = f"{self.base_url}/videos/{video_id}/" response = requests.get(url, headers=self.headers) response.raise_for_status() return response.json()
def get_convert_options(self, video_id: str) -> dict: """Retrieve whether a video can be converted and the values you can convert it to""" url = f"{self.base_url}/videos/{video_id}/conversions/" response = requests.get(url, headers=self.headers) response.raise_for_status() return response.json()
def convert_video( self, video_id: str, language: Optional[str] = None, aspect_ratio: Optional[str] = None, ) -> dict: """Generate a new video by converting an existing video to another language or aspect ratio""" url = f"{self.base_url}/videos/{video_id}/conversions/" payload = {} if language: payload["language"] = language if aspect_ratio: payload["aspect_ratio"] = aspect_ratio response = requests.post(url, headers=self.headers, json=payload) response.raise_for_status() return response.json()
def wait_for_completion(self, video_id: str, timeout: int = 600) -> Optional[str]: """Wait for video generation to finish and return the download URL""" start_time = time.time() while time.time() - start_time < timeout: status_data = self.get_video_status(video_id) if status_data["status"] == "completed": return status_data["download_url"] elif status_data["status"] == "failed": raise Exception("Video generation failed") time.sleep(10) # Poll every 10 seconds raise TimeoutError("Video generation timed out")
# Example usageapi = NoLangAPI(os.environ["NOLANG_API_KEY"])
# Generate a video from textresult = api.generate_video_from_text( video_setting_id="123e4567-e89b-12d3-a456-426614174000", text="Let's learn the basics of Python programming")print(f"Video ID: {result['video_id']}")
# Wait for completion and downloaddownload_url = api.wait_for_completion(result['video_id'])print(f"Download URL: {download_url}")
# Convert the generated video to English + vertical (9:16)options = api.get_convert_options(result['video_id'])if options["is_convertible"] and "en" in options["available_languages"]: converted = api.convert_video(result['video_id'], language="en", aspect_ratio="9:16") converted_url = api.wait_for_completion(converted['video_id']) print(f"Converted URL: {converted_url}")const axios = require('axios');const FormData = require('form-data');const fs = require('fs');
class NoLangAPI { constructor(apiKey) { this.apiKey = apiKey; this.baseUrl = 'https://api.no-lang.com/v1'; this.headers = { 'Authorization': `Bearer ${apiKey}` }; }
async generateVideoFromText(videoSettingId, text) { const formData = new FormData(); formData.append('video_setting_id', videoSettingId); formData.append('text', text);
const response = await axios.post( `${this.baseUrl}/videos/generate/`, formData, { headers: { ...this.headers, ...formData.getHeaders() } } ); return response.data; }
async generateVideoFromPDF(videoSettingId, pdfPath) { const formData = new FormData(); formData.append('video_setting_id', videoSettingId); formData.append('pdf_file', fs.createReadStream(pdfPath));
const response = await axios.post( `${this.baseUrl}/videos/generate/`, formData, { headers: { ...this.headers, ...formData.getHeaders() } } ); return response.data; }
async getVideoStatus(videoId) { const response = await axios.get( `${this.baseUrl}/videos/${videoId}/`, { headers: this.headers } ); return response.data; }
async getConvertOptions(videoId) { const response = await axios.get( `${this.baseUrl}/videos/${videoId}/conversions/`, { headers: this.headers } ); return response.data; }
async convertVideo(videoId, { language, aspectRatio } = {}) { const payload = {}; if (language) payload.language = language; if (aspectRatio) payload.aspect_ratio = aspectRatio;
const response = await axios.post( `${this.baseUrl}/videos/${videoId}/conversions/`, payload, { headers: { ...this.headers, 'Content-Type': 'application/json' } } ); return response.data; }
async waitForCompletion(videoId, timeout = 600000) { const startTime = Date.now();
while (Date.now() - startTime < timeout) { const status = await this.getVideoStatus(videoId);
if (status.status === 'completed') { return status.download_url; } else if (status.status === 'failed') { throw new Error('Video generation failed'); }
// Wait 10 seconds await new Promise(resolve => setTimeout(resolve, 10000)); }
throw new Error('Video generation timed out'); }}
// Example usage(async () => { const api = new NoLangAPI(process.env.NOLANG_API_KEY);
try { // Generate a video from text const result = await api.generateVideoFromText( '123e4567-e89b-12d3-a456-426614174000', "Explain asynchronous processing in JavaScript" );
console.log(`Video ID: ${result.video_id}`);
// Wait for completion const downloadUrl = await api.waitForCompletion(result.video_id); console.log(`Download URL: ${downloadUrl}`);
// Convert the generated video to English + vertical (9:16) const options = await api.getConvertOptions(result.video_id); if (options.is_convertible && options.available_languages.includes('en')) { const converted = await api.convertVideo(result.video_id, { language: 'en', aspectRatio: '9:16' }); const convertedUrl = await api.waitForCompletion(converted.video_id); console.log(`Converted URL: ${convertedUrl}`); }
} catch (error) { console.error('Error:', error.message); }})();Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| 401 Unauthorized | Invalid API key | Check the API key, or regenerate it |
| 429 Too Many Requests | Rate limit exceeded | Wait until the rate limit resets, then retry |
| Video generation is slow | Peak load period | Run it during off-peak hours |
| File upload error | File size exceeded | Reduce the file size |
| 403 error on video conversion | The video conversion API is not available on the Free plan | Upgrade to the Standard / Premium plan |
| LANGUAGE_NOT_SUPPORTED_BY_VOICES error | A speaker in the source video does not support the specified language | Choose from available_languages in GET /videos/{video_id}/conversions/ |
| CONVERT_NO_CHANGE error | The same language and aspect ratio as the source video are specified | Specify a value different from the source video |