Introduction
Super Duper Feeder is a service designed to subscribe to RSS/Atom feeds on your behalf. It utilizes WebSub/PubSubHubbub for real-time updates when available by subscribing to the feed's external hub, or falls back to periodic polling otherwise.
Feed updates received (either via WebSub push or polling) can be delivered directly to your own application via a configured webhook URL.
This documentation provides detailed information about the service's API endpoints, webhook usage, and callback verification process.
WebSub Concepts
WebSub (formerly PubSubHubbub) is a protocol that enables real-time notifications for content updates. It involves three main components:
- Publishers: Content creators who notify the hub when they update their content
- Hub: An intermediary server facilitating communication between publishers and subscribers. Publishers notify the hub of updates, and the hub pushes those updates to subscribers. **Super Duper Feeder acts as a subscriber to these external hubs.**
- Subscribers: Services or applications (like Super Duper Feeder, or the developer's webhook registered with it) that want to receive real-time updates about content changes from a hub.
The flow works as follows:
- A subscriber (like Super Duper Feeder) discovers the hub URL from a publisher's feed.
- The subscriber sends a subscription request to the external hub.
- The hub verifies the subscription request with the subscriber (using the `/callback/:id` endpoint of Super Duper Feeder).
- When the publisher updates content, they notify their designated hub.
- The hub fetches the updated content and sends it to all its verified subscribers (including Super Duper Feeder).
- Super Duper Feeder receives the update and forwards it to any developer-registered webhooks for that feed.
API Reference
Quick Navigation
Webhook Subscription Endpoint
POST /api/webhook
Use this endpoint to subscribe Super Duper Feeder to a feed URL (topic
). You can optionally
provide your own webhook URL (callback
) where you want feed updates delivered.
The service will attempt to discover an external WebSub hub for the specified feed and subscribe to it for real-time updates. If no external hub is found, the service will fall back to periodically polling the feed for new content.
Request Parameters
Parameter | Type | Required | Description |
---|---|---|---|
topic |
string | Yes | The URL of the feed to subscribe to. This can be an RSS, Atom, or JSON feed, or an HTML page with feed autodiscovery links. |
callback |
string | No | Your callback URL where updates will be forwarded. |
Callback Verification
Important: When you provide a callback URL, it must be verified before any updates are sent to it. This ensures that you actually own the callback URL and prevents abuse.
The verification process works as follows:
- You submit a webhook subscription with your callback URL
- The system generates a verification token and sends a GET request to your callback URL with the token
- Your callback endpoint must respond with the token in the response body
- Once verified, your callback will start receiving updates
The verification request will be sent to:
GET {your-callback-url}?mode=verify&token={verification-token}
Your callback endpoint should:
- Extract the token from the
token
query parameter - Respond with a 200 OK status code
- Return the token as plain text in the response body
Example callback handler for verification:
// Example using Express.js
app.get('/my-callback', (req, res) => {
// Check if this is a verification request
if (req.query.mode === 'verify' && req.query.token) {
// Return the token as plain text
res.type('text/plain').send(req.query.token);
} else {
// Handle other requests
res.status(400).send('Invalid request');
}
});
Verification tokens expire after 24 hours. If your callback is not verified within this time, you'll need to submit a new subscription request.
Response
Status Code: 202 Accepted
on success, 400 Bad Request
on
error,
500 Internal Server Error
on server error
Response Body (JSON):
{
"success": true|false,
"message": "Description of the result",
"usingExternalHub": true|false,
"subscriptionId": "uuid-of-subscription",
"callbackId": "uuid-of-callback", // Only if callback was provided
"pendingVerification": true|false, // Indicates if the callback needs verification
"verificationInstructions": "Instructions for verifying the callback" // Only if pendingVerification is true
}
Success Response Fields
Field | Type | Description |
---|---|---|
success |
boolean | Indicates if the subscription request was successful |
message |
string | A human-readable description of the result |
usingExternalHub |
boolean | Indicates if an external WebSub hub was found and used (true) or if the service fell back to polling (false). |
subscriptionId |
string | The UUID of the created subscription, useful for tracking |
callbackId |
string | The UUID of the created callback, only present if a callback URL was provided |
pendingVerification |
boolean | Indicates if the callback URL requires verification (true) or is already verified (false) |
verificationInstructions |
string | Instructions for verifying the callback URL, only present if pendingVerification is true |
Error Responses
Status Code | Error Message | Description |
---|---|---|
400 | Missing topic parameter | The required topic parameter was not provided |
400 | Failed to add feed for polling | The service could not add the feed for polling (when using fallback hub) |
500 | Internal server error: [error details] | An unexpected error occurred on the server |
Example Usage
// Using fetch API in JavaScript
async function subscribeToFeed(topicUrl, callbackUrl) {
const formData = new FormData();
formData.append('topic', topicUrl);
if (callbackUrl) {
formData.append('callback', callbackUrl);
}
const response = await fetch('https://superduperfeeder.deno.dev/api/webhook', {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.success) {
console.log(`Successfully subscribed to ${topicUrl}`);
console.log(`Using external hub: ${result.usingExternalHub}`);
console.log(`Subscription ID: ${result.subscriptionId}`);
if (result.callbackId) {
console.log(`Callback ID: ${result.callbackId}`);
}
} else {
console.error(`Failed to subscribe: ${result.message}`);
}
}
Notes
-
The service will automatically discover the WebSub hub for the feed by checking:
- HTTP Link headers with
rel="hub"
- Feed content for hub links
- HTML content for hub links or feed autodiscovery links
- HTTP Link headers with
- If no external WebSub hub is found, the service will poll the feed directly.
- If a callback URL is provided and verified, updates (from WebSub or polling) will be forwarded to that URL.
- WebSub subscriptions initiated by this service have a default lease time and will attempt automatic renewal with the external hub.
Webhook Verification Endpoint
GET /api/webhook/verify/:token
This endpoint is used to manually verify a callback URL. Normally, verification happens automatically when your callback responds to the verification request, but you can also use this endpoint to manually verify a callback if needed.
Path Parameters
Parameter | Type | Description |
---|---|---|
token |
string | The verification token sent to your callback URL |
Response
Status Code: 200 OK
on success, 400 Bad Request
on error
Response Body (JSON):
{
"success": true|false,
"message": "Description of the result"
}
Success Response
{
"success": true,
"message": "Callback verified successfully"
}
Error Responses
{
"success": false,
"message": "Invalid verification token"
}
{
"success": false,
"message": "Verification token has expired"
}
Notes
- Verification tokens expire after 24 hours
- This endpoint is primarily for manual verification or debugging
- In most cases, your callback should handle the verification request automatically
Internal Callback Endpoint
GET/POST /callback/:id
This endpoint is used **internally** by Super Duper Feeder to handle interactions with **external** WebSub hubs. You typically do not need to interact with this endpoint directly.
External hubs use this endpoint for:
For Verification (GET)
When a hub verifies a subscription, it sends a GET request with the following parameters:
hub.mode
: Either "subscribe" or "unsubscribe"hub.topic
: The feed URL being subscribed tohub.challenge
: A challenge string that must be echoed backhub.lease_seconds
: (Optional) The subscription duration in seconds
For Content Delivery (POST)
When a hub sends content updates, it sends a POST request with:
-
A
Link
header containing the topic URL withrel="self"
- The updated feed content in the request body
The service will forward these updates to any registered callback URLs for the topic.
Health Check
GET /health
Check if the service is running properly.
Usage Examples
Subscribing via API
Use the /api/webhook
endpoint to subscribe Super Duper Feeder to a feed and optionally register
your callback URL.
// Using fetch API in JavaScript
async function subscribeToFeed(topicUrl, callbackUrl) {
const formData = new FormData();
formData.append('topic', topicUrl);
if (callbackUrl) {
formData.append('callback', callbackUrl);
}
const response = await fetch('https://superduperfeeder.deno.dev/api/webhook', { // Replace with your instance URL if self-hosting
method: 'POST',
body: formData
});
const result = await response.json();
if (result.success) {
console.log(`Successfully initiated subscription for ${topicUrl}`);
console.log(`Using external hub: ${result.usingExternalHub}`); // True if WebSub hub found, false if polling
console.log(`Subscription ID: ${result.subscriptionId}`);
if (result.callbackId) {
console.log(`Callback ID: ${result.callbackId}`);
if(result.pendingVerification) {
console.log("Callback requires verification. Check your callback endpoint for a GET request with ?mode=verify&token=...");
console.log("Verification Instructions:", result.verificationInstructions);
} else {
console.log("Callback is verified.");
}
}
} else {
console.error(`Failed to subscribe: ${result.message}`);
}
}
// Example call:
// subscribeToFeed('https://example.com/feed.xml', 'https://my-app.com/webhook');
// subscribeToFeed('https://another-blog.com/rss'); // Without a callback
Handling Callback Verification
If you provide a callback
URL when subscribing via /api/webhook
, Super Duper Feeder
needs to verify that you control that URL. It will send a GET
request like this:
GET {your-callback-url}?mode=verify&token={verification-token}
Your endpoint must respond with a 200 OK
status and return the exact
{verification-token}
value as plain text in the response body.
// Example using Express.js
app.get('/my-webhook', (req, res) => {
// Check if this is a Super Duper Feeder verification request
if (req.query.mode === 'verify' && req.query.token) {
console.log(`Received verification request for token: ${req.query.token}`);
// Return the token as plain text to verify ownership
res.type('text/plain').status(200).send(req.query.token);
return;
}
// Handle other requests (like receiving actual feed updates via POST)
res.status(400).send('Invalid request');
});
Receiving Feed Updates at Your Callback
Once your callback is verified (or if you didn't provide one), Super Duper Feeder will forward feed updates it
receives (from external WebSub hubs or its own polling) to your registered callback URL via a POST
request. The request body will contain the feed update content.
// Example using Express.js (add this to your '/my-webhook' route)
// Make sure to use appropriate body parsing middleware (e.g., express.raw, express.text, express.json depending on expected feed types)
app.post('/my-webhook', express.raw({ type: '*/*' }), (req, res) => { // Use appropriate type or '*/*'
const feedUpdateContent = req.body.toString(); // Or parse as needed
const contentType = req.headers['content-type'];
console.log(`Received feed update (${contentType}):`);
console.log(feedUpdateContent);
// --- Process the feed update content here ---
// Example: Parse XML, extract items, store in database, etc.
// Acknowledge receipt to Super Duper Feeder
res.status(200).send('OK');
});
Important: Your endpoint should respond quickly (e.g., within a few seconds) with a
2xx
status code to acknowledge receipt. Perform time-consuming processing asynchronously. Failure
to respond promptly might cause Super Duper Feeder to consider the delivery failed and retry.
Best Practices
-
Implement callback verification properly
Always ensure your callback endpoint correctly handles verification requests. This is essential for security and ensures your callback will receive updates.
Implement proper error handling
-
Implement retry logic
Add retry logic for failed webhook deliveries to ensure you don't miss updates.
-
Ensure quick responses
Your callback endpoint should respond quickly (within a few seconds) to verification requests and content deliveries with a 2xx status code. Process heavy tasks asynchronously.
Add robust error handling for all API calls and webhook processing.
Troubleshooting
Common Issues
-
Callback verification fails
If your callback URL is not being verified:
- Ensure your callback URL is publicly accessible (not localhost or behind a firewall)
- Check that your endpoint correctly responds to verification requests by returning the token
- Verify that your endpoint responds with a 200 OK status code
- Make sure the response body contains only the token, with no extra whitespace or HTML
- If using a framework, ensure it's not adding any extra content to the response
-
Verification token expired
If you see "Verification token has expired":
- Tokens expire after 24 hours
- Submit a new subscription request to get a new verification token
- Ensure your callback endpoint is set up correctly before requesting a new token
-
Not receiving updates
If your callback is not receiving updates:
- Check that your callback has been verified (the pendingVerification flag should be false)
- Ensure your callback endpoint is functioning properly
- Check that the subscription is active and has not expired
- Verify that the feed is actually being updated