diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeRepository.kt
index d8d5bf4..0b434d1 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeRepository.kt
@@ -9,6 +9,7 @@ import kr.co.vividnext.sodalive.can.payment.QPayment.payment
 import kr.co.vividnext.sodalive.member.QMember.member
 import org.springframework.data.jpa.repository.JpaRepository
 import org.springframework.stereotype.Repository
+import java.time.LocalDateTime
 
 @Repository
 interface ChargeRepository : JpaRepository<Charge, Long>, ChargeQueryRepository
@@ -16,6 +17,7 @@ interface ChargeRepository : JpaRepository<Charge, Long>, ChargeQueryRepository
 interface ChargeQueryRepository {
     fun getOldestChargeWhereRewardCanGreaterThan0(chargeId: Long, memberId: Long, container: String): Charge?
     fun getOldestChargeWhereChargeCanGreaterThan0(chargeId: Long, memberId: Long, container: String): Charge?
+    fun getChargeCountAfterDate(date: LocalDateTime): Int
 }
 
 class ChargeQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : ChargeQueryRepository {
@@ -59,6 +61,10 @@ class ChargeQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : Cha
             .fetchFirst()
     }
 
+    override fun getChargeCountAfterDate(date: LocalDateTime): Int {
+        return 0
+    }
+
     private fun getPaymentGatewayCondition(container: String): BooleanExpression? {
         val paymentGatewayCondition = when (container) {
             "aos" -> {
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeService.kt
index a9c7e21..493346c 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/ChargeService.kt
@@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.can.charge
 import com.fasterxml.jackson.databind.ObjectMapper
 import kr.co.bootpay.Bootpay
 import kr.co.vividnext.sodalive.can.CanRepository
+import kr.co.vividnext.sodalive.can.charge.event.ChargeSpringEvent
 import kr.co.vividnext.sodalive.can.payment.Payment
 import kr.co.vividnext.sodalive.can.payment.PaymentGateway
 import kr.co.vividnext.sodalive.can.payment.PaymentStatus
@@ -15,6 +16,7 @@ import okhttp3.Request
 import okhttp3.RequestBody.Companion.toRequestBody
 import org.json.JSONObject
 import org.springframework.beans.factory.annotation.Value
+import org.springframework.context.ApplicationEventPublisher
 import org.springframework.data.repository.findByIdOrNull
 import org.springframework.http.HttpHeaders
 import org.springframework.security.core.userdetails.User
@@ -29,6 +31,8 @@ class ChargeService(
     private val memberRepository: MemberRepository,
     private val objectMapper: ObjectMapper,
     private val okHttpClient: OkHttpClient,
+    private val applicationEventPublisher: ApplicationEventPublisher,
+
     @Value("\${bootpay.application-id}")
     private val bootpayApplicationId: String,
     @Value("\${bootpay.private-key}")
@@ -80,6 +84,8 @@ class ChargeService(
                     charge.payment?.method = verifyResult.method
                     charge.payment?.status = PaymentStatus.COMPLETE
                     member.charge(charge.chargeCan, charge.rewardCan, "pg")
+
+                    applicationEventPublisher.publishEvent(ChargeSpringEvent(chargeId = charge.id!!, member = member))
                 } else {
                     throw SodaException("결제정보에 오류가 있습니다.")
                 }
@@ -127,6 +133,8 @@ class ChargeService(
                 charge.payment?.method = "애플(인 앱 결제)"
                 charge.payment?.status = PaymentStatus.COMPLETE
                 member.charge(charge.chargeCan, charge.rewardCan, "ios")
+
+                applicationEventPublisher.publishEvent(ChargeSpringEvent(chargeId = charge.id!!, member = member))
             } else {
                 throw SodaException("결제정보에 오류가 있습니다.")
             }
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventRepository.kt
new file mode 100644
index 0000000..88a047b
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventRepository.kt
@@ -0,0 +1,54 @@
+package kr.co.vividnext.sodalive.can.charge.event
+
+import com.querydsl.jpa.impl.JPAQueryFactory
+import kr.co.vividnext.sodalive.admin.event.ChargeEvent
+import kr.co.vividnext.sodalive.admin.event.QChargeEvent.chargeEvent
+import kr.co.vividnext.sodalive.can.charge.QCharge.charge
+import kr.co.vividnext.sodalive.can.payment.PaymentStatus
+import kr.co.vividnext.sodalive.can.payment.QPayment.payment
+import kr.co.vividnext.sodalive.member.Member
+import org.springframework.data.jpa.repository.JpaRepository
+import java.time.LocalDateTime
+
+interface ChargeEventRepository : JpaRepository<ChargeEvent, Long>, ChargeEventQueryRepository
+
+interface ChargeEventQueryRepository {
+    fun getChargeEvent(): ChargeEvent?
+    fun getPaymentCount(member: Member, method: String, startDate: LocalDateTime, endDate: LocalDateTime): Int
+}
+
+class ChargeEventQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : ChargeEventQueryRepository {
+    override fun getChargeEvent(): ChargeEvent? {
+        val now = LocalDateTime.now()
+        return queryFactory
+            .selectFrom(chargeEvent)
+            .where(
+                chargeEvent.isActive.isTrue
+                    .and(chargeEvent.startDate.loe(now))
+                    .and(chargeEvent.endDate.goe(now))
+            )
+            .orderBy(chargeEvent.id.asc())
+            .fetchFirst()
+    }
+
+    override fun getPaymentCount(
+        member: Member,
+        method: String,
+        startDate: LocalDateTime,
+        endDate: LocalDateTime
+    ): Int {
+        val where = charge.member.eq(member)
+            .and(charge.payment.method.eq(method))
+            .and(
+                charge.payment.status.eq(PaymentStatus.COMPLETE)
+                    .or(charge.payment.status.eq(PaymentStatus.RETURN))
+            )
+
+        return queryFactory
+            .selectFrom(charge)
+            .innerJoin(charge.payment, payment)
+            .where(where)
+            .fetch()
+            .count()
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt
new file mode 100644
index 0000000..bdcda79
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt
@@ -0,0 +1,118 @@
+package kr.co.vividnext.sodalive.can.charge.event
+
+import kr.co.vividnext.sodalive.can.charge.Charge
+import kr.co.vividnext.sodalive.can.charge.ChargeRepository
+import kr.co.vividnext.sodalive.can.charge.ChargeStatus
+import kr.co.vividnext.sodalive.can.payment.Payment
+import kr.co.vividnext.sodalive.can.payment.PaymentGateway
+import kr.co.vividnext.sodalive.can.payment.PaymentStatus
+import kr.co.vividnext.sodalive.common.SodaException
+import kr.co.vividnext.sodalive.fcm.FcmEvent
+import kr.co.vividnext.sodalive.fcm.FcmEventType
+import kr.co.vividnext.sodalive.member.Member
+import org.springframework.context.ApplicationEventPublisher
+import org.springframework.data.repository.findByIdOrNull
+import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
+import kotlin.math.ceil
+import kotlin.math.round
+
+@Service
+class ChargeEventService(
+    private val repository: ChargeEventRepository,
+    private val chargeRepository: ChargeRepository,
+    private val chargeEventRepository: ChargeEventRepository,
+    private val applicationEventPublisher: ApplicationEventPublisher
+) {
+    @Transactional
+    fun applyChargeEvent(chargeId: Long, member: Member) {
+        val charge = chargeRepository.findByIdOrNull(chargeId)
+            ?: throw SodaException("이벤트가 적용되지 않았습니다.")
+
+        if (member.auth != null) {
+            val authDate = member.auth!!.createdAt!!
+            val chargeCount = chargeRepository.getChargeCountAfterDate(authDate)
+
+            if (chargeCount > 0) {
+                applyOtherEvent(charge, member)
+            } else {
+                applyFirstChargeEvent(charge, member)
+            }
+        } else {
+            applyOtherEvent(charge, member)
+        }
+    }
+
+    private fun applyOtherEvent(charge: Charge, member: Member) {
+        val chargeEvent = repository.getChargeEvent()
+
+        if (chargeEvent != null) {
+            val eventChargeCount = chargeEventRepository.getPaymentCount(
+                member = member,
+                method = chargeEvent.title,
+                startDate = chargeEvent.startDate,
+                endDate = chargeEvent.endDate
+            )
+
+            if (eventChargeCount < chargeEvent.availableCount) {
+                val additionalCan = round(charge.chargeCan * chargeEvent.addPercent).toInt()
+                applyEvent(
+                    additionalCan = additionalCan,
+                    member = member,
+                    paymentGateway = charge.payment?.paymentGateway!!,
+                    method = chargeEvent.title
+                )
+
+                applicationEventPublisher.publishEvent(
+                    FcmEvent(
+                        type = FcmEventType.INDIVIDUAL,
+                        title = chargeEvent.title,
+                        message = "$additionalCan 캔이 추가 지급되었습니다.",
+                        recipients = listOf(member.id!!),
+                        isAuth = false
+                    )
+                )
+            }
+        }
+    }
+
+    private fun applyFirstChargeEvent(charge: Charge, member: Member) {
+        val additionalCan = ceil(charge.chargeCan * 0.2).toInt()
+        applyEvent(
+            additionalCan = additionalCan,
+            member = member,
+            paymentGateway = charge.payment?.paymentGateway!!,
+            method = "첫 충전 이벤트"
+        )
+
+        applicationEventPublisher.publishEvent(
+            FcmEvent(
+                type = FcmEventType.INDIVIDUAL,
+                title = "첫 충전 이벤트",
+                message = "$additionalCan 캔이 추가 지급되었습니다.",
+                recipients = listOf(member.id!!),
+                isAuth = false
+            )
+        )
+    }
+
+    private fun applyEvent(additionalCan: Int, member: Member, paymentGateway: PaymentGateway, method: String) {
+        val eventCharge = Charge(0, additionalCan, status = ChargeStatus.EVENT)
+        eventCharge.title = "$additionalCan 캔"
+        eventCharge.member = member
+
+        val payment = Payment(
+            status = PaymentStatus.COMPLETE,
+            paymentGateway = paymentGateway
+        )
+        payment.method = method
+        eventCharge.payment = payment
+        chargeRepository.save(eventCharge)
+
+        when (paymentGateway) {
+            PaymentGateway.PG -> member.charge(0, additionalCan, "pg")
+            PaymentGateway.GOOGLE_IAP -> member.charge(0, additionalCan, "aos")
+            PaymentGateway.APPLE_IAP -> member.charge(0, additionalCan, "ios")
+        }
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeSpringEvent.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeSpringEvent.kt
new file mode 100644
index 0000000..2716f51
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeSpringEvent.kt
@@ -0,0 +1,22 @@
+package kr.co.vividnext.sodalive.can.charge.event
+
+import kr.co.vividnext.sodalive.member.Member
+import org.springframework.context.event.EventListener
+import org.springframework.scheduling.annotation.Async
+import org.springframework.stereotype.Component
+
+class ChargeSpringEvent(
+    val chargeId: Long,
+    val member: Member
+)
+
+@Component
+class ChargeSpringEventListener(
+    private val chargeEventService: ChargeEventService
+) {
+    @Async
+    @EventListener
+    fun applyChargeEvent(event: ChargeSpringEvent) {
+        chargeEventService.applyChargeEvent(event.chargeId, event.member)
+    }
+}