ATProtocol Integration

Understanding how at://work leverages the ATProtocol ecosystem

What is ATProtocol?

The Authenticated Transfer Protocol (ATProtocol) is an open, decentralized social networking protocol that gives users ownership of their identity and data. Unlike traditional platforms, ATProtocol enables interoperability between different applications and services while keeping users in control.

at://work is built natively on ATProtocol, which means job listings are stored as ATProto records that you own and control through your ATProto identity.

🔐 ATProtocol Authentication with AIP

Universal Identity System

at://work uses ATProto Identity Provider (AIP) for authentication, which means any valid ATProtocol identity can log in. Your identity is portable across the entire ATProtocol network—no need to create yet another account!

Supported Identities

You can log in with any ATProto identity, including:

  • Bluesky accounts: @ngerakines.me, @alice.bsky.social
  • Custom domains: Any handle verified through DNS
  • DID identifiers: did:plc:... or did:web:...

How AIP Authentication Works

  1. Enter your handle: Type your ATProto handle (like @alice.bsky.social)
  2. Authorize with your PDS: Your Personal Data Server (PDS) verifies your identity
  3. Grant permissions: Approve access to create and manage job listings in the place.atwork.listing collection
  4. Secure session: OAuth 2.0 with PKCE creates an encrypted, time-limited session

OAuth Scopes

When you log in, at://work requests these specific permissions:

  • openid - Verify your identity
  • profile - Access your public profile information
  • email - Retrieve your email address
  • atproto - General ATProtocol access
  • account:email - Read account email
  • repo:place.atwork.listing - Read and write job listings in your repository

Important: at://work never stores your password. All authentication happens through your PDS.

Need help logging in? Check out our authentication guide for detailed instructions.

📡 AppView & XRPC Methods

What is an AppView?

In ATProtocol architecture, an AppView is a service that provides a specific view or interface to ATProto data. at://work is an AppView specialized for job listings—we index, aggregate, and present job opportunities from across the ATProtocol network.

The Lexicon System

ATProtocol uses lexicons to define data schemas. Think of lexicons as contracts that specify what fields a record type must have and how they should be structured. at://work defines and uses two lexicons: place.atwork.listing for job listings and place.atproto.profile for user profiles.

Job Listing Lexicon: place.atwork.listing

Key components of the job listing schema:

Field Type Description
title string Job title (1-200 characters)
description string Job description with rich text support (1-10,000 characters)
notBefore datetime When the listing becomes active
notAfter datetime When the listing expires
applyLink string? HTTPS URL for applications (optional)
facets array? Rich text annotations (mentions, links, hashtags)
locations array Geographic locations using H3 indices

Profile Lexicon: place.atproto.profile

User profiles are stored using a separate lexicon with a singleton pattern (one per user):

Field Type Description
displayName string? Preferred name or company name (1-200 graphemes, optional)
status string? Hiring status: place.atproto.profile#hiring or place.atproto.profile#forhire (optional)
description string? About the user or company (1-2,000 graphemes, optional)
facets array? Rich text annotations (mentions, links, hashtags) - max 6

Key lexicon features:

  • Singleton record: Uses literal:self as the key, ensuring each user has exactly one profile
  • All fields optional: Users can have minimal or comprehensive profiles
  • Status tokens: Two known values distinguish hiring managers (🟢) from job seekers (🔵)
  • Rich text support: Facets use the same app.bsky.richtext.facet format as Bluesky
  • Searchable: Profiles are indexed alongside jobs, making users discoverable

Learn more about profiles: Check out our User Profiles guide for step-by-step instructions on creating and managing your profile.

XRPC API Endpoints

XRPC (Cross-system Remote Procedure Call) is ATProtocol's RPC protocol. at://work exposes XRPC methods that any ATProto-compatible client can call:

Available Methods:

  • place.atwork.getListings - Query job listings with filters
    • Parameters: tag, identity, cursor, limit
    • Returns: Array of job listings with pagination
  • place.atwork.getListing - Fetch a specific job listing by URI
    • Parameters: uri (AT-URI)
    • Returns: Single job listing with full record
  • place.atwork.searchListings - Full-text search across listings
    • Parameters: q (query), tag, cursor, limit
    • Returns: Search results with relevance scoring

Example XRPC Call:

GET https://atwork.place/xrpc/place.atwork.getListings?tag=rust&limit=10

Response:
{
  "listings": [
    {
      "uri": "at://did:plc:abc123/place.atwork.listing/xyz789",
      "cid": "bafyreiabc...",
      "record": {
        "$type": "place.atwork.listing",
        "title": "Senior Rust Engineer",
        "description": "We're hiring! #rust #remote",
        "notBefore": "2025-01-15T00:00:00Z",
        "notAfter": "2025-02-15T00:00:00Z",
        ...
      }
    }
  ],
  "cursor": "next_page_token"
}

