Intake API
The Intake API handles the full dissertation submission flow: generating an upload URL, receiving the intake form, and returning submission status with analysis and quote.
POST /intake/presigned-url
Generates a presigned S3 URL that the browser uses to upload the dissertation document directly to S3.
Request
{
"fileName": "my-dissertation.docx"
}
| Field |
Type |
Required |
Description |
fileName |
string |
Yes |
Original filename of the document. Must end in .docx. |
Response (200)
{
"uploadUrl": "https://dissertation-editor-uploads-dev.s3.amazonaws.com/uploads/abc123/my-dissertation.docx?X-Amz-Algorithm=...",
"s3Key": "uploads/abc123/my-dissertation.docx",
"submissionId": "abc123"
}
| Field |
Type |
Description |
uploadUrl |
string |
Presigned S3 PUT URL. Valid for 5 minutes. |
s3Key |
string |
The S3 object key where the file will be stored. Pass this to the submit endpoint. |
submissionId |
string |
Unique identifier for this submission. Used in all subsequent API calls. |
Upload the File
After receiving the presigned URL, upload the file directly from the browser:
await fetch(uploadUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
},
});
The presigned URL expires after 5 minutes. If the upload is not completed in time, request a new URL.
Errors
| Status |
Cause |
400 |
Missing fileName or file is not .docx |
500 |
S3 error generating presigned URL |
POST /intake/submit
Submits the intake form data after the document has been uploaded to S3. This triggers async processing (document analysis, quote calculation, Pipedrive deal creation).
Request
{
"submissionId": "abc123",
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "555-123-4567",
"serviceType": "editing",
"s3Key": "uploads/abc123/my-dissertation.docx",
"notes": "Formatting per university guidelines"
}
| Field |
Type |
Required |
Description |
submissionId |
string |
Yes |
The ID returned from the presigned URL endpoint. |
name |
string |
Yes |
Full name of the submitter. |
email |
string |
Yes |
Contact email address. |
phone |
string |
No |
Contact phone number. |
serviceType |
string |
Yes |
Type of editing service requested (e.g., editing, formatting, editing_and_formatting). |
s3Key |
string |
Yes |
The S3 key returned from the presigned URL endpoint. |
notes |
string |
No |
Additional instructions or notes from the client. |
Response (200)
{
"submissionId": "abc123",
"status": "processing"
}
| Field |
Type |
Description |
submissionId |
string |
Confirms the submission ID. |
status |
string |
Always "processing" on success. The frontend should begin polling. |
Errors
| Status |
Cause |
400 |
Missing required fields or invalid serviceType |
500 |
DynamoDB write failure or Lambda invoke error |
GET /intake/submission/{submissionId}
Retrieves the current state of a submission. The frontend polls this endpoint until status is "completed" or "error".
Path Parameters
| Parameter |
Type |
Description |
submissionId |
string |
The submission ID to look up. |
Response (200) -- Processing
{
"submissionId": "abc123",
"status": "processing",
"name": "Jane Doe",
"email": "jane@example.com",
"serviceType": "editing",
"createdAt": "2026-03-09T14:30:00.000Z"
}
Response (200) -- Completed
{
"submissionId": "abc123",
"status": "completed",
"name": "Jane Doe",
"email": "jane@example.com",
"serviceType": "editing",
"createdAt": "2026-03-09T14:30:00.000Z",
"analysis": {
"textWordCount": 45230,
"refsWordCount": 3210,
"tables": 12,
"figures": 8,
"frontMatter": 15
},
"quote": {
"lineItems": [
{ "description": "Text editing (45,230 words)", "amount": 2261.50 },
{ "description": "References (3,210 words)", "amount": 96.30 },
{ "description": "Tables (12)", "amount": 60.00 },
{ "description": "Figures (8)", "amount": 40.00 },
{ "description": "Front matter (15 pages)", "amount": 75.00 }
],
"subtotal": 2532.80,
"adminFee": 253.28,
"total": 2786.08
},
"pipedriveUrl": "https://phd-advantage.pipedrive.com/deal/123"
}
Response Fields (Completed)
| Field |
Type |
Description |
analysis.textWordCount |
number |
Word count of the main body text |
analysis.refsWordCount |
number |
Word count of the references/bibliography section |
analysis.tables |
number |
Number of tables detected |
analysis.figures |
number |
Number of figures detected |
analysis.frontMatter |
number |
Number of front matter pages |
quote.lineItems |
array |
Itemized breakdown of the quote |
quote.subtotal |
number |
Sum of all line items |
quote.adminFee |
number |
Administrative fee (percentage of subtotal) |
quote.total |
number |
Final total (subtotal + admin fee) |
Errors
| Status |
Cause |
404 |
No submission found with the given ID |
500 |
DynamoDB read failure |