Search by

marque / cennad

lomsoftware

REST API for Marque tracker platform

v4.4.0 2026-10-19 15:37 UTC

This package is auto-updated.

Last update: 2026-10-19 16:46:07 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.

Bans reach the API through the api group. With usarrs 8.3 or later installed, a banned, disabled or pending member's token gets a 403 on every cennad route, because usarrs runs its check in that group. Keep 'api' in both middleware lists if you replace them, or add usarrs' EnsureUserIsActive yourself.

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.