ConvertKit - v1.0.0
ConvertKit Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
1.0.0 - 2026-07-13
Initial release. Full Kit v4 API integration for Laravel 10, 11, 12, and 13.
Added
- Kit v4 API client with exponential-backoff retries,
Retry-Afterhandling, and typed exceptions (KitAuthException,KitRateLimitException,KitValidationException,KitNotFoundException,KitServerException). - Endpoint wrappers for subscribers, forms, tags, and custom fields.
Each returns immutable DTOs (
Subscriber,Form,Tag,CustomField) orPaginatedCollectionfor list responses. - Reference-data cache for forms, tags, and custom-field lists with a per-API-key cache key so rotating credentials never serves stale data from a different Kit account.
ConvertKitfacade +convertkit()helper as the fluent entry point.- Forms integration with
artisanpack-ui/forms:KitFeedmodel — one row per (form, Kit destination) join.HandleFormSubmittedForKitlistener — subscribed via string binding so the forms package remains an optional peer.ConditionalLogicEvaluator— six operators (equals,not_equals,contains,not_contains,is_empty,is_not_empty) withall(AND) orany(OR) semantics.FieldMapper— translates a submission's slugs into the Kit payload shape; duck-typed for the concreteFormSubmissionmodel.ProcessKitFeedjob — retries only on transient failures (KitRateLimitException,KitServerException); every other exception marks the job failed immediately to avoid burning Kit quota.
- REST endpoints:
GET|POST|PUT|PATCH|DELETE /admin/convertkit/feeds[/{id}]— feed CRUD, guarded by themanage-convertkit-feedsGate ability (fails closed on empty config).POST /admin/convertkit/feeds/{id}/test— dry-run a feed against a sample submission, reports{would_send, reason, payload}without touching Kit.POST /convertkit/subscribers— public subscribe endpoint front-end forms POST to. Accepts eitherfeed_id(uses the feed's config) or a barekit_form_id. DispatchesSubscribeToKiton the queue, returns 202. Rate limited per-IP (default 10/min).
SubscribeToKitjob with the same retry policy asProcessKitFeed, plus aMAX_TAGS_PER_JOB = 50defense-in-depth cap on the tag-apply loop.- Artisan commands:
convertkit:test— verify the configured API key reaches Kit.convertkit:sync [resource]— force-refresh cached forms, tags, and custom fields.convertkit:feeds {list|create|delete}— CLI feed management, with an interactive wizard for create and confirmation prompt for delete.
- Events:
KitSubscribed— a subscribe call to Kit succeeded.KitSubscriptionFailed— a job failed terminally; fires exactly once per failure.KitFeedSkipped— a feed was loaded but not fired; reason codes includeconditional_logic,field_map,evaluator_error, anddispatch_error.
FakeConvertKit— recording test double installed viaConvertKit::fake(). Assertion helpers:assertSubscribed,assertTagged,assertNothingSent,assertSentCount.- Documentation — 30 wiki-style pages under
docs/covering install, configuration, API client, forms integration, REST endpoints, subscribe recipes (Livewire / React / Vue), Artisan commands, events, errors, testing, FAQ, and contributing. - CI — GitHub Actions matrix testing Laravel 12 (PHP 8.2/8.3/8.4) and Laravel 13 (PHP 8.3/8.4). Lint job runs PHP-CS-Fixer and PHPCS. Release workflow tags and notifies Packagist.
Security
- Public subscribe endpoint enforces
tagsarray size ≤ 20 andfieldssize ≤ 32 with each valuestring|max:2048— closes quota-drain and queue-bloat vectors. - Unknown/inactive
feed_idreturns Laravel's standard validation error shape so the endpoint doesn't act as a feed-id enumeration oracle. - Feed dry-run endpoint returns a stable
reasontoken; the underlying exception message is logged server-side viaLog::warning, not returned to the client. - Feed admin routes fail closed on empty
gate_abilityconfig — an empty ability falls back to the built-in default rather than opening the API. - Public subscribe route throttle prepended unconditionally, unless the
consumer supplies their own
throttle:*middleware (which the package detects and defers to).