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:...
ordid:web:...
How AIP Authentication Works
- Enter your handle: Type your ATProto handle (like
@alice.bsky.social
) - Authorize with your PDS: Your Personal Data Server (PDS) verifies your identity
- Grant permissions: Approve access to create and manage job listings in the
place.atwork.listing
collection - 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 identityprofile
- Access your public profile informationemail
- Retrieve your email addressatproto
- General ATProtocol accessaccount:email
- Read account emailrepo: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
- Parameters:
-
place.atwork.getListing
- Fetch a specific job listing by URI- Parameters:
uri
(AT-URI) - Returns: Single job listing with full record
- Parameters:
-
place.atwork.searchListings
- Full-text search across listings- Parameters:
q
(query),tag
,cursor
,limit
- Returns: Search results with relevance scoring
- Parameters:
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
andplace.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:
-
Collection Filter: Only events from
place.atwork.listing
andplace.atproto.profile
collections proceed- All other ATProto collections are ignored
- Reduces processing load by 99%+
-
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
-
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 afternotBefore
- URL validation:
applyLink
must be HTTPS - Facet validation: Byte indices, DIDs, and URLs must be valid
- Must conform to
-
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)
- Only
-
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
- Mentions: DIDs extracted and validated (must start with
-
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
- How to Log In - Step-by-step authentication guide
- XRPC API Documentation - Complete API reference with examples
- Creating Job Listings - Post your first job
- ATProtocol Documentation - Official protocol docs
- Bluesky Developer Docs - Learn about the ATProto ecosystem