SettleMint
Tokens

Token document uploads

Upload, confirm, list, download, and delete token or asset documents through the DALP API, SDK, and CLI.

The token document API manages files attached to an asset: a prospectus, term sheet, regulatory filing, compliance report, certificate, reserve audit, or other supporting file. The API uses the same two-step pattern as other upload flows:

  1. Request a presigned upload URL for a token document.
  2. Upload the file directly to storage using the returned method and headers.
  3. Confirm the upload so DALP records the file against the token.
  4. List, download, or delete the record later through the token document API.

This flow covers token or asset documents. Use the KYC document upload guide when the file belongs to a user's KYC profile instead of an asset.

Before you start

You need:

  • a DALP API key with access to the token document operations.
  • the token contract address for the asset that owns the document.
  • the asset profile, because DALP validates documentType against the profile.
  • the file name, MIME type, size in bytes, and visibility level before requesting an upload URL.

Flow at a glance

The upload URL and confirm calls are separate because the file bytes go directly to storage. DALP records the file only after you confirm the returned objectKey.

Rendering diagram...

If the direct storage upload fails, do not confirm. Request a fresh upload URL when the returned expiresAt time has passed or when storage rejects the returned headers.

Endpoints

The token document API exposes these operations:

  • GET /api/v2/tokens/{tokenAddress}/documents lists token documents with filtering and sorting (paginated).
  • POST /api/v2/tokens/{tokenAddress}/document-uploads returns a presigned upload URL.
  • POST /api/v2/tokens/{tokenAddress}/documents confirms an uploaded file and creates the document record.
  • POST /api/v2/tokens/{tokenAddress}/documents/{documentId}/downloads returns a secure download URL.
  • DELETE /api/v2/tokens/{tokenAddress}/documents/{documentId} deletes a token document.

Request an upload URL

Request an upload URL before sending the file bytes. The request describes the file and how it should be classified on the asset.

const upload = await client.token.documents.getUploadUrl({
  params: {
    tokenAddress: "0xTOKEN",
  },
  body: {
    documentType: "prospectus",
    fileName: "bond-prospectus.pdf",
    fileSize: 2_400_000,
    mimeType: "application/pdf",
    visibility: "public",
    title: "Bond prospectus",
    description: "Published prospectus for investor review",
  },
});

The upload URL request accepts these fields:

FieldRequiredDescription
documentTypeYesToken document type. Use a value allowed by the asset profile.
fileNameYesFile name, up to 255 characters.
fileSizeYesInteger size in bytes. The value must be positive and no larger than 50 MiB.
mimeTypeYesOne of the supported MIME types below.
visibilityYespublic, holders, or restricted.
titleNoDisplay title, up to 500 characters.
descriptionNoDescription, up to 2,000 characters.

Choose the document type for the asset profile

documentType is validated against the asset profile, not only against the shared document-type list. Use the value that matches the asset being filed. For reserve-backed assets, choose a type that describes the external file or attestation you are attaching to the token record. The asset profile also accepts common legal and regulatory types, including compliance filings. See the full table below.

Asset profileReserve or asset evidence document types
stablecoinreserve_audit, attestation_report, reserve_composition, certificate, or other.
precious-metalassay_certificate, storage_receipt, chain_of_custody, insurance_certificate, certificate, or other.

Use the stablecoin values for reserve audits, verifier attestations, or reserve-composition files. Use the precious-metal values for assay certificates, storage receipts, custody-chain files, or insurance certificates. For legal, regulatory, or compliance files, keep the more specific common type when the asset profile accepts it. Use other only when no accepted value fits, then set a clear title and description so reviewers can identify the file later.

The API and SDK accept these MIME types on an upload URL request:

  • application/pdf
  • image/jpeg
  • image/png
  • image/webp
  • application/vnd.openxmlformats-officedocument.wordprocessingml.document
  • application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
  • text/csv

The CLI documents get-upload-url and documents confirm-upload commands accept the same list except text/csv. To upload a CSV document, use the API or SDK.

The upload URL response includes:

FieldDescription
uploadUrlPresigned URL for the direct file upload.
objectKeyStorage object key to send in the confirm request.
expiresAtExpiry timestamp for the presigned URL.
methodHTTP method for the upload. Token documents use PUT.
headersHeaders that must be sent with the direct storage upload.

Upload the file bytes

Upload the file directly to the returned URL using the returned method and headers. Some storage backends add provider-specific headers to the URL response.

await fetch(upload.data.uploadUrl, {
  method: upload.data.method,
  headers: upload.data.headers,
  body: fileBytes,
});

Do not replace the returned headers with only Content-Type. Provider-specific headers are part of the upload contract.

Confirm the uploaded file

After the file upload succeeds, confirm it with the returned objectKey. DALP creates the token document record and returns the stored file metadata.

