> ## Documentation Index
> Fetch the complete documentation index at: https://commet.co/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrar con Symfony

> Agrega cobros y pagos a tu aplicación de Symfony.

Instala la Commet Skill para que tu agente integre el SDK actual y valide su trabajo contra el contrato vivo de la API.

```bash theme={null}
npx skills add commet-labs/skills --skill commet
```

<Steps>
  <Step title="Instalar">
    ```bash theme={null}
    composer require commet/commet-php
    ```
  </Step>

  <Step title="Configurar">
    ```bash title=".env" theme={null}
    COMMET_API_KEY=ck_sandbox_xxx
    COMMET_WEBHOOK_SECRET=whsec_xxx
    ```

    ```yaml title="config/services.yaml" theme={null}
    services:
        Commet\Commet:
            factory: ['@App\Factory\CommetFactory', 'create']

        App\Factory\CommetFactory:
            arguments:
                $apiKey: '%env(COMMET_API_KEY)%'
    ```

    ```php title="src/Factory/CommetFactory.php" theme={null}
    <?php

    namespace App\Factory;

    use Commet\Commet;

    class CommetFactory
    {
        public function __construct(
            private string $apiKey,
        ) {}

        public function create(): Commet
        {
            return new Commet(
                apiKey: $this->apiKey,
            );
        }
    }
    ```
  </Step>

  <Step title="Suscribir">
    ```php title="src/Controller/BillingController.php" theme={null}
    <?php

    namespace App\Controller;

    use Commet\Commet;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\HttpFoundation\JsonResponse;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\Routing\Attribute\Route;

    class BillingController extends AbstractController
    {
        public function __construct(
            private Commet $commet,
        ) {}

        #[Route('/billing/subscribe', methods: ['POST'])]
        public function subscribe(Request $request): JsonResponse
        {
            $data = $request->toArray();

            $this->commet->customers->create(
                email: $data['email'],
                id: $data['customer_id'],
            );

            $subscription = $this->commet->subscriptions->create(
                customerId: $data['customer_id'],
                planCode: 'pro',
            );

            return $this->json([
                'checkout_url' => $subscription->checkoutUrl,
            ]);
        }
    }
    ```
  </Step>

  <Step title="Verificar acceso">
    ```php title="src/Controller/BillingController.php" theme={null}
    #[Route('/billing/subscription/{customerId}', methods: ['GET'])]
    public function getSubscription(string $customerId): JsonResponse
    {
        $subscription = $this->commet->subscriptions->getActive($customerId);

        if ($subscription === null) {
            return $this->json(['error' => 'no_active_subscription'], 404);
        }

        return $this->json([
            'status' => $subscription->status->value,
        ]);
    }

    #[Route('/billing/features/{feature}/{customerId}', methods: ['GET'])]
    public function checkFeature(string $feature, string $customerId): JsonResponse
    {
        $result = $this->commet->featureAccess->get(code: $feature, customerId: $customerId);

        return $this->json([
            'allowed' => $result->allowed,
        ]);
    }
    ```
  </Step>

  <Step title="Trackear uso">
    ```php title="src/Controller/BillingController.php" theme={null}
    #[Route('/billing/usage', methods: ['POST'])]
    public function trackUsage(Request $request): JsonResponse
    {
        $data = $request->toArray();

        $this->commet->usage->track(
            customerId: $data['customer_id'],
            featureCode: 'api_calls',
            value: 1,
        );

        return $this->json(['tracked' => true]);
    }
    ```

    El uso se agrega y se cobra al final del período.
  </Step>

  <Step title="Portal del Cliente">
    ```php title="src/Controller/BillingController.php" theme={null}
    use Symfony\Component\HttpFoundation\RedirectResponse;

    #[Route('/billing/portal', methods: ['GET'])]
    public function portal(): RedirectResponse
    {
        $result = $this->commet->portal->getUrl(customerId: 'user_123');

        return $this->redirect($result->portalUrl);
    }
    ```
  </Step>

  <Step title="Webhooks">
    ```php title="src/Controller/WebhookController.php" theme={null}
    <?php

    namespace App\Controller;

    use Commet\Resources\WebhooksResource;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\DependencyInjection\Attribute\Autowire;
    use Symfony\Component\HttpFoundation\JsonResponse;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Attribute\Route;

    class WebhookController extends AbstractController
    {
        public function __construct(
            #[Autowire(env: 'COMMET_WEBHOOK_SECRET')]
            private string $webhookSecret,
        ) {}

        #[Route('/webhooks/commet', methods: ['POST'])]
        public function handle(Request $request): JsonResponse|Response
        {
            $webhooks = new WebhooksResource();

            $payload = $webhooks->verifyAndParse(
                rawBody: $request->getContent(),
                signature: $request->headers->get('x-commet-signature'),
                secret: $this->webhookSecret,
            );

            if ($payload === null) {
                return new Response('Invalid signature', 401);
            }

            match ($payload['event']) {
                'subscription.activated' => $this->handleActivated($payload),
                'subscription.canceled' => $this->handleCanceled($payload),
                default => null,
            };

            return $this->json(['ok' => true]);
        }

        private function handleActivated(array $payload): void
        {
            // manejar activación
        }

        private function handleCanceled(array $payload): void
        {
            // manejar cancelación
        }
    }
    ```
  </Step>
</Steps>

## Relacionado

* [Suscripciones](/docs/es/manage-subscriptions)
* [Trackear Uso](/docs/es/track-usage)
* [Portal del Cliente](/docs/es/customer-portal)
* [Referencia del SDK](/docs/es/sdk-reference)


## Related topics

- [Integrar con PHP](/docs/es/integrate-with-php.md)
- [Integrar con Flask](/docs/es/integrate-with-flask.md)
- [Integrar con Java](/docs/es/integrate-with-java.md)
- [Integrar con Django](/docs/es/integrate-with-django.md)
- [Integrar con Encore](/docs/es/integrate-with-encore.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.