Skip to main content
cURL
Uploads a file as AI source content for the specified proposal. The request body must be multipart/form-data and must include at least one file part. Accepted and Completed proposals cannot accept new content; templates can be edited only by their template owner. Each uploaded file part is limited by the server’s configurable MaxProposalAttachmentSizeInMB setting (20 MB in the repository defaults). Multi-chunk mode does not bypass this per-part limit; the implementation does not enforce a separate 1 GB total-size limit. For multi-chunk uploads, set ?isMultiChunkUpload=true and send each chunk as its own multipart file part — see Multi-chunk upload below.
This endpoint requires multipart/form-data, not application/x-www-form-urlencoded. Sending a URL-encoded body returns No file was provided in the request.

Request

POST /public/proposals/{ProposalId}/ai/content

Headers

string
required
Must be application/json.
string
required
Must be multipart/form-data; boundary=<generated-boundary>. The full value, including the boundary parameter, must also be used in the HMAC canonical message. See Sign multipart requests.
string
required
Your API Application Key.
string
required
Your User API Key.
string
required
Current UTC timestamp in RFC 7231 format.
string
required
HMAC-SHA256 signature, Base64-encoded.

Path parameters

integer
required
Positive numeric identifier of the proposal to which the AI content will be attached. Accepted and Completed proposals cannot accept new content.

Form fields

The body is a multipart/form-data payload containing the following parts.
string
required
Human-readable name or title for the content being uploaded. Used for display and search. Provide a concise, descriptive name.
boolean
Send false (or omit) for a normal single-file upload. Send true only when also using ?isMultiChunkUpload=true on the URL — see Multi-chunk upload.
file
required
The actual file to upload, sent as a multipart file part. See the file part naming rule below — use the same filename, including its extension, for the field name and the filename= value.

File part naming (important)

The multipart field name must include the file extension. Validation checks that field name, while the upload logic derives the stored source-file type from the filename= value. Use the same filename and extension in both places; the part’s Content-Type is not used for extension validation. Set the field name equal to the filename:
Common defaults like name="file" will fail with:
The field name has no extension, so the server sees an empty file type. Supported file extensions: .txt, .pdf, .mp3, .wav, .aac, .flac, .ogg, .wma, .aiff, .alac, .midi, .mp4, .avi, .mkv, .mov, .wmv, .flv, .webm, .mpeg, .3gp, .m4v, .ogv.

Response

Success

A 200 response returns the created content item.
integer
required
Unique identifier assigned to the new content item. Use this ID for subsequent operations such as deleting the item.
string
required
Display name for the content item, as provided in the request.
string
AI-generated summary of the content. It is initially null and may remain null until processing completes or if transcription fails.
string
required
Initial processing status. The upload response is created with Uploaded; background processing may later change it to Processing, Transcribed, or Invalid.
string
required
Source type derived from the uploaded filename extension: Text, Audio, or Video.
string
required
ISO 8601 timestamp of when the content item was created.
object
required
The user who performed the upload. The endpoint populates the user ID, first name, and last name.

Error codes

Example

Each example uploads a single text file named spec-bom.txt. Substitute the credentials, the proposal ID, and the file path as appropriate.
Response

Multi-chunk upload

For a file that exceeds the configured per-part limit, switch to multi-chunk mode. The same per-part limit applies to every chunk. There is no separate initiate or complete call — every chunk is sent as a multipart file part in a single request.

URL

As with all Portal.io endpoints, the HMAC canonical message uses the base URL without the query string. The ?isMultiChunkUpload=true is sent on the wire but not included in the signing input. See Sign Portal.io API requests for the canonical rules.

Required form fields

ProposalId remains a path parameter. The service does not require a duplicate proposalId form field or a totalChunks field.

Chunk file parts

Include each chunk as a separate multipart file part. Use the original filename plus a .partN suffix for both the field name and the filename= value. The service removes the suffix when determining the original source extension:

Chunk sizes

Choose a chunk size that stays below the server’s configured per-part limit. The same limit applies to every chunk. The implementation does not define a separate total upload-size limit.
Non-final chunks must be at least 5 MB. This is an S3 multipart upload constraint — chunks smaller than 5 MB (other than the last one) will be rejected.

Authorizations

X-MSS-API-APPID
string
header
required

Portal application identifier used as part of HMAC-authenticated API requests.

X-MSS-API-USERKEY
string
header
required

Portal user API key used together with the HMAC signature headers.

X-MSS-CUSTOM-DATE
string
header
required

Timestamp header included in the signed request to prevent replay attacks.

X-MSS-SIGNATURE
string
header
required

HMAC-SHA256 signature for the request, calculated over the canonical string defined in the authentication docs.

Headers

Accept
string
required

Accept Header

Path Parameters

ProposalId
integer<int32>
required

Numeric identifier of the proposal to which the AI-generated content will be attached. Must be a positive integer. The proposal typically must be in Draft status to accept new content.

Body

multipart/form-data

Multipart form-data containing the content name, optional multi-chunk flag, and at least one file part.

Multipart form fields. The file part property name must equal the filename, including its extension.

name
string
required

Human-readable name or title for the content being uploaded.

Example:

"site-survey.pdf"

isMultiChunkUpload
boolean

Set true when the request contains multiple parts of one file; otherwise omit or set false.

Example:

false

{key}
file

A required file part. Its property name must equal the filename, including its extension; add .partN to each multi-chunk part.

Response

Success

PublicAiProposalContentPostResponse

id
integer<int32>
required

Unique identifier assigned to the created AI content item. Use this id for subsequent operations (update, delete, fetch).

name
string
required

Human-readable name/title of the created content item. Matches the 'Name' value provided in the request.

createdDate
string<date-time>
required

Timestamp (UTC) when the content item was created. ISO 8601 format.

summary
string

Optional short summary or snippet of the content generated by the AI. Useful for preview and search.

status
enum<string>
Available options:
Uploaded,
Processing,
Transcribed,
Invalid
sourceType
enum<string>
Available options:
Text,
Audio,
Video
userCreated
SimpleUserModel · object

SimpleUserModel