const document = await client.token.documents.confirmUpload({
  params: {
    tokenAddress: "0xTOKEN",
  },
  body: {
    objectKey: upload.data.objectKey,
    documentType: "prospectus",
    fileName: "bond-prospectus.pdf",
    fileSize: 2_400_000,
    mimeType: "application/pdf",
    visibility: "public",
    title: "Bond prospectus",
    description: "Published prospectus for investor review",
  },
});

The confirm request repeats the file metadata and adds objectKey. It also accepts replaceGroupId when the new file replaces an earlier document in the same version group.

The response includes the document id, groupId, versionNumber, isLatest, fileHash, uploadedAt, and uploader details.

DALP calculates fileHash from the uploaded bytes when you confirm. Store that value in downstream systems to verify the asset document still points to the expected file.

On-chain file hash claims

Upload records and asset-level claims serve different purposes:

  • The token document upload flow stores the file metadata, version group, and fileHash that belongs to the uploaded file.
  • An asset-level document-hash claim can record a SHA-256 hash, document type, and file name without placing the file contents on-chain.

Use the upload flow to manage access, download links, and versioning. Use an asset-level document-hash claim when an asset also needs an on-chain hash anchor for a specific file.

Choose document type and visibility

Choose the document type from the token's asset profile, not from the full token catalog. DALP uses the asset type to narrow the choices shown in the Console upload dialog: a stablecoin shows reserve options; a precious metal shows assay, storage, custody-chain, and insurance options.

Asset profileDocument type choices
Bondsprospectus, term_sheet, legal_opinion, regulatory_filing, compliance_report, annual_report, financial_statement, credit_rating, covenant_agreement, interest_schedule, certificate, other
Equityprospectus, term_sheet, legal_opinion, regulatory_filing, compliance_report, annual_report, financial_statement, shareholder_agreement, certificate, other
Fundsprospectus, term_sheet, legal_opinion, regulatory_filing, compliance_report, annual_report, financial_statement, fund_fact_sheet, subscription_agreement, nav_report, certificate, other
Stablecoinslegal_opinion, regulatory_filing, compliance_report, reserve_audit, attestation_report, reserve_composition, certificate, other
Depositsterm_sheet, legal_opinion, regulatory_filing, compliance_report, financial_statement, interest_schedule, certificate, other
Real estatelegal_opinion, regulatory_filing, compliance_report, appraisal, property_deed, survey_report, environmental_assessment, title_insurance, insurance_certificate, certificate, other
Precious metalslegal_opinion, regulatory_filing, compliance_report, assay_certificate, storage_receipt, chain_of_custody, insurance_certificate, certificate, other

For API and CLI integrations, send a documentType value that belongs to the asset profile you are updating. For example, use reserve_audit, attestation_report, or reserve_composition for stablecoin reserve files, and use assay_certificate, storage_receipt, or chain_of_custody for precious metal files. Use other only when the file does not fit a more specific type.

The visibility field controls who can access the file:

  • public: visible to any caller who can reach the token document surface.
  • holders: visible to a caller who holds an operational role on the asset, and to an investor who holds the token. Holding the token means the caller's wallet has a confirmed non-zero balance of the asset. A balance-only holder reads holder-tier documents; they do not gain management rights over them.
  • restricted: visible only to a caller with governance or admin rights on the asset.

DALP confirms a caller's balance from indexed on-chain state. This check only affects the balance-based path: a caller who holds an asset role keeps holder-tier access regardless. If the balance lookup cannot complete, the balance-only path fails closed, so a caller without a role and without a confirmed balance does not receive holder-tier files. This keeps a transient lookup problem from widening access by mistake.

Choose the narrowest value that fits the operating process and regulatory basis for the file. When in doubt, restrict access and widen it later.

List documents

Use the list endpoint to reconcile published files or populate an asset's document table. Call it from a background job or on demand when a user requests the file list for an asset.

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/documents?page[limit]=50&sort=-uploadedAt" \
  -H "X-Api-Key: sm_dalp_xxxxxxxxxxxxxxxx"

The list endpoint supports sorting, filtering, and facets with standard pagination. Sort by fileName, documentType, visibility, fileSize, or uploadedAt. Filter by fileName, documentType, visibility, mimeType, isLatest, fileSize, or uploadedAt.

Use the standard collection filter shape to narrow results. For example, request the latest public prospectuses uploaded after a cutoff time:

curl --globoff "https://your-platform.example.com/api/v2/tokens/0xTOKEN/documents?filter[documentType][eq]=prospectus&filter[visibility][eq]=public&filter[uploadedAt][gte]=2026-01-01T00:00:00.000Z" \
  -H "X-Api-Key: sm_dalp_xxxxxxxxxxxxxxxx"

The API returns only the latest non-deleted records visible to the caller. Public files are visible to any caller who can reach the token document surface. Holder-tier files are visible to a caller with an asset role or to an investor who holds the token, confirmed from a non-zero on-chain balance. Restricted files require governance or admin rights. The download endpoint applies the same access rule, so the list never surfaces a file the caller cannot then download.

