프로모션 지급 api 장애 발생 (지급 실패했으나 성공으로 응답이 내려옴)

이 글의 성격은 무엇인가요?

질문 / 문제 해결

내용을 설명해주세요

execute-promotion API에서 개발 스펙에 없는 응답이 내려오는데
내용을 보니 지급 실패인데 성공으로 내려오는 장애가 발생하고 있습니다.

해당 현상은 오늘 2026-05-20 17:42:22 KST부터 현재까지 발생 중입니다.
로그상 1,000건 이상 확인되었고, 해당 응답을 받은 유저가 재시도하면서 발생 건수가 계속 증가하고 있습니다.

{
  "resultType": "SUCCESS",
  "success": {
    "blocked": true,
    "retryAfterSeconds": 57,
    "message": "요청 한도를 초과했습니다. 잠시 후 다시 시도해주세요."
  }
}
  1. 지급이 실패 또는 차단된 상황이라면 개발가이드 기준대로 errorCode/message 형태로 내려와야 하는데
    resultType이 SUCCESS로 내려와 저희 서버가 정상 지급되었다고 판단하고 유저 재화를 차감하고 있습니다. 당연히 토스에서는 포인트 지급 처리가 안되고 있습니다.

  2. 요청 한도 초과로 지급이 차단되는 케이스라면 resultType: FAIL로 내려와야 하고,
    에러코드는 하위 호환을 고려해 4110으로 내려주시고, retryAfterSeconds 등 추가 정보는 기존 에러 응답 패턴처럼 error.data 안에 포함해 주시기 바랍니다.

{
  "resultType": "FAIL",
  "success": null,
  "error": {
    "errorCode": "4110",
    "reason": "요청 한도를 초과했습니다. 잠시 후 다시 시도해주세요.",
    "data": {
      "blocked": true,
      "retryAfterSeconds": 57
    }
  }
}

3 서비스/API에 반영하기 위해 해당 에러가 발생하는 기준 문의드립니다. (예: 1초에 3건 이상 요청시 발생 이라던지)

4 여러번 시도하면 성공되는 케이스가 있습니다. 60초 막으려면 다 막아야지 몇 번 시도하면 중간중간 성공하는 케이스가 발생하는걸로 봐서는 API 서버중 일부만 배포된거 아닌가 의심됩니다.

멤버/빌링 관련 스펙 변경은 서비스 장애로 바로 이어질 수 있습니다.
사전 공지 없이 잠수함 패치가 되면 정말 곤란합니다. ㅠㅠ

안녕하세요, 최근 민원이 접수됨에 따라 프로모션 포인트 지급, 푸시 발송에 대해 api별, userKey 별로 분 당 최대 10회 프로모션 및 푸시 발송 제한이 추가되었습니다.

응답은 하위호환 가능하도록 개선해보겠습니다. :bow:

성공 응답으로 오면.. 에러 상황에서 포인트가 지급되었다는건가요??

@dohyung 님 안녕하세요, 확인감사드립니다.

제가 정확히 이해 못했는데,
파트너사쪽에서 프로모션 지급을 하면 유저에게 푸시가 가고 → 그 민원이 들어와서 정책을 조정하신거로 이해하면 될까요?

그렇다면 유저가 앱에서 직접 토스 포인트 받기를 하는 경우는 고려가 안된거 같습니다.

서비스레이어에서는 유저가 보유 재화를 토스 포인트로 교환하는 액션이 짧은 시간 내 반복할 수 있는데,
아마 앱테크는 모두 이런 방식이라 생각됩니다.

이 경우 분당 10회 제약이 걸리면, 서비스레이어에서 쿨타임 UX를 적용해야 하는데 이게 좀 애로사항이 큽니다.
예를 들어
“토스 포인트로 교환하세요. 단, 분당 10회까지만 가능합니다.” 내지는
“57초 후 재시도 해주세요” 같은..정말 이상한 UX가 됩니다.

그래서 요청 드리는 부분이 최소한 userKey 기준 분당 60회 수준으로 조정 요청드립니다.
분당 60회라면 서비스 레이어에서 교환 액션에 1초 인터벌 등을 적용해 UX적으로 대응 가능한 마지 노선이라고 봅니다.

