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:
- Request a presigned upload URL for a token document.
- Upload the file directly to storage using the returned method and headers.
- Confirm the upload so DALP records the file against the token.
- 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
documentTypeagainst 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.
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}/documentslists token documents with filtering and sorting (paginated).POST /api/v2/tokens/{tokenAddress}/document-uploadsreturns a presigned upload URL.POST /api/v2/tokens/{tokenAddress}/documentsconfirms an uploaded file and creates the document record.POST /api/v2/tokens/{tokenAddress}/documents/{documentId}/downloadsreturns 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:
| Field | Required | Description |
|---|---|---|
documentType | Yes | Token document type. Use a value allowed by the asset profile. |
fileName | Yes | File name, up to 255 characters. |
fileSize | Yes | Integer size in bytes. The value must be positive and no larger than 50 MiB. |
mimeType | Yes | One of the supported MIME types below. |
visibility | Yes | public, holders, or restricted. |
title | No | Display title, up to 500 characters. |
description | No | Description, 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 profile | Reserve or asset evidence document types |
|---|---|
stablecoin | reserve_audit, attestation_report, reserve_composition, certificate, or other. |
precious-metal | assay_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.
Supported MIME types are:
application/pdfimage/jpegimage/pngimage/webpapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
The upload URL response includes:
| Field | Description |
|---|---|
uploadUrl | Presigned URL for the direct file upload. |
objectKey | Storage object key to send in the confirm request. |
expiresAt | Expiry timestamp for the presigned URL. |
method | HTTP method for the upload. Token documents use PUT. |
headers | Headers 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
fileHashthat 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 profile | Document type choices |
|---|---|
| Bonds | prospectus, term_sheet, legal_opinion, regulatory_filing, compliance_report, annual_report, financial_statement, credit_rating, covenant_agreement, interest_schedule, certificate, other |
| Equity | prospectus, term_sheet, legal_opinion, regulatory_filing, compliance_report, annual_report, financial_statement, shareholder_agreement, certificate, other |
| Funds | prospectus, term_sheet, legal_opinion, regulatory_filing, compliance_report, annual_report, financial_statement, fund_fact_sheet, subscription_agreement, nav_report, certificate, other |
| Stablecoins | legal_opinion, regulatory_filing, compliance_report, reserve_audit, attestation_report, reserve_composition, certificate, other |
| Deposits | term_sheet, legal_opinion, regulatory_filing, compliance_report, financial_statement, interest_schedule, certificate, other |
| Real estate | legal_opinion, regulatory_filing, compliance_report, appraisal, property_deed, survey_report, environmental_assessment, title_insurance, insurance_certificate, certificate, other |
| Precious metals | legal_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 anyone who can access the token document surface.holders: visible to token holders.restricted: limited to explicitly allowed access paths.
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 accessible through the token document surface. Holder-scoped files require a caller with an asset role; restricted files require governance or admin rights.
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, and uploader details.
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.
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_123Use 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.