FEP-0ea0: Payment Links


This is a discussion thread for the proposed FEP-0ea0: Payment Links. Please use this thread to discuss the proposed FEP and any potential problems or improvements that can be addressed.


This FEP describes a way to attach payment information to ActivityPub actors and objects. That information might be a link to donation page, a link for buying an artwork, or anything else that can be represented with a URI.

cc: @silverpill

1 Like

type (REQUIRED): the type MUST be Link.

this should not be a requirement. there may be some other type used.

name (REQUIRED): the name property MUST contain a human-readable description of the payment link.

i’d drop this to a SHOULD

href (REQUIRED): the href property MUST contain a payment URI. This can be a URL of a website, or any other kind of URI, such as payto URI.

this is fine

rel (REQUIRED): the rel property MUST contain the string payment or an array with the first element being that string. The payment relation type is defined in Link Relations Registry.

why the first element? arrays in JSON-LD are unordered sets, so it is enough to test for inclusion, a la if 'payment' in rel

Payment links MUST be added to attachment array of an actor or an object.

this is fine


I thought that requiring a specific type would be better for interoperability. Without this requirement, people may start creating app-specific subtypes.

(By the way, I have the same concern about FEP-e232, which allows subtypes. But FEP-e232 link could point to an arbitrary object, therefore the scope of the proposal is much wider and subtypes are easier to justify there. This FEP, on the other hand, describes only a specific kind of link.)

Why do you think this requirement should be relaxed? I decided to use a MUST because payment link containing the name property can be presented to a user as key-value (<name>: <href>) and displayed along with other profile metadata.

I agree, there’s no good reason to specify element’s position. I’ll re-phrase this sentence.

on type

checking types at all is bad for interoperability. full stop. all you need to know something is a Link is that it has an href.

if people create subtypes, then activitystreams specifies they MUST also use a core type. examples given in as2-core include "type": ["Place", "gr:Location"] and "type": ["Person", "vcard:Individual"] which pull from goodrelations and from vcard. there is also "type": ["Like", "http://schema.org/LikeAction"] which uses a full iri.

When an implementation uses an extension type that overlaps with a core vocabulary type, the implementation MUST also specify the core vocabulary type. For instance, some vocabularies (e.g. The Good Relations Vocabulary) define their own types for describing locations. An implementation that wishes, for example, to use a http://purl.org/goodrelations/v1#Location as an object type MUST also identify the object as being a Place as illustrated in the following

When an implementation uses an extension type that overlaps with a core vocabulary type, the implementation MUST also specify the core vocabulary type. For instance, some vocabularies (e.g. VCard) define their own types for describing people. An implementation that wishes, for example, to use a vcard:Individual as an Actor MUST also identify that Actor as a Person as illustrated in the previous example.

^(activitypub i think relaxes this requirement, in that anything can be used as an actor; it’s actually weird that the phrasing is structured such that it reads “MUST be a Person” instead of using something non-normative since this is just an example, and the normative requirement just two sentences earlier already covers the intention.)

When an implementation uses an extension type that overlaps with a core vocabulary type, the implementation MUST also specify the core vocabulary type. For instance, some vocabularies (e.g. Schema.org) define their own types for describing actions. An implementation that wishes, for example, to use http://schema.org/LikeAction as an Activity MUST also identify that Object as being a Like as illustrated in the following

on name

you could just as reasonably show a list of href-values identified as payment links in a “payment” section

as2-core 4.1.1:

The name and summary MAY be absent, MAY lack explicit values in the end user’s current language, and MAY be longer than appropriate for use as a text representation of the Object in the current language context. Consumer implementations SHOULD have fallback strategies for text representation of Objects in these cases.

consider the perfectly-usable minimal example below:

href: https://donate.stripe.com/4gwcPCaMpcQ19RC4gg
rel: payment

this technically contains all you need. filter the attachment array for anything that has a rel and where rel includes payment. example python list comprehension:

payment_links = [item for item in attachment if 'rel' in item and 'payment' in item['rel']]

a name is nice to have, and you can recommend it as a SHOULD, but making it a MUST requirement is going to lead to fragility.

1 Like

Why is it bad? In this particular case I can check for href attribute, but often it is not possible to determine the way object should be processed just by looking at its attributes.

A hypothetical “payment” section? Or there’s an existing Fediverse software that already has it?

I assume not everyone will want to have such section. Some may prefer to process payment links similarly to PropertyValue or Note attachments and display them as profile metadata keypairs.

The FEP may actually recommend using rel value as a fallback. Anyway, I agree that SHOULD makes more sense here.

type: Link provides you no additional information that the mere presence of href (or even rel!) doesn’t already provide. those are already properties that can only present on Link or its subclasses. compare to e232 where the primary mechanism there is mediaType: application/ld+json; profile=... to indicate that you can fetch with activitypub Accept header. similarly in 0ea0 the rel: [payment] is doing all the semantic work, indicating that this link is a payment link for the current resource.

this is what i meant. the Link in attachment already works similarly to profile metadata. but it doesn’t need to be a key-value pair; it may simply be a list of values.

I’ll try to illustrate my point with pseudocode. The parsing of attachment array may look like this:

for attachment in actor.attachment:
    if attachment.type == "IdentityProof":
    elif attachment.type == "PropertyValue":
    elif attachment.type == "Link":
        if attachment.rel == "payment":

Maybe this is not a good idea (?), but I think many servers are doing something similar. Is there a good reason to complicate things by allowing subtypes?