The list response uses the standard shape with data, meta, and links. Each row includes the document identifiers, token address, type, access level, version group fields, file metadata, optional title and description, fileHash, uploadedAt, uploader details, and thumbnailUrl.

Preview thumbnails

Each list row carries a thumbnailUrl so you can render a visual preview next to the file without downloading the full document. Use it to build a document gallery or to show a thumbnail in an asset's document table.

File typethumbnailUrl value
PDFPresigned URL of a generated preview of the first page.
Image (jpeg, png, webp)Presigned URL of the image itself.
Word, spreadsheet, CSV, othernull. Fall back to a type icon in your interface.

A thumbnail URL is a short-lived presigned link, separate from the full download URL, and expires one hour after the list response is generated. Re-list to get a fresh URL rather than caching it. The field is also null when a thumbnail has not been generated yet or its stored object cannot be read, so always handle the null case in your interface.

Download or delete

To retrieve a file, request a secure download URL:

const download = await client.token.documents.getDownloadUrl({
  params: {
    tokenAddress: "0xTOKEN",
    documentId: document.data.id,
  },
});

To remove a file from the asset's record, call delete. Only do this when the file should no longer appear on the API surface:

await client.token.documents.delete({
  params: {
    tokenAddress: "0xTOKEN",
    documentId: document.data.id,
  },
});

Keep your delete reasoning and approval records in your operating logs. The call removes the file from the API surface but does not replace your regulated record-keeping process.

Error codes

When a document operation fails, the API returns a stable DALP-NNNN error code. Branch on the code rather than the message text so an automated integration can decide whether the caller corrects and resends, retries once, or routes the failure to an operator. Each code below maps to a canonical entry in the platform API error reference.

The Retry column states whether resending helps. no retry means the caller must change the request, the credentials, or the uploaded file before the call will succeed. operator means the caller cannot resolve the failure from the request alone and should re-prepare the upload or contact the operator.

Confirm the uploaded file

These codes surface on the confirm step, after the file bytes reach storage. They guard the object key, the declared size, the document type, the replacement group, and the record write.

CodeCategoryRetryWhen it happens
DALP-0327clientno retryThe objectKey does not start with the token's storage prefix or contains path traversal sequences. Send the objectKey from the upload URL response unchanged.
DALP-0326clientno retryThe platform could not read the uploaded file at the expected location. Re-upload the file through the presigned URL, confirm it completed, then confirm again.
DALP-0321operationalno retryThe stored object's byte length differs from the fileSize in the confirm request, and the orphaned object was removed. Re-upload and confirm with the exact file size.
DALP-0324clientno retryThe documentType is not permitted for the token's asset type. This check also runs on the upload URL request, so a bad type can fail there first. Choose a type allowed by the asset profile and resend.
DALP-0322clientno retryThe replaceGroupId matches no existing document group for this token. The uploaded object was removed. Request a fresh upload URL, re-upload the file, and confirm with the new object key.
DALP-0325operationaloperatorThe platform inserted the document metadata but the insert returned no row, indicating a persistence failure, and the orphaned object was removed from storage. Request a fresh upload URL, re-upload the file, and confirm with the new object key. If it recurs, contact support with the request ID.

Download a document

These codes surface on the download URL request. They enforce the document's visibility level against the caller's token roles and on-chain balance.

CodeCategoryRetryWhen it happens
DALP-0323clientno retryThe document ID matches no active document for this token. Verify the ID against the token's document list and resend.
DALP-0319clientno retryThe document has holders visibility, and the caller holds no role on the token and no confirmed on-chain balance of it. Use credentials for a wallet that holds a token role or a positive balance of the asset, or ask an administrator to assign a role.
DALP-0320operationalno retryThe document has restricted visibility and the caller holds no governance or admin role on the token. Use credentials with a governance or admin role.

Delete a document

The delete operation reuses the document lookup, so it returns the same not-found code when the target no longer exists.

CodeCategoryRetryWhen it happens
DALP-0323clientno retryThe document ID matches no active document for this token. The document may have been deleted already, or the ID may belong to a different token. Verify the ID and resend.

CLI commands

The DALP CLI exposes the same operations:

dalp tokens documents list 0xTOKEN

dalp tokens documents get-upload-url \
  --address 0xTOKEN \
  --fileName bond-prospectus.pdf \
  --fileSize 2400000 \
  --mimeType application/pdf \
  --documentType prospectus \
  --visibility public

dalp tokens documents confirm-upload \
  --address 0xTOKEN \
  --objectKey uploads/token-documents/example-object-key \
  --documentType prospectus \
  --fileName bond-prospectus.pdf \
  --fileSize 2400000 \
  --mimeType application/pdf \
  --visibility public

dalp tokens documents get-download-url \
  --address 0xTOKEN \
  --documentId doc_123

dalp tokens documents delete \
  --address 0xTOKEN \
  --documentId doc_123

Use the API or SDK for the direct file upload step. The CLI returns the presigned URL and object key but does not upload local file bytes.

See also

On this page