Convert document
curl --request POST \
--url https://api.example.com/api/v1/convertimport requests
url = "https://api.example.com/api/v1/convert"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.example.com/api/v1/convert', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/convert",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/convert"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/convert")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/convert")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyAPI reference
Convert document
Convert a document to any supported quiz or form format
POST
/
api
/
v1
/
convert
Convert document
curl --request POST \
--url https://api.example.com/api/v1/convertimport requests
url = "https://api.example.com/api/v1/convert"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.example.com/api/v1/convert', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/convert",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/convert"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/convert")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/convert")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyConvert a Google Drive file into a quiz or form on any of the 25 supported platforms.
For each type,
Then poll
The REST API accepts files stored in Google Drive — Google Docs, Sheets, Drive-hosted PDFs, Word documents, images, and Slides presentations. Pick the right
documentType for your file (see below). To convert files uploaded directly from your computer, use the Formswrite web app.Request
Headers
| Header | Value | Required |
|---|---|---|
Authorization | Bearer YOUR_API_TOKEN | Yes |
Content-Type | application/json | Yes |
Body parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
documentId | string | Yes | Google Doc ID or full Google Docs URL |
format | string | Yes | Target format (see supported formats) |
documentName | string | No | Name for the output file (defaults to "Untitled Document") |
documentType | string | No | Source file type. Defaults to "google_doc". See supported document types. |
async | boolean | No | Set to true for async processing (returns immediately with a job ID) |
Document ID
You can pass either a raw Google Drive file ID or a full URL. The accepted URL shapes includedocs.google.com/document/d/..., docs.google.com/spreadsheets/d/..., docs.google.com/presentation/d/..., and drive.google.com/file/d/...:
// Raw ID (works for any Google Drive file)
{ "documentId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms" }
// Full Google Docs URL
{ "documentId": "https://docs.google.com/document/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms/edit" }
// Full Google Drive PDF URL (pair with documentType: "google_drive_pdf")
{ "documentId": "https://drive.google.com/file/d/1AbCdEfGhIjKlMnOpQrStUvWxYz/view" }
The document must be shared with Formswrite (or set to “Anyone with the link can view”) for the conversion to work.
Supported document types
SetdocumentType to match the file in Google Drive you’re pointing at:
documentType value | Source file in Google Drive |
|---|---|
google_doc (default) | Google Docs document |
google_sheet | Google Sheets spreadsheet |
google_drive_pdf | PDF file in Google Drive |
google_drive_word | Microsoft Word document in Google Drive |
google_drive_picture | Image in Google Drive (PNG, JPG, etc.) |
google_drive_presentation | Google Slides presentation |
documentId is the Google Drive file ID (the part after /d/ in the file’s share URL).
The REST API only reads from Google Drive.
documentType values like uploaded_pdf, uploaded_word, etc. that appear elsewhere in the Formswrite system are not accepted here — they belong to the web-app upload flow.Supported formats
Live forms
| Format value | Platform | Description |
|---|---|---|
google_form | Google Forms | Creates a Google Form in your Google account |
formswrite_form | Formswrite Forms | Creates a hosted form on Formswrite |
google_form requires that you have previously connected your Google account via the Formswrite web app. The form will be created in your Google Drive.Learning Management Systems (LMS)
| Format value | Platform | File type |
|---|---|---|
canvas | Canvas LMS | .zip (QTI package) |
moodle | Moodle | .xml (Moodle XML) |
blackboard | Blackboard | .txt |
brightspace | Brightspace (D2L) | .zip |
schoology | Schoology | .zip (QTI package) |
sakai | Sakai | .zip (QTI 2.1 package) |
Quiz and game platforms
| Format value | Platform | File type |
|---|---|---|
kahoot | Kahoot! | .csv |
quizizz | Quizizz | .csv |
blooket | Blooket | .csv |
gimkit | Gimkit | .csv |
socrative | Socrative | .xlsx |
wooclap | Wooclap | .csv |
quizalize | Quizalize | .csv |
classmarker | ClassMarker | .csv |
pear_assessment | Pear Assessment (formerly Pear Deck) | .csv |
Standard formats
| Format value | Description | File type |
|---|---|---|
qti_21 | QTI 2.1 (IMS standard) | .zip |
qti_22 | QTI 2.2 (IMS standard) | .zip |
gift | GIFT format (Moodle-compatible) | .txt |
aiken | Aiken format (simple text) | .txt |
cloze | Cloze / Embedded Answers format | .txt |
word | Microsoft Word | .docx |
Other platforms
| Format value | Platform | File type |
|---|---|---|
learndash | LearnDash (WordPress) | .txt (GIFT format) |
h5p | H5P | .h5p (zip archive) |
Synchronous mode (default)
By default, the API waits for the document to be analyzed and converted before returning the result. This can take up to 5 minutes depending on document size.Request
curl -X POST https://api.formswrite.com/api/v1/convert \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"documentId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms",
"format": "moodle",
"documentName": "Chemistry Quiz"
}'
Success response (file formats)
For all LMS, quiz/game, standard, and other file formats, the response is the same shape:{
"success": true,
"format": "moodle",
"exportId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"downloadUrl": "https://api.formswrite.com/api/forms/exports/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"fileName": "Chemistry Quiz-moodle.xml",
"expiresAt": "2026-06-13T08:40:14.020Z"
}
downloadUrl is publicly accessible — no auth header is required to download the file. The URL stops working after expiresAt (30 days from creation). Re-run convert if you need a fresh link.Success response (Google Forms)
google_form returns two URLs. directFormUrl is the Google-hosted form your recipients fill in. formUrl is the Formswrite dashboard view of the same form (for editing inside Formswrite).
{
"success": true,
"format": "google_form",
"formId": "1AbCdEf2GhIjKlMnOpQrStUvWxYz",
"directFormUrl": "https://docs.google.com/forms/d/e/1FAIpQLSe.../viewform",
"formUrl": "https://formswrite.com/dashboard/forms/abc123",
"timedExam": null
}
Success response (Formswrite Forms)
formswrite_form creates a hosted form on Formswrite. It is created as a draft — visitors can’t submit until you publish it from the dashboard or via the MCP server.
{
"success": true,
"format": "formswrite_form",
"formId": 9814,
"formPublicId": "n8aikW7h8i4Q",
"publicId": "n8aikW7h8i4Q",
"formUrl": "https://formswrite.com/forms/n8aikW7h8i4Q",
"questionCount": 3,
"encrypted": false,
"timedExam": null
}
formId is an integer (Formswrite database primary key); formPublicId and publicId are the same string and are what appears in the public-facing URL.Timeout response (408)
If the analysis takes longer than 5 minutes, you will receive a408 response with a job ID you can use to poll for status:
{
"success": false,
"status": "processing",
"jobId": "123",
"message": "Analysis still in progress. Poll for status.",
"pollUrl": "/api/v1/convert/status/123"
}
Asynchronous mode
Set"async": true to return immediately with a job ID. Use the poll status endpoint to check when the conversion is complete.
Request
curl -X POST https://api.formswrite.com/api/v1/convert \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"documentId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms",
"format": "canvas",
"documentName": "Biology Exam",
"async": true
}'
Response (202 Accepted)
{
"success": true,
"status": "processing",
"jobId": "456",
"message": "Document analysis queued. Poll for status.",
"pollUrl": "/api/v1/convert/status/456"
}
GET /api/v1/convert/status/456 until the job is complete. See Poll status for details.
Error responses
| Status | Description |
|---|---|
400 | Missing or invalid documentId or format |
401 | Invalid or missing API token |
402 | Subscription expired or credit limit reached |
408 | Analysis timed out (sync mode only — use the returned pollUrl) |
500 | Internal server error |
Example: invalid format
{
"success": false,
"message": "Invalid format. Supported formats: google_form, formswrite_form, canvas, moodle, blackboard, brightspace, schoology, sakai, kahoot, quizizz, blooket, gimkit, socrative, wooclap, quizalize, classmarker, pear_assessment, qti_21, qti_22, gift, aiken, cloze, word, learndash, h5p"
}
Example: subscription required
{
"success": false,
"message": "Your subscription has expired. Please upgrade to continue using the API."
}