더불어 이건 걱정되어 말씀드리는건데
execute-promotion API에서 지급이 실패하거나 차단된 경우라면 당연히 SUCCESS가 아니라 FAIL 응답으로 내려와야 합니다. (에러코드 하위호환 무관)
지금 아마 많은 파트너사들이 에러가 발생하는지도 모르고 있을거에요. SUCCESS로 판단할거라고 보거든요.
저희 쪽에서도 약 100명 정도의 고객에게 영향이 있었고, 일부 고객이 직접 제보해서 인지하게 되었습니다.
이 패치와 관련해 재지급 처리 및 방어 코드 적용으로 새벽에 약 5시간가량 대응했고, 오늘도 동일 현상이 계속 발생하고 있어요.

아무튼 결론은

분당 10회는 UX적으로 해소하기 어렵기에 파트너사들이 UX 대응 가능하도록 적어도 분당 60회로 수정 요청 드립니다.

아니요,
성공응답으로 오면 보통 서비스 레이어세서 리워드를 차감하고 토스 포인트를 지급하잖아요?
그런데 에러임에도 성공응답으로 내려오기 때문에, 리워드는 차감되지만 토스 포인트는 지급이 안되는 상황이에요.

@Albert 님 혹시 최대 지급 금액을 조정해서 60초 간 지급해야하는 금액을 하나로 뭉쳐서 지금하는 것은 어려우실까요? 유저 + 앱 당 QPM이 60이 되면 하나의 앱에서만 최대 분 당 60건의 푸시를 받게 될 수 있어서, 민원으로 들어왔던 케이스들을 해소하지 못할 것 같습니다.

말씀주신 ERROR로 응답 주는 건을 수정하여 테스트 중이고 곧 배포될 예정입니다.

@dohyung
네, 확인 감사드립니다.

1.일단 금액 조정으로 그룹핑해서 지급하는 방법은 근본적인 해결책이 아닌것 같습니다. 완화는 되겠지만요

유저들은 리워드를 모아서 한번에 교환하는 방식을 선호하는 그룹군이 있는데,
그렇게 본다면 유저가 가지고 있는 보유 리워드 전체교환 개념이 있어야만 해소가 됩니다.
그리고 1회 지급 한도가 5,000원 제약이 있어서 상단에서 또 걸려요.

예를 들어 재화 3,000개 (재화 1개당 100원) 보유한 유저가
재화 50개씩 토스포인트 5,000원으로 교환하도록 그룹핑해도 연속으로 하면결국 10회 제약이 걸립니다.
결국에는 그룹핑을 하더라도 xx초후 재시도하세요 라던지 이런 방어코드가 필요하게 됩니다.

2.그렇다면 QPM 20은 어려울까요?

1회 지급시 3초 인터벌까지는 테스트해보니 답답하긴 하지만 그래도 차선으로 수용가능해 보입니다.
교환 버튼 클릭 → 응답 → 인터벌 (이게 총 3초) → 60초에 20회 가능

3.민원 케이스가 예상이 안되어서..이거 혹시 푸시쪽이 메인인가요?

토스 포인트 지급이 핵심이 아니라 푸시 민원으로 인해 푸시에 정책을 걸었다면..
토스 포인트 지급에 푸시가 함께 트랜젝션이 걸려 있어 이런 상황이 된 걸까요?

제 머리에서는 이거밖에 예상이 안되네요

만약에 이게 맞다면..푸시와 지급을 분리하고
푸시는 QPM에 걸리면 발송되지 않는 정도로 하면 될거 같은데..

혹은 A앱에서 토스포인트 지급시 해당 유저가 A앱에 접속되어 있는 상황이면 푸시는 제외한다던지..
(이건 더 복잡해보이지만 UX적으로 이게 방향은 맞습니다. 포그라운드상태에서 푸시는 보통 배제하니까요, 그리고 보통 토스포인트 지급시 미니앱이 자체적으로 얼마 지급했다라고 알리고 있어서, 이미 현재상태가 중복 알림이기는 합니다. 자체알림+푸시알림)

깔끔한 해결책이 나오지 않아 아쉽네요.
다만 정상적인 비즈니스가 대부분일거 같은데 일부 민원해소를 위해 다수의 유저 및 파트너사에게 불편함을 초래하는 정책이 되어버리는거 같습니다..

@Albert QPM을 20으로 조정하는 것에 대해 내부적으로 논의해보겠습니다 :person_bowing:

말씀주신대로 포인트 지급에 의한 푸시 발송량이 민원의 대상이지만, 그와 별개로 금원 지급이기 때문에 고지가 필요한 맥락도 함께 있어 비즈니스적으로는 말씀주신대로 까다로운 상황이 맞습니다.

현재 토스앱이 포그라운드 상태에서는 푸시가 아닌 토스트 형태로 노출되고 있습니다. 다만 유저가 포그라운드인지 여부는 지급 대상이 되는 서버 측에서 식별하기는 쉽지 않아서 일괄적인 제한 정책만 가능한 상황입니다.

추가로, errorCode = 4095로 아래 공유주신 구조로 변경해서 배포되었습니다.

@dohyung

네 빠른 수정 감사드립니다.
데이터 내려온거 확인했어요. 지금도 실시간으로 발생중입니다..ㅠㅠ

2026-05-21 15:21:24 부터 4095 확인

{
	"resultType":"FAIL",
	"success":null,
	"error":{
		"errorType":0,
		"errorCode":"4095",
		"reason":"요청 한도를 초과했습니다. 잠시 후 다시 시도해주세요.",
		"data":{
			"blocked":true,
			"retryAfterSeconds":38
		},
		"title":null
	}
}

*메모: 푸시가 민원대상, 포그라운드는 푸시가 아니고 토스트, 지급서버에서 포그라운드 구분 어려움 & 고지의무때문에 분리X

QPM 20만이라도 되면 좋겠습니다.

그리고 논의하실때 핵심은 푸시보다는
“토스 프로모션 지급 기능은 분당 10회 제약이 맞는가”
“푸시 민원을 해소하기 위해 토스 프로모션 지급 기능 자체에 10회 제약을 거는게 맞는가”
이런 관점으로 봐주세요..

저희 서비스 유저들도 요청 한도 초과 이슈를 겪고 있습니다..

@Albert 안녕하세요, 프로모션 지급에 대해 qpm 20으로 수정했습니다.

@dohyung 님 빠른 수정 감사드립니다.

다만 방금 3회 정도 테스트 해보았는데 여전히 10회 이후 에러가 내려옵니다.
아직 배포가 덜 되었거나 그런건 아닐까요? 일단 이따 다시 테스트 해보겠습니다!

금일 기준 20회/1분 적용된 부분 확인하였습니다.
다만 1분 이내 20회 이상이 되는 경우도 종종 있기는 합니다.
api 서버 덜 배포되었거나 뭔가 카운팅 공유가 잘 안되던가 그럴거 같은데 참고 부탁드립니다.
일단 resolve로 볼게요~감사합니다

혹시 grantPromotionReward 함수도 같이 수정 되었을까요? 10회 제한이 있는 것으로 보입니다

해당 함수는 영향도 없는데, 어떤 오류를 받으셨을까요?

grantPromotionReward는 지급받으려는 유저가 함수를 호출하므로, foreground 임을 보장하기 때문에 별도 호출에 제약이 없습니다.

넵, 저도 그렇게 이해하고 개발했는데 실제로 세어보면 1분 3초간 10회 지급 이후 지급이 안 됩니다.

grantPromotionReward 용 API는 파트너사 분들께 제공하는 API와 분리되어 있어, 실제 쿼타 적용이 되어 있지 않습니다.

채널톡으로 재현 영상 전달드렸습니다

보내주신 영상 전달 받았고, 다시 한번 저희 측 로직 점검 했으나 sdk 레벨에서 지급 제한이 걸려있는 것은 없습니다.

SDK 응답이 어떻게 내려왔는지 응답을 공유주실 수 있을까요? 정말 횟수가 영향이 있는지 금면한도 등 한도 제한에 의해 PENDING된 상태인지 저희가 식별하기 영상만으로는 어렵네요 :person_bowing: