ANP 1.1 is the default latest version. ANP 1.0 remains available as an archive.
ANP Profile 7: Attachments and Object Transfer
- Document ID: ANP-P7
- Title: Attachments and Object Transfer
- Status: Draft
- Version: 0.5.0
- Language: English
- Applicability: This Profile is applicable to the interoperability semantics of attachments, large objects and media objects in ANP, and supports direct messaging, group messaging, unencrypted message bearers and end-to-end encryption message bearers.
1. Purpose
This Profile defines the Attachments and Object Transfer semantics of ANP, stipulating:
- How to express attachments in direct messaging and group messaging;
- How to carry unified
attachment_manifestin non-E2EE and E2EE messages; - How to split attachment transmission into three layers: message plane, control plane, and data plane;
- How to upload and download object content through independent HTTPS channels;
- How to reduce the risk of link leakage through object location URI, short-term Download Ticket and Object-Level Encryption;
- How to perform integrity verification, access control and Object-Level Encryption on the object content;
- How to keep the v1 solution clear, simple, and implementable.
This Profile does not define:
- Internal implementation of object storage;
- Object review and risk control strategies;
- Specific cryptographic issuance format for object Download Ticket;
- object byte stream cross-domain call link forwarding through ANP;
service-managedobject encryption mode;wrapped_object_key, file-level key agreement protocol, direct link download, mirror URI, inline Download Ticket and other forked paths;- Dedicated thumbnail sub-objects and dedicated chunked list objects.
2. Terminology and Normative Keywords
In this article, MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY, OPTIONAL are interpreted as normative requirements in their capitalized form.
Definition of terms:
- Attachment: External object referenced through ANP message, its content can be a file, image, audio, video or any byte stream.
- Object: The actual byte content corresponding to the attachment.
- Attachment Message: ANP message with one or more
attachment_manifestas primary payload. - Attachment Manifest: A structured object that describes the object's location, summary, size, media properties, and encryption properties.
- Object Service: Responsible for the service of attachment control plane and object data plane.
- Control Plane: The plane where
attachment.create_slot,attachment.commit_object,attachment.abort_object,attachment.get_download_ticketand other protocol methods are located. - Data Plane: The plane on which object bytes are transferred via independent HTTPS PUT/GET.
- Message Plane:
direct.send,group.sendcarryattachment_manifestplane. - Upload Slot: The temporary upload capability and metadata place applied by the sender for uploading objects.
- Committed Object: An object that has been uploaded and can be referenced by messages.
- Object URI: Object location URI. In v1, it is a locator-style HTTPS resource address, which is not equivalent to a public direct link.
- Download Ticket: Temporary access ticket used when the object is downloaded.
- Access Grant: The download authorization record established by the sender service for an attachment after the attachment message is successfully sent.
- Object-Level Encryption: Encryption of object contents performed locally by the sender, rather than relying solely on transport-layer confidentiality.
- Object Key: A random symmetric key generated individually by the sender for an object.
- Nonce: Nonce used with object encryption; length fixed to 12 bytes in v1 MTI.
3. General Design Principles and v1 Consolidation Decisions
3.1 Three-layer separation
Attachment transfers MUST be understood as three planes:
- Message side: only responsible for sending
attachment_manifestto the recipient; - control plane: only responsible for applying for upload slots, submitting objects, discarding objects, and issuing Download Ticket;
- data plane: Only responsible for PUT/GET object bytes.
These three levels of responsibilities MUST NOT be confused. Especially:
- Control-Plane Methods is not responsible for sending attachments to the recipient;
- The message plane is not responsible for relaying object bytes;
- data plane is not responsible for business message delivery.
3.2 v1 mainline path
The standard mainline path MUST for v1 is:
- The sender calls
attachment.create_slot; - If Object-Level Encryption is enabled, the sender first encrypts the file locally;
- The sender uploads the object bytes through independent HTTPS
PUT; - The sender calls
attachment.commit_object; - The sender sends the attachment list through
direct.sendorgroup.send; - The receiver parses the public
ANPMessageServicebased on the original message sender's DID carrying the attachment list, and obtains Download Ticket throughattachment.get_download_ticket; - The receiver downloads the object through independent HTTPS
GET object_uriand carries ticket in theAuthorizationheader; - The receiver verifies the digest; if the object has
object-e2eeenabled, then perform decryption and post-decryption verification.
Before entering the concrete control-plane methods, the following overview connects the message plane, control plane, and data plane. It helps readers distinguish the three stages of "object exists", "message has been sent", and "download has been authorized" when reading the scenarios in Section 5.
flowchart TD
C[Sender client]
SLOT[attachment.create_slot]
PUT[HTTPS PUT object bytes]
COMMIT[attachment.commit_object]
SEND[Send attachment manifest<br/>direct.send / group.send]
GRANT[Create Access Grant after message accepted]
R[Receiver]
TICKET[attachment.get_download_ticket]
GET[HTTPS GET object_uri]
C --> SLOT --> PUT --> COMMIT --> SEND --> GRANT
R --> TICKET --> GET
GRANT --> TICKET2
3
4
5
6
7
8
9
10
11
12
13
14
15
Figure P7-1: Overview of attachment three-plane flow and authorization chain (non-normative).
This diagram emphasizes that create_slot / commit_object only create the object. What actually makes it downloadable to the receiver is the Access Grant established after the attachment message is accepted, followed by the download-ticket flow.
3.3 Only keep two object modes
In v1, encryption_info.mode MUST only allows the following two values:
noneobject-e2ee
service-managed MUST NOT appear in the protocol field.
Server-side disk encryption, KMS, object warehouse static encryption, etc. are all implementation details, and MUST NOT be modeled as a protocol interoperability mode.
3.4 Separation of message security and object security
There are two levels of security for attachments:
- Message Security: Determined by
transport-protected,direct-e2ee, andgroup-e2eethat carry the list; - Object Security: Determined by
encryption_info.mode.
The rules for v1 are:
- Attachment objects MUST use
mode = "none"undertransport-protectedhosting; - Attachment object MAY use
mode = "none"ormode = "object-e2ee"underdirect-e2eeorgroup-e2eehosting.
3.5 Object Keys Are Delivered Only Through E2EE Manifests
When mode = "object-e2ee":
object_key_b64uandnonce_b64uMUST only appear in the list of attachments protected bydirect-e2eeorgroup-e2ee;object_key_b64uandnonce_b64uMUST NOT appear in the control plane request ofattachment.create_slotorattachment.commit_object;- v1 undefined Separate file-level key agreement protocol.
3.6 v1 Explicitly removed forked paths
In order to keep v1 clear, simple, and implementable, the following paths are not allowed to enter this Profile:
service-managedwrapped_object_key_b64ukey_wrap_alg- Inline Download Ticket
- Custom ticket transport header negotiation
- Permanent public direct link
- Mirror URI
- Specialized chunked list structure
- Dedicated thumbnail sub-object
- Relay object bytes through ANP business methods
3.7 Allowed Combination Matrix
| Bearing mode | meta.security_profile | Allowed encryption_info.mode | Can object_key_b64u appear in the list |
|---|---|---|---|
| Direct Base | transport-protected | none | No |
| Group Base | transport-protected | none | No |
| Direct E2EE | direct-e2ee | none / object-e2ee | Yes |
| Group E2EE | group-e2ee | none / object-e2ee | Yes |
4. Profile identification and dependencies
4.1 Profile name
The standard name of this Profile is:
anp.attachment.v1
4.2 Dependencies
This Profile MUST depend on:
anp.core.binding.v1anp.identity.discovery.v1
This Profile MAY be used in combination with the following Profiles:
anp.direct.base.v1anp.group.base.v1anp.direct.e2ee.v1anp.group.e2ee.v1
4.3 Security Profile
This Profile itself does not define new security profile, but reuses the business Profile that carries it:
transport-protecteddirect-e2eegroup-e2ee
5. Attachment Transfer Flow Diagrams
5.1 Overall hierarchical flow chart
flowchart TD
A[Sender Client] -->|attachment.create_slot| S[Control Service]
A -->|HTTPS PUT object bytes| O[Object Data Plane]
A -->|direct.send / group.send\nattachment_manifest| M[Recipient or Group Host]
M -->|Resolve using sender_did from the original message\nattachment.get_download_ticket| S
M -->|HTTPS GET object_uri\nAuthorization: Bearer ticket| O2
3
4
5
6
5.2 Direct Messaging / Unencrypted Attachment
sequenceDiagram
participant A as Sender Client A
participant AS as A Domain Service
participant OS as Object Service
participant BS as B Domain Service
participant B as Recipient Client B
A->>AS: attachment.create_slot (mode=none)
AS-->>A: upload_uri + object_uri
A->>OS: HTTPS PUT plaintext bytes
A->>AS: attachment.commit_object
AS-->>A: committed = true
A->>AS: direct.send (transport-protected, manifest)
AS->>BS: direct.send
BS-->>AS: accepted
BS-->>B: direct.incoming / equivalent delivery mechanism
B->>AS: attachment.get_download_ticket (resolved from the original message sender_did)
AS-->>B: download_ticket
B->>OS: HTTPS GET object_uri + Authorization
OS-->>B: plaintext bytes
B->>B: validate size / digest2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
5.3 Direct Messaging / E2EE Attachments
sequenceDiagram
participant A as Sender Client A
participant AS as A Domain Service
participant OS as Object Service
participant BS as B Domain Service
participant B as Recipient Client B
A->>AS: attachment.create_slot (mode=object-e2ee)
AS-->>A: upload_uri + object_uri
A->>A: Generate object_key + nonce locally\nEncrypt the file locally
A->>OS: HTTPS PUT ciphertext bytes
A->>AS: attachment.commit_object
AS-->>A: committed = true
A->>AS: direct.send (direct-e2ee, inner manifest carries object_key)
AS->>BS: direct.send
BS-->>AS: accepted
BS-->>B: direct.incoming / equivalent delivery mechanism
B->>B: Decrypt the inner manifest\nObtain object_key + nonce
B->>AS: attachment.get_download_ticket
AS-->>B: download_ticket
B->>OS: HTTPS GET object_uri + Authorization
OS-->>B: ciphertext bytes
B->>B: Validate ciphertext size / digest\nDecrypt locally2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
5.4 Group Messaging / Unencrypted Attachment
sequenceDiagram
participant A as Sender Client A
participant AS as A Domain Service
participant OS as Object Service
participant GH as Group Host
participant M as Group Member Client
A->>AS: attachment.create_slot (mode=none)
AS-->>A: upload_uri + object_uri
A->>OS: HTTPS PUT plaintext bytes
A->>AS: attachment.commit_object
AS-->>A: committed = true
A->>GH: group.send (transport-protected, manifest)
GH-->>A: accepted + group_receipt
GH-->>M: group.incoming
M->>AS: attachment.get_download_ticket (resolved from the original message sender_did)
AS-->>M: download_ticket
M->>OS: HTTPS GET object_uri + Authorization
OS-->>M: plaintext bytes
M->>M: validate size / digest2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
5.5 Group Messaging / E2EE Attachments
sequenceDiagram
participant A as Sender Client A
participant AS as A Domain Service
participant OS as Object Service
participant GH as Group Host
participant M as Group Member Client
A->>AS: attachment.create_slot (mode=object-e2ee)
AS-->>A: upload_uri + object_uri
A->>A: Generate object_key + nonce locally\nEncrypt the file locally
A->>OS: HTTPS PUT ciphertext bytes
A->>AS: attachment.commit_object
AS-->>A: committed = true
A->>GH: group.send (group-e2ee, inner manifest carries object_key)
GH-->>A: accepted + group_receipt
GH-->>M: group.incoming
M->>M: Decrypt the inner manifest\nObtain object_key + nonce
M->>AS: attachment.get_download_ticket
AS-->>M: download_ticket
M->>OS: HTTPS GET object_uri + Authorization
OS-->>M: ciphertext bytes
M->>M: Validate ciphertext size / digest\nDecrypt locally2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
6. Carriage Rules: Direct Messaging, Group Messaging, Encrypted, and Unencrypted
6.1 Carried in Direct Base
When the attachment list is sent in anp.direct.base.v1 via direct.send:
meta.profileMUST equalanp.direct.base.v1meta.security_profileMUST equaltransport-protectedmeta.content_typeMUST equalapplication/anp-attachment-manifest+jsonbody.payloadMUST be the Attachment Message objectauth.origin_proofMUST exist and binds the entire Signed Direct Payload as required by P3- where each
attachment_manifest.encryption_info.modeMUST be equal tonone
6.2 Carried in Group Base
When the attachment list is sent in anp.group.base.v1 via group.send:
meta.profileMUST equalanp.group.base.v1meta.security_profileMUST equaltransport-protectedmeta.content_typeMUST equalapplication/anp-attachment-manifest+jsonbody.payloadMUST be the Attachment Message objectauth.origin_proofMUST exist and binds the entire Signed Group Payload as required by P4- Successful Response SHOULD return
group_receipt - where each
attachment_manifest.encryption_info.modeMUST be equal tonone
6.3 Carried in Direct E2EE
When the attachment list is sent via anp.direct.e2ee.v1:
- Under the normal path after session establishment, the outer
meta.content_typeMUST beapplication/anp-direct-cipher+json - If the first init carrying application message path allowed by P5 is used, the outer
meta.content_typeMAY beapplication/anp-direct-init+json - Attachment list MUST appear as the inner business object of
Application Plaintextbefore encryption - Inner layer
application_content_typeMUST equalapplication/anp-attachment-manifest+json
6.4 Carried in Group E2EE
When the attachment list is sent via anp.group.e2ee.v1:
- Outer layer
meta.content_typeMUST fixed toapplication/anp-group-cipher+json - Outer layer
bodyMUST NOT directly appears the clear text attachment list - Attachment list MUST appear as the inner business object of
Group Application Plaintextbefore encryption - Inner layer
application_content_typeMUST equalapplication/anp-attachment-manifest+json
7. attachment_message and attachment_manifest objects
7.1 Attachment Message top-level structure
The recommended structure of Attachment Message is as follows:
{
"attachments": [
{
"attachment_id": "att-001",
"filename": "report.pdf",
"mime_type": "application/pdf",
"size": "1048576",
"digest": {
"alg": "sha-256",
"value_b64u": "BASE64URL_DIGEST"
},
"access_info": {
"object_uri": "https://objects.example.com/objects/obj-001"
},
"encryption_info": {
"mode": "none"
}
}
],
"caption": "Attachment description",
"primary_attachment_id": "att-001"
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Rules:
attachmentsMUST exist and is not emptycaptionMAY existprimary_attachment_idMAY exist; if it exists, MUST point to an existingattachment_idinattachments
7.2 attachment_id scope
attachment_idMUST be unique within a single Attachment Messageattachment_idnot guaranteed to be globally unique across messages- Any Download Ticket binding, authorization record, or audit record, MUST use
(message_id, attachment_id)or(object_uri, message_id, attachment_id), not justattachment_id
7.3 Single attachment_manifest
Each attachment_manifest MUST contain:
attachment_idmime_typesizedigestaccess_infoencryption_info
Each attachment_manifest MAY contain:
filenamemedia_info
Field description:
filename: Display file name; MAYmime_type: MIME type of the original file; MUSTsize: Upload object byte size, decimal string; MUSTdigest: Upload object byte summary; MUSTaccess_info: Object download positioning information; MUSTencryption_info: Object-Level Encryption message; MUSTmedia_info: Supplementary description of media objects such as pictures, audio and video; MAY
7.4 digest
digest MUST contain:
algvalue_b64u
Rules:
digest.algin v1 MUST fixed tosha-256digest.value_b64uMUST be the SHA-256 digest of the upload object bytes- When
encryption_info.mode = "none", the digest corresponds to plaintext bytes - When
encryption_info.mode = "object-e2ee", the digest corresponds to the ciphertext byte
7.5 access_info
The structure of access_info is as follows:
{
"object_uri": "https://objects.example.com/objects/obj-001"
}2
3
Rules:
object_uriMUST be thehttps://URLobject_urirepresents a locator-style object address in v1; it is not a permanent public direct link- The receiver MUST call
attachment.get_download_ticketbefore downloading - The receiver MUST parse its public
ANPMessageServicebased on the original message sender's DID carrying the attachment list. - In a group scenario, the above original message sender DID MUST be taken from the original group message sender carrying the attachment list (e.g.
group.incoming.meta.sender_did) attachment.get_download_ticketMUST be sent to theserviceDidcorresponding to the sender’s public service.- When the receiver downloads, MUST initiate
GETtoobject_uriand carries ticket in theAuthorizationheader. - The caller MUST NOT only guesses the control plane service based on the URL domain name of
object_uri
7.6 media_info
media_info is suitable for media objects such as pictures, audio, and video. Recommended fields:
widthheightduration_mscodec
If numeric fields are present, MUST use decimal strings.
7.7 Thumbnails and chunking
v1 does not define a dedicated thumbnail field, nor does it define a dedicated chunking_info field.
If a thumbnail is required, the sender SHOULD send the thumbnail as a normal attachment.
If large files need to be uploaded in chunks, SHOULD be done internally within the HTTP upload implementation; this does not change the manifest structure of this Profile.
8. Object-Level Encryption
8.1 encryption_info
encryption_info MUST be one of the following two structures.
Unencrypted object:
{
"mode": "none"
}2
3
Object-Level Encryption object:
{
"mode": "object-e2ee",
"object_cipher": "chacha20-poly1305",
"object_key_b64u": "BASE64URL_32_BYTES",
"nonce_b64u": "BASE64URL_12_BYTES",
"plaintext_size": "1048576"
}2
3
4
5
6
7
Rules:
modeMUST take eithernoneorobject-e2eemode = "none"indicates that the sender did not locally encrypt the object content.mode = "object-e2ee"means that the sender first encrypts the object locally and then uploads the encrypted text bytes.- Under
transport-protectedhosting,modeMUST benone object_key_b64uandnonce_b64uMUST NOT appear in the list of attachments carried bytransport-protectedservice-managed, key wrapping algorithm, and file-level key agreement do not belong to this Profile
8.2 MTI algorithm of object-e2ee
The object-e2ee MTI algorithm MUST for v1 is:
object_cipher = "chacha20-poly1305"object_key_b64u: 32-byte random symmetric keynonce_b64u: 12-byte random nonceplaintext_size: Original file length in bytes, decimal string
8.3 Sender encryption steps (normative)
When encryption_info.mode = "object-e2ee", the sender MUST perform the following steps:
- Read the original file bytes, recorded as
P - Generate a new random 32-byte object key
K - Generate a new random 12-byte nonce
N - Let
AAD = empty byte string - Calculate:
C = ChaCha20-Poly1305-Encrypt(
key = K,
nonce = N,
aad = "",
plaintext = P
)2
3
4
5
6
- The object bytes uploaded to the Object Service MUST be
C attachment_manifest.sizeMUST be a decimal string equal tolen(C)attachment_manifest.digestMUST equalsha-256(C)encryption_info.plaintext_sizeMUST be a decimal string equal tolen(P)mime_typeMUST continue to represent the MIME type of the original file, not the ciphertext object MIME type
Additional requirements:
- Each committed object MUST use a new random
K - Sender MUST NOT reuse the same
(K, N)combination - Even if the same file content is sent repeatedly, the sender SHOULD regenerate new
KandN object_key_b64uMUST NOT taken directly from P5's ratchet key, also MUST NOT taken directly from P6's MLS epoch secret or other session key
8.4 expected_size and plaintext_size
Under chacha20-poly1305 for v1 MTI:
- Upload object size = original file size + 16-byte authentication tag
- If the sender fills in
expected_sizeinattachment.create_slot, the value SHOULD point to the upload object size, not the original file size - If
mode = "object-e2ee", the sender SHOULD also saves the original file size locally so thatencryption_info.plaintext_sizecan be written later
8.5 Receiver verification and decryption steps (normative)
When the receiver gets the object bytes:
- MUST first verify that the downloaded byte length is equal to
attachment_manifest.size - MUST calculate
sha-256(downloaded bytes)and compare it withattachment_manifest.digest - If
encryption_info.mode = "none", it can be delivered to the upper layer after successful verification. - If
encryption_info.mode = "object-e2ee", the receiver MUST use:
P = ChaCha20-Poly1305-Decrypt(
key = object_key_b64u,
nonce = nonce_b64u,
aad = "",
ciphertext = downloaded_bytes
)2
3
4
5
6
- If decryption fails, the recipient MUST reject the attachment
- If the decryption is successful, the receiver MUST verify whether
len(P)is equal toplaintext_size - After passing the verification, the receiver can deliver the plaintext byte to the upper-layer business
8.6 Object key distribution rules
There is only one standard object key distribution path for v1:
- When the attachment message itself is protected by
direct-e2eeorgroup-e2ee, the sender MAY directly putsobject_key_b64uandnonce_b64uinto the innerattachment_manifest - After the receiver obtains the object key from the E2EE message, it then obtains ticket through control plane and downloads the ciphertext object through data plane.
This means:
- v1 No need to design a complex key agreement protocol separately for attachments
- In a group scenario, anyone who can decrypt the group messages can get the object key.
- v1 Not Guaranteed Retrospective withdrawal of rights; if members who are removed from the group have obtained the object key and object content before, this specification does not promise to erase the information they have obtained afterwards.
9. Access Authorization and Download Ticket
9.1 Ticket Targets
The goal of Download Ticket is not to absolutely prevent legitimate recipients from forwarding, but to:
- Prevent third parties from directly downloading objects based only on the list
- Prevent
object_urifrom becoming a long-term public link - Constrain download authorization to a clear requester and message context
- Provide a starting point for implementing auditing, rate limiting and cancellation of object services
9.2 Access Grant semantics
attachment.create_slot and attachment.commit_object are only responsible for creating objects and do not grant download permission to any recipient.
When an object is available for download by the recipient of a message, MUST be determined by the Access Grant.
When the direct.send or group.send carrying the attachment is accepted by the sender service or Group Host, the sender-side system MUST create an Access Grant for each attachment.
Access Grant At least MUST bind:
message_idattachment_idobject_urimessage_security_profilemessage_target_didin the context of direct messaging; orgroup_didin the context of group messaging
9.3 Boundaries of intended_target
attachment.create_slot.body.intended_target is just a policy hint for the sender's upload phase.
intended_target:
- MAY be used for Object Service to make size, type or retention policy determinations in advance
- MUST NOT used solely as a basis for download authorization
The actual download authorization basis MUST come from the Access Grant sent successfully.
9.4 Ticket Binding
In v1, Download Ticket MUST bind at least the following context:
attachment_idobject_urirequester_didmessage_idmessage_security_profilemessage_target_didin the context of direct messaging; orgroup_didin the context of group messagingexpires_at
9.5 Ticket Lifetime and Usage
- Download Ticket SHOULD be short-term ticket
- The default validity period SHOULD NOT exceed 5 minutes
- For highly sensitive subjects MAY use disposable ticket
- Download Ticket MUST transmitted via HTTP
Authorizationheader - Download Ticket MUST NOT carried via URL query parameters
The fixed download method for v1 is:
GET {object_uri}
Authorization: Bearer {download_ticket}2
9.6 Ticket Issuance Validation
When the Object control service handles attachment.get_download_ticket, MUST check:
meta.target.kind = "service"meta.target.didMUST be equal to the publicANPMessageService.serviceDidresolved from the sender DID of the original attachment message.requester_did = meta.sender_did- The Access Grant corresponding to
(message_id, attachment_id, object_uri)exists message_security_profileis consistent with Access Grant- When direct messaging context is used,
message_target_didexists and complies with the policy - When group messaging context is entered,
group_didexists andrequester_didcurrently still complies with the group access policy
9.7 Cross-service synchronization
v1 Not separately standardized Access Grant synchronization protocol between multiple internal services.
In the default v1 path, the Download Ticket is issued by the ANPMessageService exposed by the original sender of the attachment message. Whether that public service entry routes internally to an independent Object Service is an implementation detail. If the deployer separates the object-control component internally, the implementation MUST ensure that the externally exposed service can obtain the Access Grant required to issue the Download Ticket from local state or internal synchronization.
9.8 Access boundaries after member changes
v1 Retroactive withdrawal is not guaranteed.
This means:
- The Object Service SHOULD refuse to issue a new Download Ticket to a removed member based on the current group state
- However, if the object bytes, object key, or downloaded content has previously reached a legitimate member, this specification does not promise to subsequently revoke its acquired access capabilities
Another critical boundary in P7 is that object existence does not imply object downloadability. The following diagram connects object commitment, message acceptance, Access Grant creation, ticket issuance, and final download into one authorization chain so that implementers can correctly apply access control.
sequenceDiagram
participant S as Sender service
participant O as Object Service
participant M as Message plane
participant R as Receiver
S->>O: create_slot / commit_object
Note over S,O: Only creates the object; does not create download authorization
S->>M: direct.send / group.send attachment manifest
M-->>S: message accepted
S->>S: Create Access Grant for each attachment
R->>S: attachment.get_download_ticket
S->>S: Validate requester_did + message_id + attachment_id + object_uri
S-->>R: download_ticket
R->>O: GET object_uri + Authorization2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Figure P7-2: Authorization chain for Access Grant and Download Ticket (non-normative).
Therefore, authorization for attachment.get_download_ticket should depend on message context and Access Grants, rather than only on object_uri or only on intended_target left during the upload stage.
10. Control-Plane Methods
10.1 General
The method in this section is used for object control plane. They not change direct.send, send group.send to Success Semantics.
These methods run by default on:
meta.profile = "anp.attachment.v1"meta.security_profile = "transport-protected"
And adopts the following authentication model:
attachment.create_slotattachment.commit_objectattachment.abort_objectattachment.get_download_ticket
All belong to service-scoped Control-Plane Methods.
Therefore:
meta.target.kindMUST equalservicemeta.target.didMUST equal target publicANPMessageService.serviceDid- Cross-domain outer-layer authentication is provided by P8 through
serviceDid + HTTP Message Signatures - v1 does not require the Object Service to re-verify the end recipient's
origin_proof
A control-plane detail that implementers easily overlook is that Upload Slot and Committed Object are not the same state. The following diagram places creation, upload, commit, abort, and expiration on one lifecycle.
stateDiagram-v2
[*] --> SlotCreated
SlotCreated --> Uploading: Start PUT
Uploading --> Uploaded: PUT completed
Uploaded --> Committed: attachment.commit_object
SlotCreated --> Aborted: attachment.abort_object
Uploading --> Aborted: attachment.abort_object
Uploaded --> Aborted: attachment.abort_object
SlotCreated --> Expired: timeout
Uploading --> Expired: timeout
Uploaded --> Expired: timeout2
3
4
5
6
7
8
9
10
11
12
13
Figure P7-3: Upload Slot / Object lifecycle (non-normative).
Implementations should not interpret "obtaining an object_uri" as "the object can already be referenced by a message". Only after the object enters the Committed state does it become eligible for legal reference by an attachment manifest.
10.2 attachment.create_slot
10.2.1 Semantics
Apply for an Upload Slot for the object to be uploaded.
10.2.2 Request Requirements
This method MUST use:
meta.target.kind = "service"meta.target.did = target public ANPMessageService.serviceDid
body MUST contain:
attachment_idintended_message_security_profileobject_encryption_mode
body SHOULD contain:
expected_sizemime_type
body MAY contain:
filenameexpected_digestintended_target
Field rules:
attachment_id: stringintended_message_security_profile:transport-protected/direct-e2ee/group-e2eeobject_encryption_mode:none/object-e2eeexpected_size: Upload object size in bytes, decimal stringexpected_digest: Upload object byte summaryintended_target: Object; the recommended structure is as follows:
{
"kind": "agent | group",
"did": "did:example:..."
}2
3
4
Constraints:
- When
intended_message_security_profile = "transport-protected",object_encryption_modeMUST benone - When
object_encryption_mode = "object-e2ee",expected_sizeSHOULD correspond to the ciphertext byte size intended_targetis just a hint, MUST NOT alone constitutes authorization.
10.2.3 Successful Response
A successful response MUST contain at least:
attachment_idslot_idupload_uriobject_uricommit_tokenexpires_at
A successful response MAY contain:
upload_headers
When the sender subsequently constructs attachment_manifest.access_info, object_uri SHOULD be directly taken from attachment.create_slot or attachment.commit_object's Successful Response; before downloading, the receiver will follow the provisions of this Profile and discover the ticket service based on the DID of the original attachment message sender.
10.3 attachment.commit_object
10.3.1 Semantics
Notify Object Service: The object has been uploaded and can be submitted as a referenceable object.
10.3.2 Request Requirements
This method MUST use:
meta.target.kind = "service"meta.target.did = target public ANPMessageService.serviceDid
body MUST contain at least:
attachment_idslot_idcommit_tokensizedigestobject_encryption_mode
body MAY contain:
plaintext_sizemedia_info
Rules:
digest.algMUST equalsha-256- When
object_encryption_mode = "object-e2ee",plaintext_sizeMUST exist attachment.commit_objectMUST NOT transmitobject_key_b64uattachment.commit_objectMUST NOT transmitnonce_b64uattachment.commit_objectsuccess not equal The receiver has been authorized to download the object; the actual download authorization depends on the Access Grant after the subsequent message is successfully sent.
10.3.3 Successful Response
A successful response MUST contain at least:
committedattachment_idobject_uricommitted_at
Among them:
committedMUST betrue
10.4 attachment.abort_object
10.4.1 Semantics
Terminate an upload slot that is incomplete or no longer needed.
10.4.2 Request Requirements
This method MUST use:
meta.target.kind = "service"meta.target.did = target public ANPMessageService.serviceDid
body MUST contain at least:
attachment_idslot_id
10.4.3 Successful Response
A successful response MUST contain at least:
abortedattachment_idaborted_at
Among them:
abortedMUST betrue
10.5 attachment.get_download_ticket
10.5.1 Semantics
When object access requires ticket, the receiver obtains temporary Download Ticket through this method.
10.5.2 Request Requirements
This method MUST use:
meta.target.kind = "service"meta.target.didMUST be equal to the publicANPMessageService.serviceDidresolved from the original attachment message sender DID
body MUST contain at least:
attachment_idobject_urirequester_didmessage_security_profilemessage_id
And add one according to the context:
- direct messaging Context:
message_target_did - group messaging Context:
group_did
body MAY contain:
one_time
Field rules:
requester_didMUST equalmeta.sender_didmessage_security_profilerefers to the message security profile that carries the attachment list, not themeta.security_profilecalled by control plane this time.message_target_didrefers to the target Agent DID of the original direct messaging messagegroup_didrefers to the group DID to which the original group message belongs- Before sending the ticket request, the caller MUST first parses its public
ANPMessageServicebased on the original attachment message sender's DID; in the group scenario, the DID is taken from the original group message sender, notgroup_did
10.5.3 Successful Response
A successful response MUST contain at least:
download_ticket_b64uexpires_atticket_binding
ticket_binding MUST contain at least:
attachment_idobject_urirequester_didmessage_idmessage_security_profile
And add one according to the context:
message_target_didgroup_did
11. Data-Plane Rules
11.1 Upload
The sender MUST initiate PUT to upload_uri using a separate HTTPS channel.
Rules:
- When
object_encryption_mode = "none", upload plain text stanza - When
object_encryption_mode = "object-e2ee", upload ciphertext bytes - Upload request MAY carry
upload_headers - Object bytes MUST NOT embedded in ANP's JSON-RPC business messages
11.2 Download
The receiver MUST initiate GET to object_uri using a separate HTTPS channel.
The fixed format is as follows:
GET {object_uri}
Authorization: Bearer {download_ticket}2
Object bytes MUST NOT be forwarded through ANP's cross-domain service invocation path as a regular forwarding channel.
11.3 Verification after downloading
After the download completes, the receiver MUST perform at least the following checks:
- Length verification
- Digest verification
- If
mode = "object-e2ee", perform decryption andplaintext_sizeverification
When any key check fails, the receiver:
- MUST NOT deliver the object to the higher-layer application as a valid attachment
- SHOULD log diagnostic information
12. Error Conditions and Recommended Error Codes
This Profile fixedly allocates the 6000-6013 code segment for the Attachments and Object Transfer error. When the server returns this error, error.data.anp_code MUST exist.
code | anp_code | Meaning |
|---|---|---|
| 6000 | anp.attachment.slot_not_found | No available Upload Slot found, or slot_id does not match the current context |
| 6001 | anp.attachment.slot_expired | The Upload Slot has expired and cannot be uploaded, submitted or discarded |
| 6002 | anp.attachment.commit_token_invalid | The submission token is missing, illegal, failed to verify, or does not match the current object context |
| 6003 | anp.attachment.object_too_large | The object size exceeds the service limit, policy limit, or exceeds the allowed range |
| 6004 | anp.attachment.unsupported_mime_type | mime_type is not accepted by the current service or policy |
| 6005 | anp.attachment.grant_not_found | The corresponding Access Grant was not found, or the message was that the download authorization has not been established |
| 6006 | anp.attachment.unauthorized_requester | The current requester_did does not satisfy the download policy, target constraints, or group access constraints |
| 6007 | anp.attachment.download_ticket_invalid | Download Ticket is missing, illegal, failed to verify signature, cannot be parsed, or has been invalidated |
| 6008 | anp.attachment.ticket_binding_mismatch | Download Ticket The bound object, message, or requester context is inconsistent with the actual request |
| 6009 | anp.attachment.ticket_expired | Download Ticket has expired |
| 6010 | anp.attachment.digest_mismatch | The object digest after uploading or downloading is inconsistent with the expected digest |
| 6011 | anp.attachment.decrypt_failed | object-e2ee Object decryption failed |
| 6012 | anp.attachment.object_unavailable | The object has not been submitted, has been abandoned, has been cleaned, or is temporarily unavailable |
| 6013 | anp.attachment.encryption_policy_violation | The combination of object encryption mode and message security profile is illegal, or violates the constraints of this Profile |
Error response SHOULD be provided in error.data:
attachment_idslot_idobject_urimessage_idexpected_digest
13. Minimum Interoperability Requirements
An implementation conforming to this Profile MUST support at least:
attachment.create_slotattachment.commit_objectattachment.abort_objectattachment.get_download_ticketapplication/anp-attachment-manifest+jsonattachment_message.attachmentsattachment_manifest’sattachment_id,mime_type,size,digest,access_info,encryption_infoaccess_info.object_uri- Discover
attachment.get_download_tickettarget service based on original attachment message sender DID digest.alg = sha-256- Standalone HTTPS
PUT upload_uri - Standalone HTTPS
GET object_uri Authorization: Bearer {download_ticket}download mode- All
attachment.*Control-Plane Methods usestarget.kind = "service" - Object bytes are not forwarded through ANP business messages or cross-domain service invocation paths
mode = "none"undertransport-protected
If an implementation claims to support E2EE attachments, it MUST also:
- Support
mode = "object-e2ee" - Support the
chacha20-poly1305object encryption process specified in this Profile - Distribute
object_key_b64uandnonce_b64udirectly in the E2EE attachment list - Perform ciphertext digest verification and local decryption after object download
- Clearly comply with the access boundaries of "v1 does not guarantee retroactive withdrawal of rights"
14. Example
14.1 attachment.create_slot request example
{
"jsonrpc": "2.0",
"id": "req-70001",
"method": "attachment.create_slot",
"params": {
"meta": {
"anp_version": "1.0",
"profile": "anp.attachment.v1",
"security_profile": "transport-protected",
"sender_did": "did:example:agent-a",
"target": {
"kind": "service",
"did": "did:example:domain-a"
},
"operation_id": "op-70001",
"created_at": "2026-03-29T14:00:00Z"
},
"body": {
"attachment_id": "att-001",
"expected_size": "1048592",
"mime_type": "application/pdf",
"filename": "report.pdf",
"intended_message_security_profile": "direct-e2ee",
"intended_target": {
"kind": "agent",
"did": "did:example:agent-b"
},
"object_encryption_mode": "object-e2ee"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
14.2 attachment.create_slot Successful Response Example
{
"jsonrpc": "2.0",
"id": "req-70001",
"result": {
"attachment_id": "att-001",
"slot_id": "slot-70001",
"upload_uri": "https://objects.example.com/upload/slot-70001",
"upload_headers": {
"Content-Type": "application/octet-stream"
},
"object_uri": "https://objects.example.com/objects/obj-abc",
"commit_token": "ct-abc-123",
"expires_at": "2026-03-29T14:15:00Z"
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
14.3 attachment.commit_object request example
{
"jsonrpc": "2.0",
"id": "req-70002",
"method": "attachment.commit_object",
"params": {
"meta": {
"anp_version": "1.0",
"profile": "anp.attachment.v1",
"security_profile": "transport-protected",
"sender_did": "did:example:agent-a",
"target": {
"kind": "service",
"did": "did:example:domain-a"
},
"operation_id": "op-70002",
"created_at": "2026-03-29T14:03:00Z"
},
"body": {
"attachment_id": "att-001",
"slot_id": "slot-70001",
"commit_token": "ct-abc-123",
"size": "1048592",
"digest": {
"alg": "sha-256",
"value_b64u": "BASE64URL_SHA256_OF_CIPHERTEXT"
},
"object_encryption_mode": "object-e2ee",
"plaintext_size": "1048576"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
14.4 attachment.commit_object Successful Response Example
{
"jsonrpc": "2.0",
"id": "req-70002",
"result": {
"committed": true,
"attachment_id": "att-001",
"object_uri": "https://objects.example.com/objects/obj-abc",
"committed_at": "2026-03-29T14:03:05Z"
}
}2
3
4
5
6
7
8
9
10
14.5 attachment.abort_object request example
{
"jsonrpc": "2.0",
"id": "req-70003",
"method": "attachment.abort_object",
"params": {
"meta": {
"anp_version": "1.0",
"profile": "anp.attachment.v1",
"security_profile": "transport-protected",
"sender_did": "did:example:agent-a",
"target": {
"kind": "service",
"did": "did:example:domain-a"
},
"operation_id": "op-70003",
"created_at": "2026-03-29T14:04:00Z"
},
"body": {
"attachment_id": "att-abort-001",
"slot_id": "slot-abort-001"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
14.6 attachment.abort_object Successful Response Example
{
"jsonrpc": "2.0",
"id": "req-70003",
"result": {
"aborted": true,
"attachment_id": "att-abort-001",
"aborted_at": "2026-03-29T14:04:01Z"
}
}2
3
4
5
6
7
8
9
14.7 attachment.get_download_ticket request example (direct messaging/E2EE)
{
"jsonrpc": "2.0",
"id": "req-70004",
"method": "attachment.get_download_ticket",
"params": {
"meta": {
"anp_version": "1.0",
"profile": "anp.attachment.v1",
"security_profile": "transport-protected",
"sender_did": "did:example:agent-b",
"target": {
"kind": "service",
"did": "did:example:domain-a"
},
"operation_id": "op-70004",
"created_at": "2026-03-29T14:10:00Z"
},
"body": {
"attachment_id": "att-001",
"object_uri": "https://objects.example.com/objects/obj-abc",
"requester_did": "did:example:agent-b",
"message_security_profile": "direct-e2ee",
"message_id": "msg-70008",
"message_target_did": "did:example:agent-b",
"one_time": true
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
14.8 attachment.get_download_ticket Successful Response Example
{
"jsonrpc": "2.0",
"id": "req-70004",
"result": {
"download_ticket_b64u": "BASE64URL_TICKET",
"expires_at": "2026-03-29T14:15:00Z",
"ticket_binding": {
"attachment_id": "att-001",
"object_uri": "https://objects.example.com/objects/obj-abc",
"requester_did": "did:example:agent-b",
"message_id": "msg-70008",
"message_security_profile": "direct-e2ee",
"message_target_did": "did:example:agent-b"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
14.9 HTTPS upload example (data plane)
PUT /upload/slot-70001 HTTP/1.1
Host: objects.example.com
Content-Type: application/octet-stream
Content-Length: 1048592
<encrypted object bytes>2
3
4
5
6
14.10 direct.send Example of carrying non-encrypted attachment list (Direct Base)
{
"jsonrpc": "2.0",
"id": "req-70005",
"method": "direct.send",
"params": {
"meta": {
"profile": "anp.direct.base.v1",
"security_profile": "transport-protected",
"sender_did": "did:example:agent-a",
"target": {
"kind": "agent",
"did": "did:example:agent-b"
},
"operation_id": "msg-70005",
"message_id": "msg-70005",
"created_at": "2026-03-29T14:20:00Z",
"content_type": "application/anp-attachment-manifest+json"
},
"auth": {
"scheme": "anp-rfc9421-origin-proof-v1",
"origin_proof": {
"contentDigest": "sha-256=:BASE64_SHA256_OF_SIGNED_DIRECT_PAYLOAD:",
"signatureInput": "sig1=(\"@method\" \"@target-uri\" \"content-digest\");created=1774794000;expires=1774794060;nonce=\"n-70005\";keyid=\"did:example:agent-a#key-1\"",
"signature": "sig1=:BASE64_SIGNATURE:"
}
},
"body": {
"payload": {
"attachments": [
{
"attachment_id": "att-plain-001",
"filename": "report.pdf",
"mime_type": "application/pdf",
"size": "1048576",
"digest": {
"alg": "sha-256",
"value_b64u": "BASE64URL_SHA256_OF_PLAINTEXT"
},
"access_info": {
"object_uri": "https://objects.example.com/objects/obj-plain-001"
},
"encryption_info": {
"mode": "none"
}
}
],
"caption": "Please check the attachment",
"primary_attachment_id": "att-plain-001"
}
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
14.11 group.send Example of carrying non-encrypted attachment list (Group Base)
{
"jsonrpc": "2.0",
"id": "req-70006",
"method": "group.send",
"params": {
"meta": {
"profile": "anp.group.base.v1",
"security_profile": "transport-protected",
"sender_did": "did:example:agent-a",
"target": {
"kind": "group",
"did": "did:example:group-123"
},
"operation_id": "msg-70006",
"message_id": "msg-70006",
"created_at": "2026-03-29T14:25:00Z",
"content_type": "application/anp-attachment-manifest+json"
},
"auth": {
"scheme": "anp-rfc9421-origin-proof-v1",
"origin_proof": {
"contentDigest": "sha-256=:BASE64_SHA256_OF_SIGNED_GROUP_PAYLOAD:",
"signatureInput": "sig1=(\"@method\" \"@target-uri\" \"content-digest\");created=1774794300;expires=1774794360;nonce=\"n-70006\";keyid=\"did:example:agent-a#key-1\"",
"signature": "sig1=:BASE64_SIGNATURE:"
}
},
"body": {
"payload": {
"attachments": [
{
"attachment_id": "att-group-plain-001",
"filename": "team-plan.pdf",
"mime_type": "application/pdf",
"size": "204800",
"digest": {
"alg": "sha-256",
"value_b64u": "BASE64URL_SHA256_OF_PLAINTEXT"
},
"access_info": {
"object_uri": "https://objects.example.com/objects/obj-group-plain-001"
},
"encryption_info": {
"mode": "none"
}
}
],
"caption": "Group file",
"primary_attachment_id": "att-group-plain-001"
}
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
14.12 direct.send outer ciphertext example (Direct E2EE)
{
"jsonrpc": "2.0",
"id": "req-70008",
"method": "direct.send",
"params": {
"meta": {
"anp_version": "1.0",
"profile": "anp.direct.e2ee.v1",
"security_profile": "direct-e2ee",
"sender_did": "did:example:agent-a",
"target": {
"kind": "agent",
"did": "did:example:agent-b"
},
"operation_id": "msg-70008",
"message_id": "msg-70008",
"created_at": "2026-03-29T14:30:00Z",
"content_type": "application/anp-direct-cipher+json"
},
"body": {
"session_id": "BASE64URL_16_BYTES",
"ratchet_header": {
"dh_pub_b64u": "BASE64URL_DH_PUB",
"pn": "12",
"n": "3"
},
"ciphertext_b64u": "BASE64URL_DIRECT_CIPHERTEXT"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
14.13 Direct E2EE inner Application Plaintext example (attachment object is encrypted)
{
"application_content_type": "application/anp-attachment-manifest+json",
"payload": {
"attachments": [
{
"attachment_id": "att-001",
"filename": "report.pdf",
"mime_type": "application/pdf",
"size": "1048592",
"digest": {
"alg": "sha-256",
"value_b64u": "BASE64URL_SHA256_OF_CIPHERTEXT"
},
"access_info": {
"object_uri": "https://objects.example.com/objects/obj-abc"
},
"encryption_info": {
"mode": "object-e2ee",
"object_cipher": "chacha20-poly1305",
"object_key_b64u": "BASE64URL_32_BYTES_OBJECT_KEY",
"nonce_b64u": "BASE64URL_12_BYTES_NONCE",
"plaintext_size": "1048576"
}
}
],
"caption": "Please check the attachment",
"primary_attachment_id": "att-001"
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
14.14 group.send outer ciphertext example (Group E2EE)
{
"jsonrpc": "2.0",
"id": "req-70009",
"method": "group.send",
"params": {
"meta": {
"anp_version": "1.0",
"profile": "anp.group.e2ee.v1",
"security_profile": "group-e2ee",
"sender_did": "did:example:agent-a",
"target": {
"kind": "group",
"did": "did:example:group-123"
},
"operation_id": "msg-70009",
"message_id": "msg-70009",
"created_at": "2026-03-29T14:35:00Z",
"content_type": "application/anp-group-cipher+json"
},
"auth": {
"scheme": "anp-rfc9421-origin-proof-v1",
"origin_proof": {
"contentDigest": "sha-256=:BASE64_SHA256_OF_SIGNED_GROUP_PAYLOAD:",
"signatureInput": "sig1=(\"@method\" \"@target-uri\" \"content-digest\");created=1774794900;expires=1774794960;nonce=\"n-70009\";keyid=\"did:example:agent-a#key-1\"",
"signature": "sig1=:BASE64_SIGNATURE:"
}
},
"body": {
"crypto_group_id_b64u": "BASE64URL_GROUPID",
"epoch": "8",
"private_message_b64u": "BASE64URL_PRIVATE_MESSAGE",
"group_state_ref": {
"group_did": "did:example:group-123",
"group_state_version": "43",
"policy_hash": "sha-256:BASE64URL_POLICY_HASH"
},
"epoch_authenticator": "BASE64URL_EPOCH_AUTH"
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
14.15 Group E2EE inner Group Application Plaintext example (attachment object is encrypted)
{
"application_content_type": "application/anp-attachment-manifest+json",
"payload": {
"attachments": [
{
"attachment_id": "att-group-e2ee-001",
"filename": "design.png",
"mime_type": "image/png",
"size": "524304",
"digest": {
"alg": "sha-256",
"value_b64u": "BASE64URL_SHA256_OF_CIPHERTEXT"
},
"access_info": {
"object_uri": "https://objects.example.com/objects/obj-group-e2ee-001"
},
"encryption_info": {
"mode": "object-e2ee",
"object_cipher": "chacha20-poly1305",
"object_key_b64u": "BASE64URL_32_BYTES_OBJECT_KEY",
"nonce_b64u": "BASE64URL_12_BYTES_NONCE",
"plaintext_size": "524288"
},
"media_info": {
"width": "1920",
"height": "1080"
}
}
],
"caption": "Design draft",
"primary_attachment_id": "att-group-e2ee-001"
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
14.16 HTTPS download example (data plane)
GET /objects/obj-abc HTTP/1.1
Host: objects.example.com
Authorization: Bearer BASE64URL_TICKET2
3
Appendix A (Informative): Implementation Recommendations
- Default is
operation_id = message_id - By default, each attachment runs
attachment.get_download_ticket - Each object uses a new random object key by default
- Treat thumbnails as independent attachments by default instead of inventing new sub-objects
- If you really need more complex object capabilities, they should be defined separately in future versions instead of re-forking the v1 mainline path.