Reuse documents and post attachments

Reuse an existing file by passing its source document ID. No download or re-upload is needed. The source must belong to the same company and be accessible to the current user.

These examples use an authenticated sdk from Getting started and IDs selected by your app. Kotlin calls run in a coroutine; React hooks run inside the configured providers.

1. Find a document in Solibo Home

Search the company library and let the user select a file:

val page = sdk.api.documents.listDocument(
    companyId = companyId,
    search = "House rules",
    count = 20,
).body()
val files = page.items.filter { it.isDirectory != true }
files.forEach { println("${it.id}: ${it.fileName}") }
const page = await sdk.api.documents.listDocument({
  companyId,
  search: 'House rules',
  count: 20,
})
const files = (page.items ?? []).filter(file => !file.isDirectory)
files.forEach(file => console.log(file.id, file.fileName))

Use the selected file’s id as sourceDocumentId. If it is already a reference, use sourceDocumentId from its metadata instead.

2. Or select an attachment from a post

Read the post’s documents collection. Its cover image is separate (pictureDocument / pictureDocumentId). Here attachmentId is the attachment selected by the user.

val post = sdk.api.homepage.getHomepageFeedPost(
    companyId = companyId,
    postId = sourcePostId,
).body()
val attachment = post.documents.orEmpty().firstOrNull { it.id == attachmentId }
    ?: error("Selected attachment is not available")
val sourceDocumentId = attachment.sourceDocumentId ?: attachment.id
const post = await sdk.api.homepage.getHomepageFeedPost({
  companyId,
  postId: sourcePostId,
})
const attachment = (post.documents ?? []).find(file => file.id === attachmentId)
if (!attachment) throw new Error('Selected attachment is not available')
const sourceDocumentId = attachment.sourceDocumentId ?? attachment.id

Use attachment.id to manage this attachment and sourceDocumentId to reuse the file elsewhere.

3. Attach it to an existing post

Create a reference with type = POST and the destination post ID as belongsToId:

import no.solibo.oss.sdk.api.gen.models.CreateDocumentReferenceCommand
import no.solibo.oss.sdk.api.gen.models.DocumentType

val reference = sdk.api.documents.createDocumentReference(
    companyId = companyId,
    documentId = sourceDocumentId,
    createDocumentReferenceCommand = CreateDocumentReferenceCommand(
        type = DocumentType.POST,
        belongsToId = targetPostId,
    ),
).body()
println("New attachment: ${reference.id}")
const reference = await sdk.api.documents.createDocumentReference({
  companyId,
  documentId: sourceDocumentId,
  input: { type: 'POST', belongsToId: targetPostId },
})
console.log('New attachment:', reference.id)

In React, use useCreateDocumentReference() and refresh any additional destination views you cache. Direct SDK calls do not refresh query caches.

For a conversation, set visibility: 'INTERNAL' to keep the attachment in the internal (board-only) thread. Uploads to a conversation take the same option.

4. Create a post with an attachment and an inline link

Create the post and its document references together. The rules slot connects the inline link to inlineDocuments.rules; attachments adds the file to the attachment list.

import no.solibo.oss.sdk.api.DocumentInput
import no.solibo.oss.sdk.api.inlineDocumentLinkSlot
import no.solibo.oss.sdk.api.gen.models.CreatePostCommand

val result = sdk.api.integratedDocuments.createHomepagePost(
    companyId = companyId,
    command = CreatePostCommand(
        title = "House rules",
        content = "<p>Please read " + inlineDocumentLinkSlot("rules", "the house rules") + "</p>",
    ),
    attachments = listOf(DocumentInput.Existing(sourceDocumentId)),
    inlineDocuments = mapOf("rules" to DocumentInput.Existing(sourceDocumentId)),
)
println("Created post ${result.resource.id}")
import { inlineDocumentLinkSlot, type Id } from '@solibo/solibo-sdk'
import { useCreateHomepagePostWithDocuments } from '@solibo/solibo-react'

// Call this hook from a React component, then call publish() from its submit handler.
function usePublishHouseRules(companyId: Id, sourceDocumentId: Id) {
  const createPost = useCreateHomepagePostWithDocuments()
  return () => createPost.mutateAsync({
    companyId,
    command: {
      title: 'House rules',
      content: '<p>Please read ' + inlineDocumentLinkSlot('rules', 'the house rules') + '</p>',
    },
    attachments: [{ sourceDocumentId }],
    inlineDocuments: { rules: { sourceDocumentId } },
  })
}

For an inline image, use inlineDocumentImageSlot("entrance", "Building entrance") and supply an image under the same entrance key. For a cover image, pass image separately. Mix reused files with new uploads using DocumentInput.Upload("minutes.pdf", bytes, "application/pdf") in Kotlin, or { file } / { fileName: "minutes.pdf", bytes, contentType: "application/pdf" } in TypeScript.

Outside React, use createHomepagePostWithDocumentsMutationOptions(sdk, queryClient) from @solibo/solibo-query. See Usage examples for standalone uploads.

5. Download an image at the size you need

Request transformations when resolving the signed URL. This example preserves the full image at a maximum width of 1002 pixels and requests WebP output.

val imageUrl = sdk.api.documents.showDocument(
    companyId = companyId,
    documentId = sourceDocumentId,
    redirect = false,
    size = "1002xauto",
    format = "webp",
    quality = "85",
).body().url
const { url: imageUrl } = await sdk.api.documents.showDocument({
  companyId,
  documentId: sourceDocumentId,
  redirect: false,
  size: '1002xauto',
  format: 'webp',
  quality: '85',
})

For a cached URL, pass the same options to useGetDocumentURL(params) or getDocumentURLQueryOptions(sdk, params). Public pages use usePublicDocumentURL(params) or publicGetDocumentURLQueryOptions(sdk, params). Public conversations use usePublicConversationDocumentURL(params) or publicConversationDocumentURLQueryOptions(sdk, params) with companySlug, conversationId, and documentId. Signed URLs currently expire after an hour, so keep the query’s staleTime well below that.

The private and public URL hooks send the lookups a screen makes together as one request per company and rendition, so render one hook per picture. To sign a list you already hold, use useDocumentURLs(params) or usePublicDocumentURLs(params) (documentURLsQueryOptions and publicDocumentURLsQueryOptions) with up to 100 documentIds and autoPaginate: true.

Omit transformation options to get the original file. All option values are strings.

Image options
Option Use
size 1002x488, 1002xauto, or autox488. Dimensions: 1–8192; at most 32 million pixels. auto requires fit: 'inside'.
fit inside (default), cover (crop), contain (pad), fill (stretch), or outside. All except inside require two numeric dimensions.
position center (default), an edge such as top, or a corner such as top-left. Non-center positions require cover or contain.
format auto (default), jpeg, png, webp, or avif.
quality '1'–'100', default '82'; applies to JPEG, WebP, and AVIF.
upscale 'false' (default) or 'true'. Some fits fail if enlargement is required and disabled.
background Six or eight hex digits; default 'ffffff'. Use '00000000' for transparent padding.

For a crop, use size: '1002x488', fit: 'cover'. For a transparent square, use size: '640x640', fit: 'contain', background: '00000000', format: 'png'.

Request a new signed URL when changing options. Invalid options return HTTP 400; image-dependent failures can return HTTP 422 at download time, even if resolving the URL succeeded. For non-images, size alone is ignored; other image options are rejected.

Store document IDs, display resolved URLs

Save and edit content, which keeps document markers. Display renderedContent, which resolves those markers into URLs. Do not save signed URLs as document references or replace editable content with rendered HTML.

For upload failures and safe retries, see integrated resource mutations.


Solibo AS