Search by

marque / cennad

lomsoftware

REST API for Marque tracker platform

v4.3.0 2026-10-06 01:21 UTC

This package is auto-updated.

Last update: 2026-10-06 04:37:43 UTC


README

REST API for the Marque tracker platform. Provides JSON endpoints for torrent management.

Installation

Requires marque/trove.

composer require marque/cennad

Publish the config:

php artisan vendor:publish --tag=cennad-config

Endpoints

All endpoints require authentication by default and return JSON. Read endpoints can be opened to guests for a public tracker — see Authentication.

Method Endpoint Description
GET /api/torrents List torrents (paginated, searchable)
GET /api/torrents/{id} Get torrent details
POST /api/torrents Upload a torrent (Uploader+)
PUT /api/torrents/{id} Update torrent (name, description)
DELETE /api/torrents/{id} Delete torrent

List Torrents

GET /api/torrents?search=ubuntu&page=2

Returns paginated results with standard Laravel pagination metadata.

Get Torrent

GET /api/torrents/1

Response:

{
    "data": {
        "id": 1,
        "info_hash": "a1b2c3...",
        "name": "Example Torrent",
        "description": "Description text",
        "size": 734003200,
        "size_formatted": "700 MB",
        "file_count": 12,
        "seeders": 4,
        "leechers": 1,
        "has_torrent_file": true,
        "created_at": "2026-01-15T10:30:00.000000Z",
        "updated_at": "2026-01-15T10:30:00.000000Z",
        "user": {
            "id": 1,
            "name": "uploader"
        },
        "links": {
            "self": "https://example.com/api/torrents/1",
            "download": "https://example.com/torrents/1/download"
        }
    }
}

Upload Torrent

POST /api/torrents
Content-Type: multipart/form-data

torrent_file=<file>, name=..., description=...

Returns 201 with the torrent, plus meta.warnings (any warnings from the tracker's rules, e.g. a public torrent on a tracker that warns about them). The installed tracker's rules are checked before anything is stored. A refused torrent is a 422 validation error on torrent_file that says what to change: a public torrent on a private tracker, a v2-only torrent, or a file that isn't a torrent at all.

Update Torrent

PUT /api/torrents/1
Content-Type: application/json

{
    "name": "Updated Name",
    "description": "Updated description"
}

Requires ownership or Moderator+ role.

Delete Torrent

DELETE /api/torrents/1

Requires Moderator+ role. Returns 204 No Content.

Authorization

Cennad uses Trove's TorrentPolicy for access control:

Action Who Can
List Anyone read_middleware lets through. The list only holds torrents the viewer's role may see
View The same, except a torrent with a min_role needs a viewer at that role or above (guests see only unrestricted torrents)
Update Torrent owner or Moderator+
Delete Moderator+

Configuration

Published to config/cennad.php:

Key Default Description
prefix api URL prefix for all endpoints
read_middleware ['api', 'auth:api'] Middleware for index and show
write_middleware ['api', 'auth:api'] Middleware for store, update, destroy
route_names.prefix cennad Route name prefix
route_names.download torrents.download Download route name (for link generation)
rate_limit 60 Requests per minute, per user (per IP for guests). 0 or null turns it off

public_middleware and protected_middleware are the pre-4.0 names for read_middleware and write_middleware. They still work and still take precedence, but they emit a deprecation notice and are removed in 5.0.

Rate limiting

Every cennad route carries throttle:cennad, a named limiter allowing rate_limit requests a minute (60 by default). Reads and writes share one count. Signed-in users are counted by their id, and everyone else by IP. On read routes opened to guests no guard runs, so a client sending a token there is counted by IP too. Past the limit a request gets 429 Too Many Requests with a Retry-After header. While the limit is on, every response carries X-RateLimit-Limit and X-RateLimit-Remaining.

The limiter is appended after your read_middleware and write_middleware, so replacing those lists can't drop it by accident. To turn it off, for example because your app already throttles its API, set CENNAD_RATE_LIMIT=0. For a different shape (per token, or one limit for reads and another for writes), redefine the cennad limiter in your own service provider after cennad's has booted:

RateLimiter::for('cennad', fn (Request $request) => Limit::perMinute(300)->by($request->user()?->id ?: $request->ip()));

Authentication

The default middleware uses auth:api, which needs a guard named api in config/auth.php. Stock Laravel defines only web, and neither passport:install nor install:api adds one, so you add it yourself. With Passport, that's 'api' => ['driver' => 'passport', 'provider' => 'users']. With Sanctum, either define 'api' => ['driver' => 'sanctum', 'provider' => null], or set read_middleware and write_middleware to ['api', 'auth:sanctum']. Any guard works, as long as the middleware names it.

Reads and writes are configured separately so a public tracker can expose its catalogue without exposing its write endpoints. Both default to requiring authentication, because Cennad cannot tell whether it is serving a private tracker (bloodhound/guise) or a public one (hound/disguise), and the safe assumption is the private one.

To open the catalogue to unauthenticated visitors, drop the guard from read_middleware:

'read_middleware' => ['api'],

Leave write_middleware alone when you do — uploads, edits, and deletes are still governed by Trove's TorrentPolicy on top of whatever middleware you set.

Requirements

License

MIT. See LICENSE.