ATProtocol Record Proposal: Event Transfer Records

Overview

This proposal introduces the community.lexicon.calendar.transfer record type for the ATProtocol ecosystem. This record serves as a “sidecar” mechanism to indicate when a community.lexicon.calendar.event record has been transferred from one owner to another, enabling seamless event ownership transitions in decentralized calendar systems.

Problem Statement

In decentralized social networks, events are often created by community members on behalf of organizers who may not yet be present on the network. When the actual event organizer joins the platform, they need a way to claim ownership of their events while maintaining referential integrity and providing clear transfer provenance.

Current challenges include:

  • No standardized way to indicate event ownership transfers
  • Difficulty redirecting users from original to canonical event records
  • Lack of cryptographic verification for transfer authenticity
  • Potential confusion about which event record is authoritative

Proposed Solution

The community.lexicon.calendar.transfer record type provides a standardized mechanism for event ownership transfers. When an event is transferred, the original owner creates a transfer record using the same record key as the original event, containing:

  1. A strong reference to the new canonical event record
  2. Optional cryptographic signatures from the new owner accepting the transfer

Technical Specification

Record Type

community.lexicon.calendar.transfer

Schema Definition

{
  "lexicon": 1,
  "id": "community.lexicon.calendar.transfer",
  "defs": {
    "main": {
      "type": "record",
      "description": "A record indicating that a calendar event has been transferred to another owner",
      "key": "tid",
      "record": {
        "type": "object",
        "required": ["subject"],
        "properties": {
          "subject": {
            "type": "ref",
            "ref": "com.atproto.repo.strongRef",
            "description": "Strong reference to the new canonical event record"
          },
          "signatures": {
            "type": "array",
            "description": "Optional attestations from the new owner accepting the transfer",
            "items": {
              "type": "ref",
              "ref": "#transferAcceptance"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "datetime",
            "description": "When the transfer record was created"
          }
        }
      }
    },
    "transferAcceptance": {
      "type": "object",
      "description": "Cryptographic attestation of transfer acceptance",
      "required": ["issuer", "issuedAt", "signature"],
      "properties": {
        "issuer": {
          "type": "string",
          "format": "did",
          "description": "DID of the new event owner"
        },
        "issuedAt": {
          "type": "string",
          "format": "datetime",
          "description": "When the acceptance was signed"
        },
        "signature": {
          "type": "string",
          "description": "Cryptographic signature proving acceptance"
        }
      }
    }
  }
}

Example Record

{
    "$type": "community.lexicon.calendar.transfer",
    "subject": {
        "$type": "com.atproto.repo.strongRef",
        "uri": "at://did:plc:cbkjy5n7bk3ax2wplmtjofq2/community.lexicon.calendar.event/3lukj4a4ho72a",
        "cid": "bafyreiezhxevee3oa6coizlkyqzngqmkwrxnrsl7vvgx3omzb3ys4nlv2i"
    },
    "signatures": [
        {
            "$type": "community.lexicon.calendar.transferAcceptance",
            "issuer": "did:plc:cbkjy5n7bk3ax2wplmtjofq2",
            "issuedAt": "2025-07-25T16:39:00.000Z",
            "signature": "u56lN...e5KZg"
        }
    ],
    "createdAt": "2025-07-25T16:39:00.000Z"
}

Implementation Flow

Transfer Process

  1. Original Event Creation: Nick creates an event record with record key 3lukj4a4ho72a
  2. Event Duplication: Boris joins the network and creates his own event record with the same semantic content
  3. Transfer Record Creation: Nick creates a community.lexicon.calendar.transfer record using the same record key (3lukj4a4ho72a)
  4. Signature Generation: Boris signs an acceptance attestation to verify the transfer authenticity
  5. Record Publication: The transfer record is published to Nick’s PDS

Client Implementation

When displaying an event record, clients should:

  1. Check for a corresponding transfer record with the same record key
  2. If a transfer record exists, prioritize displaying the transferred event
  3. Show transfer provenance information to users
  4. Verify signatures when present to ensure transfer authenticity

Use Cases

Primary Use Case: Proxy Event Creation

  • Community member creates event for external organizer
  • Organizer joins network and wants to claim their event
  • Transfer mechanism provides clear ownership transition

Secondary Use Cases

  • Event organization handoffs within teams
  • Migrating events between different organizational accounts
  • Correcting incorrectly attributed events

Security Considerations

Signature Verification

  • Signatures should be verified against the new owner’s public key
  • Clients should clearly indicate unverified transfers
  • Multiple signatures can provide additional confidence

Record Key Collision

  • Transfer records use the same record key as original events
  • This creates a clear 1:1 relationship but requires careful handling
  • Clients must differentiate between event and transfer record types

Malicious Transfers

  • Anyone can create transfer records pointing to arbitrary events
  • Signature verification is crucial for authenticity
  • Clients should allow users to ignore suspicious transfers

Implementation Considerations

Client UX

  • Clear visual indicators for transferred events
  • Option to view both original and transferred events
  • Transfer history and provenance information

PDS Storage

  • Transfer records are stored separately from event records
  • Same record key but different record type
  • Standard ATProtocol record management applies

Indexing and Discovery

  • Transfer records should be indexed alongside event records
  • Search systems should consider transfer relationships
  • Feed algorithms should prioritize canonical event versions

Conclusion

The community.lexicon.calendar.transfer record type provides a robust, secure mechanism for event ownership transfers in decentralized calendar systems. By leveraging ATProtocol’s existing infrastructure and adding cryptographic verification, this proposal enables seamless event transitions while maintaining data integrity and user trust.

The sidecar approach ensures backward compatibility while providing clear upgrade paths for enhanced functionality. Implementation can begin immediately with basic transfer support, with additional features added incrementally based on community needs.

1 Like

I feel like the signature field would be better as a standalone object type, with structured fields of its own, in a defs.json file rather than localized here. I think the general idea of a “signature “ would be useful for many more types of records in the future (for example badges, or anything that wants to verify the authenticity of the sender) and formalizing it here might be good for standardization across community lexicons.

2 Likes

Yeah, I think I agree. Where I get a little tripped up is that signature records should have a general pattern for how signatures are created and also in such a way that uses referential and contextual data of the record itself. They should also be strongly typed.

What I really want is a “signatures” field to be an array of objects that inherit from a basic object. They should all have the “signature” and “issuedAt” fields, but could have additional fields specific to the meta-data of that particular signature.

A badge award signature is going to be different from a record-transfer signature which is going to be different than an RSVP-acceptance signature, but they should all have a common signing process so they can be verified the same way.

:thought_balloon: Design decision thread: Why I went with community.lexicon.calendar.transfer instead of a more generic com.atproto.repo.transfer type…

I initially considered making this completely generic - any record type could be transferred! But this creates a key problem: record keys would need to be globally unique within a repository to avoid ambiguity about which record is being transferred.

Without global uniqueness, you’d need to embed more metadata in the transfer record itself to identify the source record type. This adds complexity and makes the “sidecar” relationship less clean.

I also explored using composite record keys like calendar.event/3lukj4a4ho72a but that violates ATProtocol’s rule against paths in record keys.

The domain-specific approach keeps things simple: same record key, clear 1:1 relationship, easy for clients to discover and handle.

This comment might be a bit ignorant, as I am just starting to understand AtProto, and it’s nuances. So, bare with me.

I don’t have a good sense of how negotiation between the event produces work.

If Alice wants to transfer the event to Boris; how do their PDS coordinate? Does her PDS server contact Boris’ PDS server directly, maybe via an RPC call? What should this look like? What is the structure of this payload that Boris is expected to sign?

Something like?

   "subject": {
        "$type": "com.atproto.repo.strongRef",
        "uri": "at://did:plc:cbkjy5n7bk3ax2wplmtjofq2/community.lexicon.calendar.event/3lukj4a4ho72a",
        "cid": "bafyreiezhxevee3oa6coizlkyqzngqmkwrxnrsl7vvgx3omzb3ys4nlv2i"
    },

I’m assuming this should be encoding and signed using something like rfc8785 or some other Canonical JSON encoding?

What set of fields are used to sign the object? Is it the entirety of subject object or some subset?

What is the reasoning behind the signature field being optional? What is the client behavior for missing signature field? What does that mean?

Also, what happens if Alice, updates an event after it has been transferred?

As noted

Anyone can create transfer records pointing to arbitrary events

Shouldn’t transfer records only point to records owned by the owner of the transfer record. Any transfer record not adhering to this constraint be considered invalid? In other words shouldn’t the transfer record reside in the same PDS server as the event record?

What happens if Alice, transfers an event to multiple other entities?

No, there’s no coordination.

  1. Alice creates my-awesome-event
  2. Boris is the show runner and duplicates the Alice/my-awesome-event record with some tool as Boris/my-awesome-event
  3. Boris tells Alice “I’ve taken over this event”
  4. Alice creates a transfer record and tells Boris where it is
  5. Boris creates a signature for the transfer record
  6. Alice updates the Alice/my-awesome-event transfer record to contain the signature

Practically, this would work with some sort of intermediary application like https://smokesignal.events/.

I’m wondering about cases where you could have more than one owner of an event. Use case in mind: perhaps DJ Alice is performing at Venue Bob. You may want either parties to have authority to update the event as new details arise, rather than transferring the ownership, or off-site coordination. You also might want to enforce consensus among multiple parties to update certain events.

1 Like