GuidesUpload a file

Upload a file

Uploading is three calls: ask for a signed upload, send the bytes to storage, then add the file to the library. The file becomes an image, video or audio asset in the workspace, ready to place on a board or use as a reference.

1. Get a signed upload

Call createSignedUploadUrl with the file's category, filename and contentType, and your workspaceId. Select uploadForm to get a signed form.

curl https://api.plentylabs.com/graphql \
  -H "Authorization: Bearer $PLENTY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation CreateSignedUpload($workspaceId: ID!) { createSignedUploadUrl(workspaceId: $workspaceId, category: UGC_IMAGE, filename: \"photo.png\", contentType: \"image/png\") { fileId uploadForm { url fields } } }",
    "variables": { "workspaceId": "YOUR_WORKSPACE_ID" }
  }' > response.json
CategoryContent types
UGC_IMAGEimage/jpeg, image/jpg, image/png, image/webp, image/avif, image/svg+xml
AI_IMAGE_REFERENCEimage/jpeg, image/jpg, image/png, image/webp, image/avif
VIDEOvideo/mp4, video/webm, video/quicktime, video/x-msvideo
AUDIOaudio/mpeg, audio/mp3, audio/wav, audio/x-wav, audio/wave, audio/ogg, audio/aac, audio/webm, audio/mp4, audio/x-m4a, audio/m4a, audio/flac, audio/x-flac

Any other content type returns BAD_USER_INPUT with the allowed list. UploadCategory in the schema lists every category.

The signed form and URL expire after 15 minutes.

2. Upload the file

POST a multipart form to uploadForm.url. Send every field in uploadForm.fields, then the file last, named file.

UPLOAD_URL=$(jq -r '.data.createSignedUploadUrl.uploadForm.url' response.json)
UPLOAD_FIELDS=$(jq -c '.data.createSignedUploadUrl.uploadForm.fields' response.json)

form=()
while IFS= read -r field; do form+=(-F "$field"); done < <(jq -r 'to_entries[] | "\(.key)=\(.value)"' <<< "$UPLOAD_FIELDS")

curl -f "$UPLOAD_URL" "${form[@]}" -F "file=@photo.png"

The form accepts a file from 1 byte to 256 MiB. Any 2xx status means the file is stored.

You can PUT the bytes to signedUrl instead. Send every header in requiredHeaders, exactly as given.

curl -f -X PUT "$SIGNED_URL" \
  -H "content-type: image/png" \
  -H "x-goog-if-generation-match: 0" \
  --data-binary @photo.png

3. Add it to the library

Pass the fileId to the mutation for its category. The file becomes an asset in the workspace library.

CategoryMutationReturns
UGC_IMAGE, AI_IMAGE_REFERENCEuploadImageImage
VIDEOuploadVideoVideo
AUDIOuploadAudioAudio
curl https://api.plentylabs.com/graphql \
  -H "Authorization: Bearer $PLENTY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation UploadImage($workspaceId: ID!, $fileId: ID!) { uploadImage(workspaceId: $workspaceId, input: { fileId: $fileId, displayName: \"Product photo\" }) { image { id status } } }",
    "variables": { "workspaceId": "YOUR_WORKSPACE_ID", "fileId": "FILE_ID" }
  }'

If the bytes did not arrive, the mutation is refused. Upload again, then retry with the same fileId.

For images and videos, width and height are measured from the file shortly after, when you omit them. Place the asset with PlaceCards.

Files outside the library

For any other category, call confirmFileUpload instead. It keeps the file without adding it to the library. Do not call it for a file you add with a step 3 mutation.

curl https://api.plentylabs.com/graphql \
  -H "Authorization: Bearer $PLENTY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation ConfirmFileUpload($fileId: ID!) { confirmFileUpload(fileId: $fileId) }",
    "variables": { "fileId": "FILE_ID" }
  }'

An upload that is neither added nor confirmed is deleted one to two hours after it was requested.

Limits

  • A key cannot import a file from a link. Upload the bytes.