id(); $table->string('name'); $table->string('url', 2048); // Signs every delivery. Encrypted at rest: it is a credential. $table->text('secret'); $table->jsonb('events'); // Submissions carry names, addresses and messages from people // outside the collective; sending them elsewhere is opted into. $table->boolean('include_personal_data')->default(false); $table->boolean('is_active')->default(true); $table->unsignedSmallInteger('consecutive_failures')->default(0); $table->timestamp('last_delivered_at')->nullable(); $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete(); $table->timestamps(); }); Schema::create('webhook_deliveries', function (Blueprint $table): void { $table->id(); $table->foreignId('webhook_id')->constrained()->cascadeOnDelete(); $table->uuid('uuid')->unique(); $table->string('event', 60); $table->jsonb('payload'); $table->string('status', 20)->default('pending'); $table->unsignedSmallInteger('attempts')->default(0); $table->unsignedSmallInteger('response_status')->nullable(); $table->text('error')->nullable(); $table->timestamp('delivered_at')->nullable(); $table->timestamps(); $table->index(['webhook_id', 'created_at']); }); } public function down(): void { Schema::dropIfExists('webhook_deliveries'); Schema::dropIfExists('webhooks'); } };