1161 lines
35 KiB
Markdown
1161 lines
35 KiB
Markdown
|
|
# API Documentation Plan
|
||
|
|
|
||
|
|
**Goal:** Expose Host Hub APIs via api.host.uk.com with OpenAPI documentation, enabling SDK generation for multiple languages.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Architecture Overview
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
||
|
|
│ api.host.uk.com │
|
||
|
|
│ │
|
||
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │
|
||
|
|
│ │ Swagger │ │ ReDoc │ │ SDK Downloads │ │
|
||
|
|
│ │ UI /docs │ │ /reference │ │ /sdks/php, /sdks/js... │ │
|
||
|
|
│ └──────────────┘ └──────────────┘ └──────────────────────────┘ │
|
||
|
|
│ │ │
|
||
|
|
│ ▼ │
|
||
|
|
│ ┌──────────────────┐ │
|
||
|
|
│ │ openapi.json │ │
|
||
|
|
│ │ openapi.yaml │ │
|
||
|
|
│ └────────┬─────────┘ │
|
||
|
|
│ │ │
|
||
|
|
└──────────────────────────────┼──────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌──────────────────────────────────────────────────────────────────────┐
|
||
|
|
│ Host Hub Laravel │
|
||
|
|
│ │
|
||
|
|
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||
|
|
│ │ API Routes │ │
|
||
|
|
│ │ /api/v1/workspaces, /api/v1/entitlements, /api/v1/commerce │ │
|
||
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
||
|
|
│ │ │
|
||
|
|
│ ┌───────────────┼───────────────┐ │
|
||
|
|
│ ▼ ▼ ▼ │
|
||
|
|
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
|
||
|
|
│ │ Scramble │ │ Controller │ │ Form │ │
|
||
|
|
│ │ (auto-gen) │ │ Attributes │ │ Requests │ │
|
||
|
|
│ └────────────┘ └────────────┘ └────────────┘ │
|
||
|
|
│ │
|
||
|
|
│ Note: MCP tools may call these same endpoints internally. │
|
||
|
|
│ For agent-native interface, see mcp.host.uk.com │
|
||
|
|
└──────────────────────────────────────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Package Selection: Scramble
|
||
|
|
|
||
|
|
**Why Scramble over L5-Swagger:**
|
||
|
|
- Zero annotations required - generates from code
|
||
|
|
- Understands Laravel conventions (Form Requests, Resources, Policies)
|
||
|
|
- Active development, Laravel-native
|
||
|
|
- Supports PHP 8 attributes for customization when needed
|
||
|
|
|
||
|
|
```bash
|
||
|
|
composer require dedoc/scramble
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## API Structure
|
||
|
|
|
||
|
|
### Version Strategy
|
||
|
|
|
||
|
|
```
|
||
|
|
/api/v1/* - Current stable
|
||
|
|
/api/v2/* - Future (when breaking changes needed)
|
||
|
|
```
|
||
|
|
|
||
|
|
Version in URL, not headers. Simple, cacheable, debuggable.
|
||
|
|
|
||
|
|
### Authentication
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────────────────┐
|
||
|
|
│ Authentication Methods │
|
||
|
|
├─────────────────────────────────────────────────────────────┤
|
||
|
|
│ │
|
||
|
|
│ 1. API Keys (Primary for SDK usage) │
|
||
|
|
│ Authorization: Bearer <api_key> │
|
||
|
|
│ - Scoped to workspace │
|
||
|
|
│ - Rotatable, revocable │
|
||
|
|
│ - Rate limited per key │
|
||
|
|
│ │
|
||
|
|
│ 2. OAuth 2.0 (For third-party apps) │
|
||
|
|
│ - Authorization code flow │
|
||
|
|
│ - Scopes map to entitlements │
|
||
|
|
│ - Managed via Passport │
|
||
|
|
│ │
|
||
|
|
│ 3. Session (Internal dashboard calls) │
|
||
|
|
│ - Sanctum SPA authentication │
|
||
|
|
│ - CSRF protected │
|
||
|
|
│ │
|
||
|
|
└─────────────────────────────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
### Endpoint Categories
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
/api/v1:
|
||
|
|
/auth:
|
||
|
|
- POST /token # Exchange credentials for token
|
||
|
|
- DELETE /token # Revoke token
|
||
|
|
- GET /me # Current user info
|
||
|
|
|
||
|
|
/workspaces:
|
||
|
|
- GET / # List user's workspaces
|
||
|
|
- GET /{id} # Get workspace details
|
||
|
|
- POST / # Create workspace
|
||
|
|
- PATCH /{id} # Update workspace
|
||
|
|
- DELETE /{id} # Delete workspace
|
||
|
|
|
||
|
|
/workspaces/{workspace}:
|
||
|
|
/members:
|
||
|
|
- GET / # List members
|
||
|
|
- POST / # Invite member
|
||
|
|
- DELETE /{user} # Remove member
|
||
|
|
|
||
|
|
/entitlements:
|
||
|
|
- GET / # Get entitlement summary
|
||
|
|
- GET /check/{feature} # Check specific feature
|
||
|
|
- GET /usage # Usage breakdown
|
||
|
|
|
||
|
|
/biolinks:
|
||
|
|
- GET / # List biolinks
|
||
|
|
- POST / # Create biolink
|
||
|
|
- GET /{id} # Get biolink
|
||
|
|
- PATCH /{id} # Update biolink
|
||
|
|
- DELETE /{id} # Delete biolink
|
||
|
|
|
||
|
|
/links:
|
||
|
|
- GET / # List short links
|
||
|
|
- POST / # Create short link
|
||
|
|
- GET /{id} # Get link details
|
||
|
|
- PATCH /{id} # Update link
|
||
|
|
- DELETE /{id} # Delete link
|
||
|
|
- GET /{id}/stats # Link analytics
|
||
|
|
|
||
|
|
/qr-codes:
|
||
|
|
- GET / # List QR codes
|
||
|
|
- POST / # Create QR code
|
||
|
|
- GET /{id} # Get QR code
|
||
|
|
- GET /{id}/download # Download QR image
|
||
|
|
|
||
|
|
/commerce:
|
||
|
|
/subscriptions:
|
||
|
|
- GET / # Current subscription
|
||
|
|
- POST /change # Change plan (preview)
|
||
|
|
- POST /change/confirm # Execute plan change
|
||
|
|
- POST /cancel # Cancel subscription
|
||
|
|
|
||
|
|
/invoices:
|
||
|
|
- GET / # List invoices
|
||
|
|
- GET /{id} # Get invoice
|
||
|
|
- GET /{id}/pdf # Download PDF
|
||
|
|
|
||
|
|
/payment-methods:
|
||
|
|
- GET / # List payment methods
|
||
|
|
- POST / # Add payment method
|
||
|
|
- DELETE /{id} # Remove payment method
|
||
|
|
- POST /{id}/default # Set as default
|
||
|
|
|
||
|
|
/support:
|
||
|
|
/tickets:
|
||
|
|
- GET / # List tickets
|
||
|
|
- POST / # Create ticket
|
||
|
|
- GET /{id} # Get ticket
|
||
|
|
- POST /{id}/reply # Reply to ticket
|
||
|
|
|
||
|
|
/webhooks:
|
||
|
|
- GET / # List webhook endpoints
|
||
|
|
- POST / # Create webhook endpoint
|
||
|
|
- PATCH /{id} # Update webhook
|
||
|
|
- DELETE /{id} # Delete webhook
|
||
|
|
- GET /{id}/deliveries # View delivery history
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Implementation
|
||
|
|
|
||
|
|
### Phase 1: Core Setup
|
||
|
|
|
||
|
|
```php
|
||
|
|
// config/scramble.php
|
||
|
|
return [
|
||
|
|
'info' => [
|
||
|
|
'title' => 'Host Hub API',
|
||
|
|
'description' => 'API for managing workspaces, biolinks, short links, and commerce.',
|
||
|
|
'version' => '1.0.0',
|
||
|
|
'contact' => [
|
||
|
|
'name' => 'Host UK Support',
|
||
|
|
'url' => 'https://support.host.uk.com',
|
||
|
|
'email' => 'api@host.uk.com',
|
||
|
|
],
|
||
|
|
],
|
||
|
|
|
||
|
|
'servers' => [
|
||
|
|
['url' => 'https://api.host.uk.com', 'description' => 'Production'],
|
||
|
|
['url' => 'https://api.staging.host.uk.com', 'description' => 'Staging'],
|
||
|
|
],
|
||
|
|
|
||
|
|
'api_path' => 'api/v1',
|
||
|
|
'api_domain' => null,
|
||
|
|
|
||
|
|
// Generate docs at this path
|
||
|
|
'export_path' => 'api/openapi.json',
|
||
|
|
];
|
||
|
|
```
|
||
|
|
|
||
|
|
### Phase 2: API Key System
|
||
|
|
|
||
|
|
```php
|
||
|
|
// database/migrations/create_api_keys_table.php
|
||
|
|
Schema::create('api_keys', function (Blueprint $table) {
|
||
|
|
$table->id();
|
||
|
|
$table->foreignId('workspace_id')->constrained()->cascadeOnDelete();
|
||
|
|
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||
|
|
$table->string('name');
|
||
|
|
$table->string('key', 64)->unique(); // hashed
|
||
|
|
$table->string('prefix', 8); // visible prefix for identification
|
||
|
|
$table->json('scopes')->nullable(); // ['read', 'write', 'delete']
|
||
|
|
$table->timestamp('last_used_at')->nullable();
|
||
|
|
$table->timestamp('expires_at')->nullable();
|
||
|
|
$table->timestamps();
|
||
|
|
$table->softDeletes();
|
||
|
|
|
||
|
|
$table->index(['workspace_id', 'deleted_at']);
|
||
|
|
});
|
||
|
|
|
||
|
|
// app/Models/ApiKey.php
|
||
|
|
class ApiKey extends Model
|
||
|
|
{
|
||
|
|
use SoftDeletes;
|
||
|
|
|
||
|
|
protected $casts = [
|
||
|
|
'scopes' => 'array',
|
||
|
|
'last_used_at' => 'datetime',
|
||
|
|
'expires_at' => 'datetime',
|
||
|
|
];
|
||
|
|
|
||
|
|
public static function generate(Workspace $workspace, User $user, string $name): array
|
||
|
|
{
|
||
|
|
$plainKey = Str::random(48);
|
||
|
|
$prefix = Str::random(8);
|
||
|
|
|
||
|
|
$apiKey = static::create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'user_id' => $user->id,
|
||
|
|
'name' => $name,
|
||
|
|
'key' => hash('sha256', $plainKey),
|
||
|
|
'prefix' => $prefix,
|
||
|
|
'scopes' => ['read', 'write'],
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Return plain key only once - never stored
|
||
|
|
return [
|
||
|
|
'api_key' => $apiKey,
|
||
|
|
'plain_key' => "{$prefix}_{$plainKey}", // hk_xxxxxxxx_xxxxx...
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function findByPlainKey(string $plainKey): ?static
|
||
|
|
{
|
||
|
|
[$prefix, $key] = explode('_', $plainKey, 2);
|
||
|
|
|
||
|
|
return static::where('prefix', $prefix)
|
||
|
|
->where('key', hash('sha256', $key))
|
||
|
|
->whereNull('deleted_at')
|
||
|
|
->where(fn($q) => $q->whereNull('expires_at')->orWhere('expires_at', '>', now()))
|
||
|
|
->first();
|
||
|
|
}
|
||
|
|
|
||
|
|
public function recordUsage(): void
|
||
|
|
{
|
||
|
|
$this->update(['last_used_at' => now()]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Phase 3: Authentication Guard
|
||
|
|
|
||
|
|
```php
|
||
|
|
// app/Http/Middleware/AuthenticateApiKey.php
|
||
|
|
class AuthenticateApiKey
|
||
|
|
{
|
||
|
|
public function handle(Request $request, Closure $next)
|
||
|
|
{
|
||
|
|
$token = $request->bearerToken();
|
||
|
|
|
||
|
|
if (!$token) {
|
||
|
|
return response()->json([
|
||
|
|
'error' => 'unauthorized',
|
||
|
|
'message' => 'API key required',
|
||
|
|
], 401);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check if it's an API key (prefixed with hk_)
|
||
|
|
if (str_starts_with($token, 'hk_')) {
|
||
|
|
$apiKey = ApiKey::findByPlainKey($token);
|
||
|
|
|
||
|
|
if (!$apiKey) {
|
||
|
|
return response()->json([
|
||
|
|
'error' => 'unauthorized',
|
||
|
|
'message' => 'Invalid API key',
|
||
|
|
], 401);
|
||
|
|
}
|
||
|
|
|
||
|
|
$apiKey->recordUsage();
|
||
|
|
|
||
|
|
// Set workspace context
|
||
|
|
$request->setUserResolver(fn() => $apiKey->user);
|
||
|
|
$request->attributes->set('api_key', $apiKey);
|
||
|
|
$request->attributes->set('workspace', $apiKey->workspace);
|
||
|
|
|
||
|
|
return $next($request);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fall back to Sanctum for OAuth tokens
|
||
|
|
return app(Authenticate::class)->handle($request, $next, 'sanctum');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Phase 4: API Controllers
|
||
|
|
|
||
|
|
```php
|
||
|
|
// app/Http/Controllers/Api/V1/WorkspaceController.php
|
||
|
|
namespace App\Http\Controllers\Api\V1;
|
||
|
|
|
||
|
|
use App\Http\Controllers\Controller;
|
||
|
|
use App\Http\Resources\WorkspaceResource;
|
||
|
|
use App\Http\Requests\Api\CreateWorkspaceRequest;
|
||
|
|
use App\Http\Requests\Api\UpdateWorkspaceRequest;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @tags Workspaces
|
||
|
|
*/
|
||
|
|
class WorkspaceController extends Controller
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* List workspaces
|
||
|
|
*
|
||
|
|
* Returns all workspaces the authenticated user has access to.
|
||
|
|
*
|
||
|
|
* @response WorkspaceResource[]
|
||
|
|
*/
|
||
|
|
public function index(Request $request)
|
||
|
|
{
|
||
|
|
$workspaces = $request->user()
|
||
|
|
->workspaces()
|
||
|
|
->with('subscription.package')
|
||
|
|
->paginate();
|
||
|
|
|
||
|
|
return WorkspaceResource::collection($workspaces);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get workspace
|
||
|
|
*
|
||
|
|
* @response WorkspaceResource
|
||
|
|
*/
|
||
|
|
public function show(Workspace $workspace)
|
||
|
|
{
|
||
|
|
$this->authorize('view', $workspace);
|
||
|
|
|
||
|
|
return new WorkspaceResource(
|
||
|
|
$workspace->load('subscription.package', 'members')
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create workspace
|
||
|
|
*
|
||
|
|
* @response 201 WorkspaceResource
|
||
|
|
*/
|
||
|
|
public function store(CreateWorkspaceRequest $request)
|
||
|
|
{
|
||
|
|
$workspace = Workspace::create([
|
||
|
|
'name' => $request->name,
|
||
|
|
'slug' => $request->slug ?? Str::slug($request->name),
|
||
|
|
'owner_id' => $request->user()->id,
|
||
|
|
]);
|
||
|
|
|
||
|
|
return new WorkspaceResource($workspace);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Phase 5: API Resources (Response Schemas)
|
||
|
|
|
||
|
|
```php
|
||
|
|
// app/Http/Resources/WorkspaceResource.php
|
||
|
|
namespace App\Http\Resources;
|
||
|
|
|
||
|
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @property int $id
|
||
|
|
* @property string $name
|
||
|
|
* @property string $slug
|
||
|
|
* @property string $created_at
|
||
|
|
*/
|
||
|
|
class WorkspaceResource extends JsonResource
|
||
|
|
{
|
||
|
|
public function toArray($request): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
'id' => $this->id,
|
||
|
|
'name' => $this->name,
|
||
|
|
'slug' => $this->slug,
|
||
|
|
'created_at' => $this->created_at->toIso8601String(),
|
||
|
|
'updated_at' => $this->updated_at->toIso8601String(),
|
||
|
|
|
||
|
|
// Relationships
|
||
|
|
'subscription' => new SubscriptionResource($this->whenLoaded('subscription')),
|
||
|
|
'members' => UserResource::collection($this->whenLoaded('members')),
|
||
|
|
'member_count' => $this->whenCounted('members'),
|
||
|
|
|
||
|
|
// Computed
|
||
|
|
'links' => [
|
||
|
|
'self' => route('api.v1.workspaces.show', $this->id),
|
||
|
|
'biolinks' => route('api.v1.workspaces.biolinks.index', $this->id),
|
||
|
|
'entitlements' => route('api.v1.workspaces.entitlements.index', $this->id),
|
||
|
|
],
|
||
|
|
];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## SDK Generation
|
||
|
|
|
||
|
|
### Target Registries (Maximum Developer Signal)
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||
|
|
│ SDK Distribution Matrix │
|
||
|
|
├──────────────┬────────────────────┬─────────────────────┬───────────────────┤
|
||
|
|
│ Language │ Registry │ Audience │ Generator │
|
||
|
|
├──────────────┼────────────────────┼─────────────────────┼───────────────────┤
|
||
|
|
│ PHP │ Packagist │ Web devs │ php │
|
||
|
|
│ TypeScript │ npm │ Frontend/Node │ typescript-fetch │
|
||
|
|
│ Python │ PyPI │ Scripts/Data/AI │ python │
|
||
|
|
│ Go │ pkg.go.dev │ DevOps/Cloud/CLI │ go │
|
||
|
|
│ Rust │ crates.io │ Systems/Performance │ rust │
|
||
|
|
│ Ruby │ RubyGems │ Rails/Web │ ruby │
|
||
|
|
│ Java │ Maven Central │ Enterprise │ java │
|
||
|
|
│ C#/.NET │ NuGet │ Enterprise/Windows │ csharp-netcore │
|
||
|
|
│ Kotlin │ Maven Central │ Android/Modern Java │ kotlin │
|
||
|
|
│ Swift │ Swift PM │ Apple ecosystem │ swift5 │
|
||
|
|
│ Dart │ pub.dev │ Flutter/Mobile │ dart │
|
||
|
|
├──────────────┴────────────────────┴─────────────────────┴───────────────────┤
|
||
|
|
│ Infrastructure / DevOps │
|
||
|
|
├──────────────┬────────────────────┬─────────────────────┬───────────────────┤
|
||
|
|
│ Ansible │ Ansible Galaxy │ SysAdmins │ SwaggerToAnsible │
|
||
|
|
│ Terraform │ Terraform Registry │ IaC DevOps │ Custom provider │
|
||
|
|
│ Pulumi │ Pulumi Registry │ Modern IaC │ Pulumi bridge │
|
||
|
|
│ CLI (Go) │ Homebrew/apt/yum │ Terminal users │ go + goreleaser │
|
||
|
|
│ GitHub Action│ GH Marketplace │ CI/CD users │ Custom │
|
||
|
|
└──────────────┴────────────────────┴─────────────────────┴───────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
### Priority Tiers
|
||
|
|
|
||
|
|
**Tier 1 - Core (Day 1):**
|
||
|
|
- PHP, TypeScript, Python (your primary audiences)
|
||
|
|
|
||
|
|
**Tier 2 - High Signal (Week 1):**
|
||
|
|
- Go (DevOps love, plus builds CLI binary)
|
||
|
|
- Rust (growing fast, crates.io visibility)
|
||
|
|
- Ruby (still strong web community)
|
||
|
|
|
||
|
|
**Tier 3 - Enterprise (Week 2):**
|
||
|
|
- Java, Kotlin (Maven Central = enterprise discovery)
|
||
|
|
- C#/.NET (NuGet = Microsoft ecosystem)
|
||
|
|
|
||
|
|
**Tier 4 - Mobile/Niche:**
|
||
|
|
- Swift (Apple developers)
|
||
|
|
- Dart (Flutter mobile)
|
||
|
|
|
||
|
|
**Tier 5 - Infrastructure:**
|
||
|
|
- Ansible (you have SwaggerToAnsible)
|
||
|
|
- Terraform Provider (huge IaC market)
|
||
|
|
- CLI binary via Homebrew
|
||
|
|
- GitHub Action
|
||
|
|
|
||
|
|
### OpenAPI Generator Configs
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# sdk-config/php.yaml
|
||
|
|
generatorName: php
|
||
|
|
outputDir: ./sdks/php
|
||
|
|
additionalProperties:
|
||
|
|
packageName: HostHubSdk
|
||
|
|
invokerPackage: HostUK\HostHub
|
||
|
|
apiPackage: Api
|
||
|
|
modelPackage: Model
|
||
|
|
composerVendorName: host-uk
|
||
|
|
composerProjectName: hosthub-sdk
|
||
|
|
gitUserId: host-uk
|
||
|
|
gitRepoId: hosthub-php-sdk
|
||
|
|
|
||
|
|
# sdk-config/typescript.yaml
|
||
|
|
generatorName: typescript-fetch
|
||
|
|
outputDir: ./sdks/typescript
|
||
|
|
additionalProperties:
|
||
|
|
npmName: "@host-uk/hosthub-sdk"
|
||
|
|
npmVersion: "1.0.0"
|
||
|
|
supportsES6: true
|
||
|
|
typescriptThreePlus: true
|
||
|
|
|
||
|
|
# sdk-config/python.yaml
|
||
|
|
generatorName: python
|
||
|
|
outputDir: ./sdks/python
|
||
|
|
additionalProperties:
|
||
|
|
packageName: hosthub
|
||
|
|
projectName: hosthub-sdk
|
||
|
|
packageVersion: "1.0.0"
|
||
|
|
|
||
|
|
# sdk-config/go.yaml
|
||
|
|
generatorName: go
|
||
|
|
outputDir: ./sdks/go
|
||
|
|
additionalProperties:
|
||
|
|
packageName: hosthub
|
||
|
|
moduleName: github.com/host-uk/hosthub-go
|
||
|
|
|
||
|
|
# sdk-config/rust.yaml
|
||
|
|
generatorName: rust
|
||
|
|
outputDir: ./sdks/rust
|
||
|
|
additionalProperties:
|
||
|
|
packageName: hosthub
|
||
|
|
packageVersion: "1.0.0"
|
||
|
|
|
||
|
|
# sdk-config/ruby.yaml
|
||
|
|
generatorName: ruby
|
||
|
|
outputDir: ./sdks/ruby
|
||
|
|
additionalProperties:
|
||
|
|
gemName: hosthub
|
||
|
|
gemVersion: "1.0.0"
|
||
|
|
gemAuthor: "Host UK"
|
||
|
|
gemHomepage: "https://api.host.uk.com"
|
||
|
|
|
||
|
|
# sdk-config/java.yaml
|
||
|
|
generatorName: java
|
||
|
|
outputDir: ./sdks/java
|
||
|
|
additionalProperties:
|
||
|
|
groupId: com.hostuk
|
||
|
|
artifactId: hosthub-sdk
|
||
|
|
artifactVersion: "1.0.0"
|
||
|
|
invokerPackage: com.hostuk.hosthub
|
||
|
|
apiPackage: com.hostuk.hosthub.api
|
||
|
|
modelPackage: com.hostuk.hosthub.model
|
||
|
|
|
||
|
|
# sdk-config/csharp.yaml
|
||
|
|
generatorName: csharp-netcore
|
||
|
|
outputDir: ./sdks/csharp
|
||
|
|
additionalProperties:
|
||
|
|
packageName: HostUK.HostHub
|
||
|
|
packageVersion: "1.0.0"
|
||
|
|
targetFramework: "net6.0"
|
||
|
|
|
||
|
|
# sdk-config/kotlin.yaml
|
||
|
|
generatorName: kotlin
|
||
|
|
outputDir: ./sdks/kotlin
|
||
|
|
additionalProperties:
|
||
|
|
groupId: com.hostuk
|
||
|
|
artifactId: hosthub-sdk
|
||
|
|
packageName: com.hostuk.hosthub
|
||
|
|
|
||
|
|
# sdk-config/swift.yaml
|
||
|
|
generatorName: swift5
|
||
|
|
outputDir: ./sdks/swift
|
||
|
|
additionalProperties:
|
||
|
|
projectName: HostHubSDK
|
||
|
|
podVersion: "1.0.0"
|
||
|
|
|
||
|
|
# sdk-config/dart.yaml
|
||
|
|
generatorName: dart
|
||
|
|
outputDir: ./sdks/dart
|
||
|
|
additionalProperties:
|
||
|
|
pubName: hosthub
|
||
|
|
pubVersion: "1.0.0"
|
||
|
|
pubAuthor: "Host UK"
|
||
|
|
```
|
||
|
|
|
||
|
|
### CLI Tool (Go-based)
|
||
|
|
|
||
|
|
```go
|
||
|
|
// cmd/hosthub/main.go
|
||
|
|
// Built from Go SDK, distributed via:
|
||
|
|
// - Homebrew (macOS/Linux)
|
||
|
|
// - apt repository (Debian/Ubuntu)
|
||
|
|
// - yum repository (RHEL/CentOS)
|
||
|
|
// - Scoop (Windows)
|
||
|
|
// - Direct binary downloads
|
||
|
|
|
||
|
|
// Example usage:
|
||
|
|
// $ hosthub workspaces list
|
||
|
|
// $ hosthub links create --url https://example.com
|
||
|
|
// $ hosthub biolinks get bl_123
|
||
|
|
```
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# .goreleaser.yml
|
||
|
|
builds:
|
||
|
|
- main: ./cmd/hosthub
|
||
|
|
binary: hosthub
|
||
|
|
goos: [linux, darwin, windows]
|
||
|
|
goarch: [amd64, arm64]
|
||
|
|
|
||
|
|
brews:
|
||
|
|
- tap:
|
||
|
|
owner: host-uk
|
||
|
|
name: homebrew-tap
|
||
|
|
name: hosthub
|
||
|
|
homepage: https://api.host.uk.com
|
||
|
|
|
||
|
|
nfpms:
|
||
|
|
- package_name: hosthub
|
||
|
|
vendor: Host UK
|
||
|
|
formats: [deb, rpm]
|
||
|
|
```
|
||
|
|
|
||
|
|
### Terraform Provider
|
||
|
|
|
||
|
|
```
|
||
|
|
terraform-provider-hosthub/
|
||
|
|
├── internal/
|
||
|
|
│ └── provider/
|
||
|
|
│ ├── provider.go
|
||
|
|
│ ├── workspace_resource.go
|
||
|
|
│ ├── biolink_resource.go
|
||
|
|
│ └── link_resource.go
|
||
|
|
└── examples/
|
||
|
|
└── main.tf
|
||
|
|
```
|
||
|
|
|
||
|
|
```hcl
|
||
|
|
# Example Terraform usage
|
||
|
|
terraform {
|
||
|
|
required_providers {
|
||
|
|
hosthub = {
|
||
|
|
source = "host-uk/hosthub"
|
||
|
|
version = "~> 1.0"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
provider "hosthub" {
|
||
|
|
api_key = var.hosthub_api_key
|
||
|
|
}
|
||
|
|
|
||
|
|
resource "hosthub_workspace" "main" {
|
||
|
|
name = "My Workspace"
|
||
|
|
slug = "my-workspace"
|
||
|
|
}
|
||
|
|
|
||
|
|
resource "hosthub_biolink" "landing" {
|
||
|
|
workspace_id = hosthub_workspace.main.id
|
||
|
|
name = "Landing Page"
|
||
|
|
url = "landing"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### GitHub Action
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# action.yml
|
||
|
|
name: 'Host Hub Action'
|
||
|
|
description: 'Manage Host Hub resources in CI/CD'
|
||
|
|
branding:
|
||
|
|
icon: 'link'
|
||
|
|
color: 'blue'
|
||
|
|
|
||
|
|
inputs:
|
||
|
|
api-key:
|
||
|
|
description: 'Host Hub API key'
|
||
|
|
required: true
|
||
|
|
command:
|
||
|
|
description: 'Command to run (e.g., "links create")'
|
||
|
|
required: true
|
||
|
|
|
||
|
|
runs:
|
||
|
|
using: 'node16'
|
||
|
|
main: 'dist/index.js'
|
||
|
|
```
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# Usage in workflow
|
||
|
|
- uses: host-uk/hosthub-action@v1
|
||
|
|
with:
|
||
|
|
api-key: ${{ secrets.HOSTHUB_API_KEY }}
|
||
|
|
command: links create --url ${{ github.event.deployment.url }}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Package Registry Summary
|
||
|
|
|
||
|
|
| Registry | Package Name | Install Command |
|
||
|
|
|----------|--------------|-----------------|
|
||
|
|
| Packagist | `host-uk/hosthub-sdk` | `composer require host-uk/hosthub-sdk` |
|
||
|
|
| npm | `@host-uk/hosthub-sdk` | `npm install @host-uk/hosthub-sdk` |
|
||
|
|
| PyPI | `hosthub` | `pip install hosthub` |
|
||
|
|
| pkg.go.dev | `github.com/host-uk/hosthub-go` | `go get github.com/host-uk/hosthub-go` |
|
||
|
|
| crates.io | `hosthub` | `cargo add hosthub` |
|
||
|
|
| RubyGems | `hosthub` | `gem install hosthub` |
|
||
|
|
| Maven | `com.hostuk:hosthub-sdk` | Maven/Gradle dependency |
|
||
|
|
| NuGet | `HostUK.HostHub` | `dotnet add package HostUK.HostHub` |
|
||
|
|
| pub.dev | `hosthub` | `dart pub add hosthub` |
|
||
|
|
| Swift PM | `HostHubSDK` | Package.swift dependency |
|
||
|
|
| Ansible Galaxy | `hostuk.hosthub` | `ansible-galaxy collection install hostuk.hosthub` |
|
||
|
|
| Terraform | `host-uk/hosthub` | `required_providers` block |
|
||
|
|
| Homebrew | `hosthub` | `brew install host-uk/tap/hosthub` |
|
||
|
|
| GitHub Actions | `host-uk/hosthub-action` | `uses: host-uk/hosthub-action@v1` |
|
||
|
|
|
||
|
|
### Generation Script
|
||
|
|
|
||
|
|
```bash
|
||
|
|
#!/bin/bash
|
||
|
|
# scripts/generate-sdks.sh
|
||
|
|
|
||
|
|
OPENAPI_FILE="storage/app/openapi.json"
|
||
|
|
OUTPUT_DIR="./sdks"
|
||
|
|
|
||
|
|
# Export fresh OpenAPI spec
|
||
|
|
php artisan scramble:export
|
||
|
|
|
||
|
|
# Array of all SDK configs
|
||
|
|
SDKS=(
|
||
|
|
"php"
|
||
|
|
"typescript"
|
||
|
|
"python"
|
||
|
|
"go"
|
||
|
|
"rust"
|
||
|
|
"ruby"
|
||
|
|
"java"
|
||
|
|
"csharp"
|
||
|
|
"kotlin"
|
||
|
|
"swift"
|
||
|
|
"dart"
|
||
|
|
)
|
||
|
|
|
||
|
|
# Generate all SDKs
|
||
|
|
for sdk in "${SDKS[@]}"; do
|
||
|
|
echo "Generating $sdk SDK..."
|
||
|
|
openapi-generator-cli generate \
|
||
|
|
-i $OPENAPI_FILE \
|
||
|
|
-c sdk-config/$sdk.yaml \
|
||
|
|
-o $OUTPUT_DIR/$sdk
|
||
|
|
done
|
||
|
|
|
||
|
|
echo "All SDKs generated in $OUTPUT_DIR"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Publish Script
|
||
|
|
|
||
|
|
```bash
|
||
|
|
#!/bin/bash
|
||
|
|
# scripts/publish-sdks.sh
|
||
|
|
|
||
|
|
VERSION=$1
|
||
|
|
|
||
|
|
if [ -z "$VERSION" ]; then
|
||
|
|
echo "Usage: ./publish-sdks.sh <version>"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
# PHP → Packagist (auto via GitHub webhook)
|
||
|
|
echo "PHP: Push to host-uk/hosthub-php-sdk triggers Packagist"
|
||
|
|
|
||
|
|
# TypeScript → npm
|
||
|
|
cd sdks/typescript
|
||
|
|
npm version $VERSION
|
||
|
|
npm publish --access public
|
||
|
|
cd ../..
|
||
|
|
|
||
|
|
# Python → PyPI
|
||
|
|
cd sdks/python
|
||
|
|
python -m build
|
||
|
|
twine upload dist/*
|
||
|
|
cd ../..
|
||
|
|
|
||
|
|
# Go → pkg.go.dev (auto on push + tag)
|
||
|
|
cd sdks/go
|
||
|
|
git tag v$VERSION
|
||
|
|
git push origin v$VERSION
|
||
|
|
cd ../..
|
||
|
|
|
||
|
|
# Rust → crates.io
|
||
|
|
cd sdks/rust
|
||
|
|
cargo publish
|
||
|
|
cd ../..
|
||
|
|
|
||
|
|
# Ruby → RubyGems
|
||
|
|
cd sdks/ruby
|
||
|
|
gem build hosthub.gemspec
|
||
|
|
gem push hosthub-$VERSION.gem
|
||
|
|
cd ../..
|
||
|
|
|
||
|
|
# Java/Kotlin → Maven Central
|
||
|
|
cd sdks/java
|
||
|
|
./gradlew publish
|
||
|
|
cd ../..
|
||
|
|
|
||
|
|
# C# → NuGet
|
||
|
|
cd sdks/csharp
|
||
|
|
dotnet pack -c Release
|
||
|
|
dotnet nuget push **/*.nupkg --source https://api.nuget.org/v3/index.json
|
||
|
|
cd ../..
|
||
|
|
|
||
|
|
# Dart → pub.dev
|
||
|
|
cd sdks/dart
|
||
|
|
dart pub publish
|
||
|
|
cd ../..
|
||
|
|
|
||
|
|
echo "All SDKs published at version $VERSION"
|
||
|
|
```
|
||
|
|
|
||
|
|
### SDK Usage Examples
|
||
|
|
|
||
|
|
```php
|
||
|
|
// PHP SDK
|
||
|
|
use HostUK\HostHub\Api\WorkspacesApi;
|
||
|
|
use HostUK\HostHub\Configuration;
|
||
|
|
|
||
|
|
$config = Configuration::getDefaultConfiguration()
|
||
|
|
->setApiKey('Authorization', 'Bearer hk_xxxxxxxx_xxxxx...');
|
||
|
|
|
||
|
|
$api = new WorkspacesApi(config: $config);
|
||
|
|
|
||
|
|
$workspaces = $api->listWorkspaces();
|
||
|
|
foreach ($workspaces as $workspace) {
|
||
|
|
echo $workspace->getName();
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// TypeScript SDK
|
||
|
|
import { WorkspacesApi, Configuration } from '@host-uk/hosthub-sdk';
|
||
|
|
|
||
|
|
const config = new Configuration({
|
||
|
|
apiKey: 'Bearer hk_xxxxxxxx_xxxxx...',
|
||
|
|
});
|
||
|
|
|
||
|
|
const api = new WorkspacesApi(config);
|
||
|
|
|
||
|
|
const workspaces = await api.listWorkspaces();
|
||
|
|
workspaces.forEach(ws => console.log(ws.name));
|
||
|
|
```
|
||
|
|
|
||
|
|
```python
|
||
|
|
# Python SDK
|
||
|
|
from hosthub import Configuration, WorkspacesApi
|
||
|
|
|
||
|
|
config = Configuration()
|
||
|
|
config.api_key['Authorization'] = 'Bearer hk_xxxxxxxx_xxxxx...'
|
||
|
|
|
||
|
|
api = WorkspacesApi(configuration=config)
|
||
|
|
|
||
|
|
workspaces = api.list_workspaces()
|
||
|
|
for ws in workspaces:
|
||
|
|
print(ws.name)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Documentation Site (api.host.uk.com)
|
||
|
|
|
||
|
|
### Site Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
api.host.uk.com/
|
||
|
|
├── / # Landing page (getting started)
|
||
|
|
├── /docs # Swagger UI (interactive)
|
||
|
|
├── /reference # ReDoc (beautiful reference)
|
||
|
|
├── /openapi.json # Raw OpenAPI spec
|
||
|
|
├── /openapi.yaml # YAML version
|
||
|
|
├── /sdks # SDK download page
|
||
|
|
│ ├── /php # PHP SDK + docs
|
||
|
|
│ ├── /typescript # TypeScript SDK + docs
|
||
|
|
│ └── /python # Python SDK + docs
|
||
|
|
├── /guides # Integration guides
|
||
|
|
│ ├── /authentication # Auth guide
|
||
|
|
│ ├── /webhooks # Webhook setup
|
||
|
|
│ └── /rate-limits # Rate limiting info
|
||
|
|
└── /changelog # API changelog
|
||
|
|
```
|
||
|
|
|
||
|
|
### Landing Page Content
|
||
|
|
|
||
|
|
```markdown
|
||
|
|
# Host Hub API
|
||
|
|
|
||
|
|
Build integrations with Host Hub using our REST API.
|
||
|
|
|
||
|
|
## Quick Start
|
||
|
|
|
||
|
|
1. **Get an API Key**
|
||
|
|
Navigate to Settings → API Keys in your workspace dashboard.
|
||
|
|
|
||
|
|
2. **Make Your First Request**
|
||
|
|
```bash
|
||
|
|
curl https://api.host.uk.com/v1/workspaces \
|
||
|
|
-H "Authorization: Bearer hk_your_api_key"
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Use an SDK**
|
||
|
|
- [PHP SDK](/sdks/php)
|
||
|
|
- [TypeScript SDK](/sdks/typescript)
|
||
|
|
- [Python SDK](/sdks/python)
|
||
|
|
|
||
|
|
## Looking for Agent Integration?
|
||
|
|
|
||
|
|
For AI agent and MCP server integration, visit [mcp.host.uk.com](https://mcp.host.uk.com).
|
||
|
|
```
|
||
|
|
|
||
|
|
### Deployment
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# Separate static site or Laravel routes
|
||
|
|
# Option A: Static site (Astro/Next.js) pulling openapi.json
|
||
|
|
# Option B: Laravel routes serving documentation
|
||
|
|
|
||
|
|
# routes/api-docs.php (if using Laravel)
|
||
|
|
Route::domain('api.host.uk.com')->group(function () {
|
||
|
|
Route::get('/', [ApiDocsController::class, 'landing']);
|
||
|
|
Route::get('/docs', [ApiDocsController::class, 'swagger']);
|
||
|
|
Route::get('/reference', [ApiDocsController::class, 'redoc']);
|
||
|
|
Route::get('/openapi.json', [ApiDocsController::class, 'openApiJson']);
|
||
|
|
Route::get('/openapi.yaml', [ApiDocsController::class, 'openApiYaml']);
|
||
|
|
Route::get('/sdks', [ApiDocsController::class, 'sdks']);
|
||
|
|
Route::get('/sdks/{language}', [ApiDocsController::class, 'sdkDownload']);
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Rate Limiting
|
||
|
|
|
||
|
|
```php
|
||
|
|
// config/api.php
|
||
|
|
return [
|
||
|
|
'rate_limits' => [
|
||
|
|
'default' => [
|
||
|
|
'requests' => 1000,
|
||
|
|
'per_minutes' => 60,
|
||
|
|
],
|
||
|
|
'authenticated' => [
|
||
|
|
'requests' => 5000,
|
||
|
|
'per_minutes' => 60,
|
||
|
|
],
|
||
|
|
'by_tier' => [
|
||
|
|
'starter' => ['requests' => 1000, 'per_minutes' => 60],
|
||
|
|
'pro' => ['requests' => 5000, 'per_minutes' => 60],
|
||
|
|
'agency' => ['requests' => 20000, 'per_minutes' => 60],
|
||
|
|
],
|
||
|
|
],
|
||
|
|
];
|
||
|
|
|
||
|
|
// Rate limit headers included in all responses:
|
||
|
|
// X-RateLimit-Limit: 5000
|
||
|
|
// X-RateLimit-Remaining: 4987
|
||
|
|
// X-RateLimit-Reset: 1704067200
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Error Responses
|
||
|
|
|
||
|
|
```json
|
||
|
|
// Standard error format
|
||
|
|
{
|
||
|
|
"error": "validation_error",
|
||
|
|
"message": "The given data was invalid.",
|
||
|
|
"details": {
|
||
|
|
"name": ["The name field is required."],
|
||
|
|
"slug": ["The slug has already been taken."]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Error codes
|
||
|
|
{
|
||
|
|
"error": "unauthorized", // 401 - Missing/invalid auth
|
||
|
|
"error": "forbidden", // 403 - No permission
|
||
|
|
"error": "not_found", // 404 - Resource not found
|
||
|
|
"error": "validation_error", // 422 - Invalid input
|
||
|
|
"error": "rate_limit_exceeded", // 429 - Too many requests
|
||
|
|
"error": "internal_error", // 500 - Server error
|
||
|
|
"error": "entitlement_exceeded", // 403 - Plan limit reached
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Webhooks
|
||
|
|
|
||
|
|
```php
|
||
|
|
// Webhook events
|
||
|
|
'workspace.created'
|
||
|
|
'workspace.updated'
|
||
|
|
'workspace.deleted'
|
||
|
|
'subscription.created'
|
||
|
|
'subscription.updated'
|
||
|
|
'subscription.cancelled'
|
||
|
|
'invoice.created'
|
||
|
|
'invoice.paid'
|
||
|
|
'invoice.failed'
|
||
|
|
'biolink.created'
|
||
|
|
'biolink.updated'
|
||
|
|
'link.created'
|
||
|
|
'link.clicked' // High volume - opt-in only
|
||
|
|
|
||
|
|
// Webhook payload
|
||
|
|
{
|
||
|
|
"id": "evt_123456",
|
||
|
|
"type": "subscription.updated",
|
||
|
|
"created_at": "2024-12-31T12:00:00Z",
|
||
|
|
"data": {
|
||
|
|
"subscription": { ... }
|
||
|
|
},
|
||
|
|
"workspace_id": 123
|
||
|
|
}
|
||
|
|
|
||
|
|
// Signature verification
|
||
|
|
$signature = hash_hmac('sha256', $payload, $webhookSecret);
|
||
|
|
// Compare with X-HostHub-Signature header
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## MCP Intersection Note
|
||
|
|
|
||
|
|
The REST API and MCP tools share the same underlying services:
|
||
|
|
|
||
|
|
```
|
||
|
|
┌──────────────────┐ ┌──────────────────┐
|
||
|
|
│ REST API │ │ MCP Tools │
|
||
|
|
│ api.host.uk.com │ │ mcp.host.uk.com │
|
||
|
|
└────────┬─────────┘ └────────┬─────────┘
|
||
|
|
│ │
|
||
|
|
└──────────┬─────────────┘
|
||
|
|
▼
|
||
|
|
┌──────────────────┐
|
||
|
|
│ Service Layer │
|
||
|
|
│ (Laravel) │
|
||
|
|
└──────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
PHP applications may call REST endpoints directly. AI agents should prefer the MCP interface at [mcp.host.uk.com](https://mcp.host.uk.com) for:
|
||
|
|
- Structured tool calling
|
||
|
|
- Entitlement-aware server discovery
|
||
|
|
- Agent-optimized response formats
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Implementation Phases
|
||
|
|
|
||
|
|
### Phase 1: Foundation
|
||
|
|
- [ ] Install Scramble
|
||
|
|
- [ ] Configure API versioning
|
||
|
|
- [ ] Create API key model and migration
|
||
|
|
- [ ] Implement API key authentication guard
|
||
|
|
- [ ] Set up rate limiting
|
||
|
|
|
||
|
|
### Phase 2: Core Endpoints
|
||
|
|
- [ ] Auth endpoints (token exchange)
|
||
|
|
- [ ] Workspace CRUD
|
||
|
|
- [ ] Entitlement checking
|
||
|
|
- [ ] Member management
|
||
|
|
|
||
|
|
### Phase 3: Product Endpoints
|
||
|
|
- [ ] Biolinks CRUD
|
||
|
|
- [ ] Short links CRUD
|
||
|
|
- [ ] QR codes CRUD
|
||
|
|
- [ ] Analytics endpoints
|
||
|
|
|
||
|
|
### Phase 4: Commerce Endpoints
|
||
|
|
- [ ] Subscription management
|
||
|
|
- [ ] Invoice listing
|
||
|
|
- [ ] Payment methods
|
||
|
|
|
||
|
|
### Phase 5: Documentation Site
|
||
|
|
- [ ] Deploy api.host.uk.com
|
||
|
|
- [ ] Swagger UI integration
|
||
|
|
- [ ] ReDoc integration
|
||
|
|
- [ ] SDK download pages
|
||
|
|
|
||
|
|
### Phase 6: SDK Generation
|
||
|
|
- [ ] Set up OpenAPI Generator
|
||
|
|
- [ ] Generate PHP SDK
|
||
|
|
- [ ] Generate TypeScript SDK
|
||
|
|
- [ ] Generate Python SDK
|
||
|
|
- [ ] Publish to package registries
|
||
|
|
|
||
|
|
### Phase 7: Webhooks
|
||
|
|
- [ ] Webhook endpoint management
|
||
|
|
- [ ] Event dispatching
|
||
|
|
- [ ] Delivery tracking
|
||
|
|
- [ ] Retry logic
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Files to Create/Modify
|
||
|
|
|
||
|
|
### New Files
|
||
|
|
```
|
||
|
|
app/
|
||
|
|
├── Http/
|
||
|
|
│ ├── Controllers/Api/V1/
|
||
|
|
│ │ ├── AuthController.php
|
||
|
|
│ │ ├── WorkspaceController.php
|
||
|
|
│ │ ├── EntitlementController.php
|
||
|
|
│ │ ├── BiolinkController.php
|
||
|
|
│ │ ├── LinkController.php
|
||
|
|
│ │ ├── QrCodeController.php
|
||
|
|
│ │ ├── SubscriptionController.php
|
||
|
|
│ │ ├── InvoiceController.php
|
||
|
|
│ │ └── WebhookController.php
|
||
|
|
│ ├── Middleware/
|
||
|
|
│ │ └── AuthenticateApiKey.php
|
||
|
|
│ ├── Resources/
|
||
|
|
│ │ ├── WorkspaceResource.php
|
||
|
|
│ │ ├── BiolinkResource.php
|
||
|
|
│ │ ├── LinkResource.php
|
||
|
|
│ │ └── ... (all API resources)
|
||
|
|
│ └── Requests/Api/
|
||
|
|
│ └── ... (all form requests)
|
||
|
|
├── Models/
|
||
|
|
│ ├── ApiKey.php
|
||
|
|
│ └── WebhookEndpoint.php
|
||
|
|
config/
|
||
|
|
├── scramble.php
|
||
|
|
└── api.php
|
||
|
|
routes/
|
||
|
|
├── api_v1.php
|
||
|
|
└── api-docs.php
|
||
|
|
database/migrations/
|
||
|
|
├── create_api_keys_table.php
|
||
|
|
└── create_webhook_endpoints_table.php
|
||
|
|
scripts/
|
||
|
|
└── generate-sdks.sh
|
||
|
|
sdk-config/
|
||
|
|
├── php.yaml
|
||
|
|
├── typescript.yaml
|
||
|
|
└── python.yaml
|
||
|
|
```
|
||
|
|
|
||
|
|
### Modified Files
|
||
|
|
- `routes/api.php` - Include versioned routes
|
||
|
|
- `app/Http/Kernel.php` - Register API middleware
|
||
|
|
- `composer.json` - Add Scramble dependency
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
*Created: 2024-12-31*
|
||
|
|
*Status: Planning*
|
||
|
|
*Destination: api.host.uk.com*
|