Debugging Marketplace
Use this when Marketplace account linking, public domain verification, catalogue browsing, install authorization, heartbeat, diagnostics, or update notices fail.
Flow Diagram
Section titled “Flow Diagram”sequenceDiagram participant Admin participant CMS as Capell CMS participant App as Capell App participant Public as Public Host
Admin->>CMS: Connect account CMS->>App: Create account connection session App-->>Admin: Approval URL Admin->>App: Approve site App->>CMS: Authenticated callback with code/state CMS->>App: Exchange code App-->>CMS: Instance ID and signing secret Admin->>CMS: Verify public domain CMS->>Public: Write challenge file CMS->>App: Request verification App->>Public: Fetch .well-known challenge App-->>CMS: Verified instance/domain CMS->>App: Heartbeat and install authorization requestsAccount linking is the normal setup path. Public domain verification is a stronger production signal and requires a real public hostname.
First Checks
Section titled “First Checks”php artisan config:show app.urlphp artisan config:show capell-marketplace.marketplace.base_urlphp artisan config:show capell-marketplace.marketplace.webhook_urlphp artisan route:list --name=capell-marketplaceThe default API URL is:
CAPELL_MARKETPLACE_URL=https://capell.app/api/v1Account Connection
Section titled “Account Connection”select connection_session_id, claimed_domain, app_url, callback_url, status, expires_at, completed_at, last_errorfrom marketplace_account_connection_sessionsorder by id desclimit 5;| Status | Meaning | Fix |
|---|---|---|
pending | Admin has not returned from Capell App yet | Complete the current approval URL before it expires. |
completing | Callback reserved the session while exchanging code | Wait briefly; if stuck, start a new connection. |
failed | Remote request or validation failed | Read last_error, fix config/session, retry. |
expired | 10-minute window passed | Start a fresh connection. |
completed | Instance should exist | Check marketplace_instances. |
Do not reuse old approval URLs after starting a newer account connection.
Public Domain Verification
Section titled “Public Domain Verification”select domain, challenge_id, challenge_path, status, expires_at, last_errorfrom marketplace_registration_sessionsorder by id desclimit 5;Fetch the exact public challenge URL:
curl -i https://your-domain/.well-known/capell/marketplace/chal_EXAMPLEExpected result: 200 OK, Content-Type: text/plain, and the stored challenge token body.
Common blockers:
www.example.comwas entered butexample.comis being fetched, or the reverse.- The challenge route is behind auth, maintenance mode, or a CDN rule.
- Static file handling bypasses Laravel/public files incorrectly.
- The session expired.
- The domain is local-only, such as
.test,.localhost,localhost,127.*, or an IP address.
Catalogue And Install Authorization
Section titled “Catalogue And Install Authorization”select instance_id, connection_mode, account_email, verified_domains, last_heartbeat_atfrom marketplace_instancesorder by last_heartbeat_at desclimit 5;Browsing the catalogue only proves the catalogue endpoint works. Installing also needs a connected instance, entitlement/licence state, domain policy, and local platform compatibility.
Check local package versions:
composer show capell-app/core filament/filament livewire/livewire laravel/frameworkIf the catalogue appears stale in local debugging:
php artisan cache:clearUse targeted browser refresh controls in production rather than broad cache clears.
Heartbeat And Update Notices
Section titled “Heartbeat And Update Notices”select instance_id, last_heartbeat_atfrom marketplace_instancesorder by last_heartbeat_at desclimit 5;
select source, checked_at, capell_version, metadatafrom marketplace_update_advisory_snapshotsorder by checked_at desclimit 5;Heartbeat needs:
- Marketplace API base URL;
- public webhook/callback URL from
CAPELL_MARKETPLACE_WEBHOOK_URLorAPP_URL; - known instance ID;
- outbound network access to the Marketplace API.
Test Recipes
Section titled “Test Recipes”Account Connection
Section titled “Account Connection”it('fails account connection when app url has no host', function (): void { config(['app.url' => '']);
StartMarketplaceAccountConnectionAction::run();})->throws(RuntimeException::class, 'APP_URL must include a valid host');Challenge Route
Section titled “Challenge Route”it('serves only matching pending challenge domains', function (): void { MarketplaceRegistrationSession::factory()->create([ 'domain' => 'example.com', 'challenge_id' => 'chal_TEST', 'challenge_token' => 'secret-token', ]);
$this->get('https://example.com/.well-known/capell/marketplace/chal_TEST') ->assertOk() ->assertSee('secret-token');});Heartbeat
Section titled “Heartbeat”it('does not phone home without a connected instance', function (): void { expect(PhoneHomeAction::run())->toBeFalse() ->and(PhoneHomeAction::lastFailureMessage())->toContain('not connected');});