{"lexicon":1,"id":"money.atmosphere.membership.getAccess","defs":{"accessTier":{"type":"object","required":["tier"],"properties":{"tier":{"type":"ref","ref":"com.atproto.repo.strongRef","description":"Matched money.atmosphere.membership.tier record."},"product":{"type":"ref","ref":"com.atproto.repo.strongRef","description":"Linked membership product, when known."},"price":{"type":"ref","ref":"com.atproto.repo.strongRef","description":"Linked recurring price, when known."},"rank":{"type":"integer","minimum":0,"description":"Resolved tier rank, when known."},"currentPeriodEndsAt":{"type":"string","format":"datetime","description":"When the current paid period ends, when available to the caller."}}},"main":{"type":"procedure","description":"Cross-app membership access check. Authority is double-keyed: (1) memberAssertionJwt is a single-use, short-TTL com.atproto.server.getServiceAuth token issued by the member (lxm money.atmosphere.membership.assertMember, iss = memberDid) proving the member authorized a check right now; and (2) the calling app must itself hold creator consent for creatorDid (an approved recipient approval covering subscription payments, or be the creator). ATM answers from the union of attested subscription truth and registered grants. The personalized response is returned with Cache-Control private, no-store and must never be cached. Residual risk: because a standard getServiceAuth token binds aud+lxm but NOT the request body, an app approved by multiple creators that is handed a member token could substitute a different creatorDid on that single (single-use) check; a fully request-bound member artifact (member OAuth-to-ATM) is the future hardening. Gated by ATM_MEMBERSHIP_ACCESS_QUERY_ENABLED; when disabled the route returns FeatureUnavailable.","input":{"encoding":"application/json","schema":{"type":"object","required":["memberDid","creatorDid","memberAssertionJwt"],"properties":{"memberDid":{"type":"string","format":"did","description":"Member DID to check. Must match memberAssertionJwt issuer."},"creatorDid":{"type":"string","format":"did","description":"Creator or project DID whose membership is being checked."},"memberAssertionJwt":{"type":"string","maxLength":8192,"description":"Single-use, short-TTL member presence token: a com.atproto.server.getServiceAuth JWT with iss = memberDid, aud = the broker DID's #AttestedNetwork service, lxm = money.atmosphere.membership.assertMember. Verified and discarded; jti is replay-protected so a token satisfies exactly one check."},"environment":{"type":"string","knownValues":["test","live"],"maxLength":8,"description":"ATM app environment. Defaults to live."},"program":{"type":"string","format":"at-uri","description":"Optional money.atmosphere.membership.program AT-URI to check."},"tier":{"type":"string","format":"at-uri","description":"Optional money.atmosphere.membership.tier AT-URI to check. When absent, any active tier in the program may satisfy access."},"tierOrAbove":{"type":"boolean","default":false,"description":"When true, an exact tier match or a different tier with rank strictly greater than the requested tier rank satisfies access. Equal-ranked tiers are peers and do not satisfy one another. Defaults to exact tier/program access."}}}},"output":{"encoding":"application/json","schema":{"type":"object","required":["access","memberDid","creatorDid","checkedAt"],"properties":{"access":{"type":"boolean","description":"True when ATM found an active membership satisfying the request."},"memberDid":{"type":"string","format":"did"},"creatorDid":{"type":"string","format":"did"},"program":{"type":"ref","ref":"com.atproto.repo.strongRef","description":"Matched membership program, when resolved."},"tiers":{"type":"array","maxLength":16,"items":{"type":"ref","ref":"#accessTier"},"description":"Matched active tiers the caller is authorized to know about. Empty when access is false or only program-level access is known."},"checkedAt":{"type":"string","format":"datetime","description":"When ATM evaluated access."}}}},"errors":[{"name":"FeatureUnavailable","description":"The cross-app membership access query is disabled on this deployment (ATM_MEMBERSHIP_ACCESS_QUERY_ENABLED is off)."},{"name":"InvalidActor","description":"Member or creator DID is malformed."},{"name":"AppNotRegistered","description":"Caller is not a registered ATM app."},{"name":"NotAuthorized","description":"memberAssertionJwt is missing, invalid, or not issued by memberDid."}]}}}