Inbound Activity Handling
k-ap handles the following inbound activities out of the box. All arrive via POST /inbox or POST /users/{id}/inbox, after HTTP signature verification.
Handled activities
| Activity | What k-ap does |
|---|---|
Follow |
Saves follower with Pending status; checks blocklist first |
Accept |
Updates outbound following status to Accepted |
Reject |
Updates outbound following status to Rejected |
Undo(Follow) |
Removes the follower record; calls on_actor_removed |
Undo(Like) |
Calls on_unlike |
Undo(Announce) |
Removes announce record from ActorRepository; calls on_announce_removed |
Undo(Add) |
No-op |
Undo(Block) |
No-op |
Create |
Calls on_create with the wrapped object JSON; dispatches mentions |
Update |
Calls on_update with the wrapped object JSON; dispatches mentions |
Delete |
Calls on_delete with the object URL; if object is an actor, calls on_actor_removed |
Announce |
Records in ActorRepository; calls on_announce_received (local object) or on_announce_of_remote (remote object) |
Like |
Calls on_like |
Add |
Calls on_create with the object JSON |
Block |
No-op (you may surface this in your UI separately) |
Move |
Verifies alsoKnownAs, migrates follower records, re-follows in background |
Deduplication
Before any handler is called, k-ap calls ActivityRepository::is_activity_processed with the activity's id. If already processed, the handler is skipped and the inbox returns 200. After successful processing, mark_activity_processed is called.
This makes inbound delivery safe to retry — the sender can retry on network failure without causing duplicate effects.
Mention dispatch
For Create and Update activities, k-ap extracts the tag array from the wrapped object and looks for {"type":"Mention","href":"<local-actor-url>"} entries. For each mention that resolves to a local user, ApObjectHandler::on_mention is called with the object's AP ID, the local user's UUID, and the mentioning actor's URL.
on_mention failures are logged and swallowed — a broken notification must not cause the activity to be rejected.
Move (account migration)
When a Move activity is received:
- k-ap fetches the target actor's JSON
- Verifies that the target's
alsoKnownAsarray contains the source actor's URL (all aliases checked) - Calls
FollowRepository::migrate_follower_actorto update follower records - Spawns a background task (non-blocking) to re-follow the new actor on behalf of local users who followed the old one
Step 4 runs in the background so the inbox handler returns immediately.
Error responses
4xx responses sent to remote servers use generic messages. Internal error details are only logged via tracing, never sent to clients. This prevents information leakage to potentially adversarial servers.
Body limit
Both inbox routes enforce a 1 MB body limit via axum's DefaultBodyLimit. Oversized payloads are rejected with 413 before any processing.
Actor types accepted
k-ap accepts activities from Person, Service, Application, Organization, and Group actors.