I’d like to add this paragraph to proposal:

## Payment links as actor metadata

(This section is non-normative.)

Implementers may treat payment links attached to actor object in the same way as actor metadata fields. In that case, `name` translates into field label and `href` translates into field value.

this is giving me the idea to update FEP-fb2a Actor metadata and provide a more general description of using attachment on actors. but in any case the pseudocode would probably be more like so:

for item in actor.attachment:
   if 'payment' in item.rel:
   elif 'IdentityProof' in item.type:

although i don’t think there’s much difference in parsing – all of these can be considered as various metadata values or key-values.

anyway. the idea i had for fb2a is to explicitly describe attaching Notes and Links, while leaving the door open for other attachments. if a Note is attached, use content as value. if a Link is attached, use href as value. if name is present, use it as a key. this means that 0ea0 could build off of fb2a, since they use largely similar mechanism (attachment)

taking the above in synthesis, you could imagine multiple checks like so (in python):

def parse_metadata(item):

  value = item.get('content') or item.get('href')  # one of these should be present
  key = item.get('name')  # None if not present

  is_link = 'href' in item
  is_payment = 'payment' in item.get('rel', [])
  is_identity = 'IdentityProof' in item.get('type', [])

  # ...

i’m not actually familiar with what an IdentityProof’s salient properties are, off the top of my head, so that one may require some special handling not expressed above.

but the point i’m trying to make is that the above is actually less complicated, and less fragile to boot. types are nothing more than a hint. it’s bad practice to check them strictly when you don’t need to.

Proposal has been updated: #91 - FEP-0ea0: Update proposal - fep - Codeberg.org

I decided to keep type: Link requirement. “Duck typing” approach could make sense in certain situations, but when working with AS objects I prefer to match by type first (because this results in cleaner code when the number of variants is large); other implementations I’m familiar with seem to do that as well. If there’s a use case for payment link where a different type is really necessary, I’ll re-consider this.

Mastodon’s legacy identity proofs had type, name, signatureAlgorithm and signatureValue properties. FEP-c390 identity proofs have type, subject, alsoKnownAs and proof properties.

then in this case i would indeed recommend checking type == DataIntegrityProof, as the proof property could serve virtually any purpose, and so the type carries semantic information here.

well, i imagine you could have types such as Paypal, Stripe, Cashapp, Venmo, and so on. also, i disagree that type-matching results in cleaner code. i think it actually results in longer and more complex code, and serves no functional purpose, because you don’t actually care about the type in most cases. the only time type matters is if it carries semantic information, like how OrderedCollection is specifically reverse-chronological and an ordinary Collection may still have orderedItems in some other ordering.

in any case, i suppose it doesn’t actually matter that much. i imagine best practice would be to declare Link anyway, regardless of whether it was a requirement or not. i just think it doesn’t have to be a MUST when a SHOULD will do. although you could argue that by AS2-Core, any extension type MUST also specify the core type, so the Link will end up in there anyway.

1 Like

PeerTube videos can have support property: ActivityPub | PeerTube documentation.
It’s not a link though, just a text field.

I agree with this, leaving out types is a perfect way to get more bugs. Not worth it and it wont help for compatibility with well-behaving software.

1 Like

if your software requires type when it won’t get used, it is not well-behaving. of course you probably SHOULD NOT leave out type, but it’s not a MUST to include it.

as2-core 4.1:

All properties are optional (including the id and type).

activitypub 3.1 adds back the requirement for id for anything that needs to be referenced (persistent, non-transient objects and activities):

All Objects in [ActivityStreams] should have unique global identifiers. ActivityPub extends this requirement; all objects distributed by the ActivityPub protocol MUST have unique global identifiers, unless they are intentionally transient (short lived activities that are not intended to be able to be looked up, such as some kinds of chat messages or game notifications). […] Identifiers MUST be provided for activities posted in server to server communication, unless the activity is intentionally transient.

the only usage of type that is required and defined within activitypub is the Activity subtypes Create Add Remove Update Delete Accept Reject Follow Like Announce Undo and their side-effects. these types matter because they have semantics. but many other types have no real semantics. enforcing a type-check only leads to fragility.

i think this is unrelated, as the semantics of support in this case seems to just be “A text field describing how you can support the uploader of the video.” and there doesn’t seem to be any intent to have it be machine-parseable. honestly it could just as easily be part of the summary or content.

1 Like

Yes, it’s unrelated but I may add this to “Prior art” section of the proposal.

1 Like

I think requiring it may be a valid point, for compatibility reasons. If it isn’t set, software that doesn’t support unnamed links won’t show the link at all. We want it to show these links more often than not (right?), so making it work (better) with things that currently use profile metadata makes sense.

The main concern I have with this one is also compatibility. Do the major implementations that have profile metadata understand the Link type for it? Looking briefly at one of Mastodon’s Actor objects, it uses PropertyValue and not Link, even for links.

1 Like

name is RECOMMENDED and “Payment links as actor metadata” section explains how payment link can be translated into profile metadata field, so I think implementers will have to make conscious decision to not include this attribute. There might be cases where name doesn’t make sense, especially if payment link is attached to an object (not actor).

I believe they won’t understand the Link type. FEP-0ea0 implementers may include PropertyValue representation of payment link along with Link attachment to maximize compatibility.

1 Like

FEP has been updated: #200 - FEP-0ea0: Update proposal - fep - Codeberg.org

The new “History” section mentions the support property (used by PeerTube) and FEP-8c3f: Web Monetization.