Want to integrate our API? See the complete XRPC API documentation with examples and schemas.

🌊 Firehose Consumption via Jetstream

The ATProtocol Firehose

The ATProtocol firehose is a real-time stream of all public activity across the network—every post, like, follow, and record creation flows through this stream. at://work taps into this firehose to automatically discover and index new job listings as they're created anywhere in the ATmosphere.

Jetstream: Simplified Firehose Consumption

We use Jetstream (wss://jetstream.atproto.tools), a service that simplifies firehose consumption by:

  • Filtering events by collection (we receive place.atwork.listing and place.atproto.profile events)
  • Providing clean JSON events instead of raw CAR files
  • Handling connection recovery and cursor management
  • Reducing bandwidth and processing overhead

Event Processing Pipeline

When a job listing or profile event arrives through Jetstream, here's what happens:

  1. Collection Filter: Only events from place.atwork.listing and place.atproto.profile collections proceed
    • All other ATProto collections are ignored
    • Reduces processing load by 99%+
  2. Denylist Check: Verify the creator's DID isn't on our denylist
    • Denylisted accounts are blocked from appearing on the platform
    • Helps maintain content quality and safety
  3. Record Validation: Parse and validate the job listing
    • Must conform to place.atwork.listing schema
    • Field length limits enforced (title ≤200, description ≤10,000 chars)
    • Date validation: notAfter must be after notBefore
    • URL validation: applyLink must be HTTPS
    • Facet validation: Byte indices, DIDs, and URLs must be valid
  4. Location Processing: Extract and validate geographic locations
    • Only community.lexicon.location#h3 type supported
    • Maximum of 3 inline H3 locations per listing
    • H3 indices validated for proper format
    • Location references (#ref) are ignored (not inline)
  5. Facet Extraction: Process rich text annotations
    • Mentions: DIDs extracted and validated (must start with did:)
    • Links: URLs extracted (must be HTTP/HTTPS)
    • Tags: Hashtags normalized to lowercase for case-insensitive search
  6. Storage & Indexing: Persist and make searchable
    • Stored in PostgreSQL with full record JSON
    • Indexed in OpenSearch for full-text search
    • H3 locations converted to geo_points for map visualization
    • Tags and facets indexed for filtering and aggregation

Supported Operations

Operation Action Description
create Add listing New job listing is indexed and made searchable
update Update listing Existing listing is re-indexed with new data
delete Remove listing Listing is deleted from storage and search index

Location Constraints

Geographic locations in job listings have specific requirements:

Supported Location Type:

  • H3 Locations: community.lexicon.location#h3
    • Uses H3 hexagonal hierarchical geospatial indexing
    • Precision levels typically range from resolution 4-7 (city to neighborhood)
    • Each location includes an H3 cell ID and optional name

Location Limits:

  • Maximum 3 inline locations per job listing
  • Only direct H3 locations are indexed (not references)
  • Invalid H3 indices are silently skipped during indexing
  • Locations are converted to latitude/longitude coordinates for map display

Example Location Object:

{
  "$type": "community.lexicon.location#h3",
  "h3": "8c2a1072b1b97ff",
  "name": "San Francisco, CA"
}

What Gets Rejected?

Records are not processed if they:

  • Belong to a collection other than place.atwork.listing
  • Come from a denylisted DID
  • Fail schema validation (missing required fields, invalid types)
  • Have invalid date ranges (notAfter ≤ notBefore)
  • Contain malformed facets (invalid byte indices, bad DIDs/URLs)
  • Include non-HTTPS apply links
  • Exceed character limits (title >200, description >10,000)

🔍 Real-Time Processing

Job listings appear on at://work within seconds of being created on any PDS. The Jetstream connection maintains a persistent WebSocket and automatically reconnects if interrupted, ensuring we never miss updates from the network.

🌐 Part of the ATmosphere

at://work is just one application in the growing ATmosphere—the ecosystem of apps, services, and tools built on ATProtocol. Key characteristics of being part of the ATmosphere:

Data Portability

  • Your job listings are stored in your repository on your PDS
  • You can export, migrate, or delete your data at any time
  • Other ATProto applications could build alternative views of job listings

Interoperability

  • Job listings can reference users from any ATProto service (not just Bluesky)
  • XRPC APIs allow third-party integrations and widgets
  • Standard lexicons enable cross-app data sharing

Decentralization

  • No single point of failure—your data lives on your PDS
  • Multiple AppViews could index the same job listings differently
  • Identity and authentication are handled by the protocol, not by us

Open Standards

  • Lexicons are published and openly documented
  • Anyone can build tools that read or write place.atwork.listing records
  • Protocol upgrades happen through open governance

🔗 Learn More