Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions content/concepts/files/_meta.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default {
'files-in-sharetribe': {},
'file-lifecycle': {}
};
208 changes: 208 additions & 0 deletions content/concepts/files/file-lifecycle/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
---
title: File lifecycle in Sharetribe
sidebarTitle: File lifecycle
description:
This article describes the lifecycle of files on a Sharetribe
marketplace
---

import { Callout, Steps } from 'nextra/components';

# File lifecycle in Sharetribe

Sharetribe has endpoints and mechanisms for uploading and downloading
digital files. Uploading and downloading files are both multi-step
operations, and there are a number of different entities and states
involved.

## Uploading a file

<Callout>

Files can be uploaded in two sequences. The sequence described here is
to first create the **ownFile** resource, and then create the
**fileUpload** resource and upload details with the file id of the
**ownFile**.

It is also possible to first create the **fileUpload** resource and
upload the file, and then create the **ownFile** resource with the id of
the **fileUpload** resource.

</Callout>

<Steps>

### Read file metadata

Before we make any API calls, we need to get the metadata of the file in
the local file system.

The SDK has a helper function for parsing the attributes of the file
metadata that are needed for uploading the file.

```js
import * as sharetribeSdk from 'sharetribe-flex-sdk';

const { file: sdkFile } = sharetribeSdk;

const metadata = sdkFile.metadata(file);
```

If you are using the APIs directly, you'll need to parse the necessary
metadata information from the File object:

```js
const metadata = {
name: 'File to be uploaded.pdf',
mimeType: 'application/pdf',
size: 10697,
};
```

### Create an ownFile resource

With the metadata information, you can create an `ownFile` resource in
the Sharetribe backend with `ownFiles.create`.

```js
const ownFileResource = await sdk.ownFiles.create({ ...metadata }).data;
```

This step also validates that the file mime type is supported.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What mime types are supported?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe pinging @lyyder and @walterrw on this – how closely do we want to document supported/blocked mime types? I did find the categorization in src/sharetribe/util/file_security.clj. I don't know what the security balance is in terms of documenting the categories externally, so any advice is welcome!


### Create a file upload URL

The id of the `ownFile` resource is then used to create a signed file
upload URL.

```js
const fileId = ownFileResource.data.id;
const fileUploadDetails = await sdk.fileUploads.create({
Comment thread
SariSaar marked this conversation as resolved.
fileId,
});
```

```json
{
"fileUploadDetails": {
"status": 200,
"statusText": "",
"data": {
"data": {
"id": {
"uuid": "63abdec4-85e7-4157-8e99-2e2c7465d8be"
},
"type": "fileUpload",
"attributes": {
"fileId": {
"uuid": "69fd8859-8380-49c0-ab7e-0ee502e40811"
},
"url": "https://unique-signed-sharetribe-upload-url.com",
"headers": {
"Content-Type": "application/pdf"
},
"method": "PUT",
"expiresAt": "2026-05-08T08:16:30.988Z"
}
}
}
}
}
```

### Upload the file to storage with the file upload URL

The actual file is uploaded directly to storage with the URL and other
details from the response, and the upload does not use Sharetribe APIs.
The SDK has another helper function to upload the file.
Comment on lines +115 to +117
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds interesting! Could this flow be elaborated in the Files in Sharetribe article? That is, explaining the interaction between the client, our APIs, and the file storage. I feel like once I made it to this sentence, I started understanding how the architecture of file uploads work

Copy link
Copy Markdown
Contributor Author

@SariSaar SariSaar May 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good highlight! I added some more explanation as well as a visual for explaining this. Let me know if this still requires more elaboration!


When using the SDK, you can also pass in an upload progress tracking
callback to display the progress to the user.

```js
const {
method = 'PUT',
url,
headers = {},
} = fileUploadDetails?.data?.data?.attributes;

const onUploadProgress = (progressEvent) => {
const loaded = progressEvent?.loaded || 0;
const total = progressEvent?.total || file.size;
const progress = total
? Math.min(100, Math.round((loaded / total) * 100))
: null;
console.log(`progress ${progress} %`);
};

sdkFile.upload({
method,
url,
headers,
file,
onUploadProgress,
});
```

### Attach the file to a resource

The file id of the `ownFile` resource is then used to attach the file to
Comment thread
SariSaar marked this conversation as resolved.
another resource, e.g. to a message:

```js
sdk.messages.send({
transactionId: '6985dfd3-34bc-4bc8-806f-03a0f29e056d',
content: 'This is a message with a file',
publicFileAttachments: [fileId],
});
```

The file resource (`file` or `ownFile`) can be in one of several states:

- pendingUpload
- pendingVerification
- available
- verificationFailed

Depending on your use case, you may only want to attach files that are
available, or then allow attaching files that have completed upload.

</Steps>

After the file is attached to a resource, it is visible according to the
scope of the `fileAttachment`.

## Downloading a file

To download a file, the user makes a POST request for a short-lived
download URL for the file from Sharetribe API, and uses that generated
URL to fetch the file from storage.

Download links are only created for files in the `available` state.

There are two different download endpoints that use different ids:

- sdk.ownFileDownloads.create for ownFile resources, where the parameter
is the `file` id
- sdk.fileDownloads.create for file resources, where the parameter is
the `fileAttachment` id

```js
const downloadDetails = isOwnFile
? sdk.ownFileDownloads.create({ fileId }).data?.data
: sdk.fileDownloads.create({ fileAttachmentId }).data?.data;

const { url } = downloadDetails?.attributes;
```

## Deleting a file
Comment thread
SariSaar marked this conversation as resolved.

An operator can delete a file in Console. When attaching files to a
message, a single file is only attached to a single message at a time,
so when an operator deletes a file associated with a message, both the
`fileAttachment` and the `file` are deleted.

There is no file deletion endpoint in either Integration API or
Marketplace API. If you've uploaded a file but you have not yet attached
it to a message, leaving the file unattached will result in it being
eventually deleted.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading