Upload a contract PDF to a project. The file is stored and queued for processing. You can optionally request specific extractions to run automatically after upload.
Only PDF files are supported. Maximum file size is 50 MB.
Upload Contract
Creates a new contract record and uploads the file. Supports two content types: multipart/form-data for direct file upload, and application/json for base64-encoded files.
Request
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|
projectId | UUID | Yes | — | The project to upload the contract to |
| Header | Required | Description |
|---|
Authorization | Yes | Bearer <token> — must be scoped to the requested project |
Content-Type | Yes | multipart/form-data or application/json |
Accept | No | Set to text/event-stream for real-time upload progress via SSE |
Upload a file directly using multipart/form-data.
| Field | Type | Required | Description |
|---|
file | File | Yes | The PDF file to upload |
extractions | string | No | JSON array of extraction types to run |
Example
curl -X POST "https://api.royaltyport.com/v1/contracts?projectId=a1b2c3d4-..." \
-H "Authorization: Bearer rp_your_token_here" \
-F "file=@contract.pdf" \
-F 'extractions=["extract-royalties","extract-dates"]'
Option B: JSON Body
Upload a base64-encoded file using application/json.
| Field | Type | Required | Default | Description |
|---|
file | string | Yes | — | Base64-encoded file content |
fileName | string | Yes | — | The file name (e.g. contract.pdf) |
fileType | string | No | application/pdf | MIME type of the file |
extractions | array | No | — | Array of extraction types to run |
Example
curl -X POST "https://api.royaltyport.com/v1/contracts?projectId=a1b2c3d4-..." \
-H "Authorization: Bearer rp_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"file": "JVBERi0xLjQK...",
"fileName": "contract.pdf",
"extractions": ["extract-royalties", "extract-dates"]
}'
Pass any combination of the following extraction types to automatically process the contract after upload:
| Extraction | Description |
|---|
extract-accounting-period | Accounting period definitions |
extract-assets | Asset references |
extract-commitments | Commitment clauses |
extract-compensations | Compensation terms |
extract-control-areas | Control area definitions |
extract-costs | Cost provisions |
extract-creative-approvals | Creative approval clauses |
extract-dates | Key dates (effective, termination, etc.) |
extract-royalties | Royalty terms |
extract-signatures | Signature information |
extract-splits | Revenue split information |
extract-targets | Target and threshold clauses |
extract-balances | Balance provisions and terms |
Response
| Field | Type | Description |
|---|
staging_id | integer | Unique identifier for tracking processing progress |
staging_stage | string | Current processing stage (queued, processing, completed, failed) |
staging_done | boolean | Whether staging (pre-processing) has completed |
extractions_done | boolean | Whether all extractions have completed |
created_at | string | Upload timestamp (ISO 8601) |
{
"data": {
"staging_id": 456,
"staging_stage": "queued",
"staging_done": false,
"extractions_done": false,
"created_at": "2025-03-01T12:00:00Z"
}
}
SSE Response
If the Accept header includes text/event-stream, the response is a server-sent event stream with upload progress:
event: progress
data: {"bytesUploaded":3145728,"bytesTotal":10485760,"percent":30}
event: progress
data: {"bytesUploaded":10485760,"bytesTotal":10485760,"percent":100}
event: complete
data: {"data":{"staging_id":456,"staging_stage":"queued","staging_done":false,"extractions_done":false,"created_at":"2025-03-01T12:00:00Z"}}
Errors
| Status | Description |
|---|
400 | Missing file, invalid extractions, unsupported file type, or file exceeds 50 MB |
403 | Token is not scoped to the requested project |
429 | Rate limit exceeded |
500 | File upload or database error |