Handyman
Handyman13mo ago

안녕하세요

const paymentSuccessController = async (req, res) => { try { const userId = req.userId; const { orderId, amount, paymentKey } = req.query; // usePoint added const { usePoint, letterId } = req.body; const response = await axios.post( "https://api.tosspayments.com/v1/payments/confirm", { orderId, amount, paymentKey, }, { headers: { Authorization: "Basic " + Buffer.from(secretKey + ":").toString("base64"), "Content-Type": "application/json", }, responseType: "json", } ); 이런식으로 토스페이먼츠로 필수값을 보내는데 혹시 뭐가 잘못됬는지 code: 'NOT_FOUND_PAYMENT_SESSION', message: '결제 시간이 만료되어 결제 진행 데이터가 존재하지 않습니다.' 이런 오류가 발생했네요 db에는 정상적으로 데이터가 저장되었습니다 이후 failUrl로 이동하네요...
31 Replies
토스페이먼츠 BOT
⏳ 잠시만 기다려주세요! 곧 답변드리겠습니다
오류 문의일 경우 아래 정보를 미리 전달해주시면, 빠른 답변에 도움이 됩니다.
- 주문번호(orderId) : - 문의 내용 :
(img를 함께 첨부해주시면 도움이됩니다)
* 계약관련 내용은 1544-7772로 문의주세요. * 주말/공휴일에는 답변이 늦을 수 있어요.
Handyman
HandymanOP13mo ago
주문번호(orderId): 113a31ec-dd13-4277-92af-d95fa4976821 문의 내용:
No description
유부장
유부장13mo ago
orderId, amount, paymentKey 가 전부 빈값으로 넘어온 호출이 보이네요 결제승인 API 가 우선 빈값으로 호출되고, 그 다음 정상 호출이 들어오는 것 같은데 어떤 상황에서 빈값으로 승인 API 를 호출하는지 확인 해보시면 될것 같아요
토스페이먼츠 BOT
❤️ 기술문의 경험이 어떠셨나요?!
간단히 코멘트 남겨주세요! 제품 발전에 큰 힘이 됩니다.
Handyman
HandymanOP13mo ago
아 감사합니다! 혹시 orderId amount paymentKey 를 서버에서 유효성 검사를 한후에 컴펌링크로 값을 보내야하는건가요?
OMG
OMG13mo ago
네 결제 요청시 전달한 orderId, amount 랑 맞는지 valid 체크 후 paymentKey 로 승인 요청 하시면 됩니다
Ayaan이안
Ayaan이안13mo ago
https://discord.com/channels/864296203746803753/1194168728603074590 에 남겨주신 코드 여기도 올려둡니다.
const paymentSuccessController = async (req, res) => {
try {
const userId = req.userId;
const { orderId, amount, paymentKey } = req.query; // usePoint added
const { usePoint, letterId } = req.body;
const response = await axios.post(
"https://api.tosspayments.com/v1/payments/confirm",
{
orderId,
amount,
paymentKey,
},
{
headers: {
Authorization:
"Basic " + Buffer.from(secretKey + ":").toString("base64"),
"Content-Type": "application/json",
},
responseType: "json",
}
);

if (response.data.error) {
console.error("API 응답에서 오류:", response.data.error);
throw new Error(response.data.error);
}

const paymentInfo = response.data;
await paymentSuccessService(
userId,
letterId,
paymentInfo,
usePoint === "true"
); // usePoint passed

res.status(201).json({
message: "success",
});
} catch (error) {
console.error("결제 성공 컨트롤러에서 오류:", error);

// TODO: 결제 실패 비즈니스 로직 처리
res.redirect(
`/fail?code=${error.response?.data?.code || 'UNKNOWN_ERROR'}&message=${error.response?.data?.message || 'Unknown error'}`
);
}
};
const paymentSuccessController = async (req, res) => {
try {
const userId = req.userId;
const { orderId, amount, paymentKey } = req.query; // usePoint added
const { usePoint, letterId } = req.body;
const response = await axios.post(
"https://api.tosspayments.com/v1/payments/confirm",
{
orderId,
amount,
paymentKey,
},
{
headers: {
Authorization:
"Basic " + Buffer.from(secretKey + ":").toString("base64"),
"Content-Type": "application/json",
},
responseType: "json",
}
);

if (response.data.error) {
console.error("API 응답에서 오류:", response.data.error);
throw new Error(response.data.error);
}

const paymentInfo = response.data;
await paymentSuccessService(
userId,
letterId,
paymentInfo,
usePoint === "true"
); // usePoint passed

res.status(201).json({
message: "success",
});
} catch (error) {
console.error("결제 성공 컨트롤러에서 오류:", error);

// TODO: 결제 실패 비즈니스 로직 처리
res.redirect(
`/fail?code=${error.response?.data?.code || 'UNKNOWN_ERROR'}&message=${error.response?.data?.message || 'Unknown error'}`
);
}
};
Handyman
HandymanOP13mo ago
Ayaan이안
Ayaan이안13mo ago
지금 이용하시는 언어가 어떻게 되시는건가요? Node.js + Express 이신가요?
Handyman
HandymanOP13mo ago
네 맞습니다!
Ayaan이안
Ayaan이안13mo ago
paymentSuccessService 안 쪽 코드를 좀 볼 수 있을까요?
Handyman
HandymanOP13mo ago
네 알겠습니다 음 너무 길다고 하는데
Ayaan이안
Ayaan이안13mo ago
아 그러면, paymentSuccessService가 하는게 어떤 작업인지 알 수 있을까요? 단순 가맹점 DB처리인가요? 아니면 저기서 금액 등 validation을 처리하고 DB처리까지 다 하는 건가요?
Handyman
HandymanOP13mo ago
네 금액들어오면 db에 저장되어있는 값과 비교 분석하고 amount가 맞으면
Ayaan이안
Ayaan이안13mo ago
그 부분이 문제가 있는 것 같습니다. https://api.tosspayments.com/v1/payments/confirm 요청 직전에, 가맹점 DB에 저장되어 있는 값과 비교 분석 하시고 amount가 맞으면 https://api.tosspayments.com/v1/payments/confirm 호출 해 주시구요. 그 응답값을 파싱해서 가맹점 DB에 결제완료 처리를 해주셔야 합니다.
Handyman
HandymanOP13mo ago
아 그렇군요 그럼 포인트를 만약 사용했다고 가정을하면 포인트를 사용했다고 정보도 포함해서 보내야하나요 아니면 포인트를 뺸 amount를 보내야하나요?
Ayaan이안
Ayaan이안13mo ago
귀사 포인트인가요? 아니면 카드사 포인트인가요?
Handyman
HandymanOP13mo ago
귀사의 포인트입니다
Ayaan이안
Ayaan이안13mo ago
귀사 포인트면 결제창 오픈 시부터 가격을 빼서 호출해 주시고, validation에서도 그만큼 가격을 빼서 보내시면 됩니다.
Handyman
HandymanOP13mo ago
오 알겠습니다 감사합니다 새해복많이 받으세요~
Ayaan이안
Ayaan이안13mo ago
그리고 추가적으로
Handyman
HandymanOP13mo ago
Ayaan이안
Ayaan이안13mo ago
successUrl을 처음 결제창 오픈 시 설정하시잖아요? successUrl에 요청이 들어오면 바로 이 컨트롤러 로직이 실행되도록 해주시기 바랍니다.
Handyman
HandymanOP13mo ago
아 그럼 api를 나눠서 진행해야하는건가요?
Ayaan이안
Ayaan이안13mo ago
successUrl 발생 10분이 넘어가면 NOT_FOUND_PAYMENT_SESSION, 결제 시간이 만료되어 결제 진행 데이터가 존재하지 않습니다. 가 떨어집니다. 아니요, validation부터 승인 호출까지 모든 로직을 successUrl에서 처리해 주시면 됩니다. 아니면 validation, 승인 호출만 진행해 주시고 웹훅을 등록해서 DB처리를 해주셔야 합니다.
Handyman
HandymanOP13mo ago
알겠습니다
Ayaan이안
Ayaan이안13mo ago
저희 샘플 소스코드 일부 전달드립니다.
// server.js
// Node.js Express 환경

// POST /confirm -> successUrl 엔드포인트
app.post("/confirm", function (req, res) {
// 클라이언트에서 받은 JSON 요청 바디입니다.
const { paymentKey, orderId, amount } = req.body;

// 토스페이먼츠 API는 시크릿 키를 사용자 ID로 사용하고, 비밀번호는 사용하지 않습니다.
// 비밀번호가 없다는 것을 알리기 위해 시크릿 키 뒤에 콜론을 추가합니다.
const widgetSecretKey = "test_gsk_docs_OaPz8L5KdmQXkzRz3y47BMw6";
const encryptedSecretKey =
"Basic " + Buffer.from(widgetSecretKey + ":").toString("base64");

// 결제를 승인하면 결제수단에서 금액이 차감돼요.
got
.post("https://api.tosspayments.com/v1/payments/confirm", {
headers: {
Authorization: encryptedSecretKey,
"Content-Type": "application/json",
},
json: {
orderId: orderId,
amount: amount,
paymentKey: paymentKey,
},
responseType: "json",
})
.then(function (response) {
// 결제 성공 비즈니스 로직을 구현하세요.
// 가맹점 DB처리 포함
console.log(response.body);
res.status(response.statusCode).json(response.body)
})
.catch(function (error) {
// 결제 실패 비즈니스 로직을 구현하세요.
// 가맹점 DB처리 후 오류 얼럿 표시 등 포함
console.log(error.response.body);
res.status(error.response.statusCode).json(error.response.body)
});
});
// server.js
// Node.js Express 환경

// POST /confirm -> successUrl 엔드포인트
app.post("/confirm", function (req, res) {
// 클라이언트에서 받은 JSON 요청 바디입니다.
const { paymentKey, orderId, amount } = req.body;

// 토스페이먼츠 API는 시크릿 키를 사용자 ID로 사용하고, 비밀번호는 사용하지 않습니다.
// 비밀번호가 없다는 것을 알리기 위해 시크릿 키 뒤에 콜론을 추가합니다.
const widgetSecretKey = "test_gsk_docs_OaPz8L5KdmQXkzRz3y47BMw6";
const encryptedSecretKey =
"Basic " + Buffer.from(widgetSecretKey + ":").toString("base64");

// 결제를 승인하면 결제수단에서 금액이 차감돼요.
got
.post("https://api.tosspayments.com/v1/payments/confirm", {
headers: {
Authorization: encryptedSecretKey,
"Content-Type": "application/json",
},
json: {
orderId: orderId,
amount: amount,
paymentKey: paymentKey,
},
responseType: "json",
})
.then(function (response) {
// 결제 성공 비즈니스 로직을 구현하세요.
// 가맹점 DB처리 포함
console.log(response.body);
res.status(response.statusCode).json(response.body)
})
.catch(function (error) {
// 결제 실패 비즈니스 로직을 구현하세요.
// 가맹점 DB처리 후 오류 얼럿 표시 등 포함
console.log(error.response.body);
res.status(error.response.statusCode).json(error.response.body)
});
});
Handyman
HandymanOP13mo ago
Ayaan이안
Ayaan이안13mo ago
해당 소스코드는 https://developers.tosspayments.com/sandbox 에서도 확인이 가능하십니다.
토스페이먼츠 개발자센터
토스페이먼츠 결제 연동 문서, API, 키, 테스트 내역, 웹훅 등록 등 개발에 필요한 정보와 기능을 확인해 보세요. 결제 연동에 필요한 모든 개발자 도구를 제공해 드립니다.
Handyman
HandymanOP13mo ago
네 알겠습니다 감사합니다!
Ayaan이안
Ayaan이안13mo ago
@handyman2061 님 팔로우업: 어제 말씀주신대로 코드를 좀 손을 봤는데요 POST /payments/success?paymentKey=71DG90nOlP24xLea5zVAl1DpmqY0Dl3QAMYNwW6BvjZdyEmJ&amount=4600&orderId=0b156b4d-5580-493b-a13d-0e911b91cf6d 500 17.130 ms - 68 결제 서비스에서 오류 : ReferenceError: orderId is not defined at paymentSuccessService (/app/src/services/paymentServices.js:99:53) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async paymentSuccessController (/app/src/controllers/paymentControllers.js:20:5) 결제 성공 컨트롤러에서 오류: ReferenceError: orderId is not defined at paymentSuccessService (/app/src/services/paymentServices.js:99:53) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async paymentSuccessController (/app/src/controllers/paymentControllers.js:20:5) 계속이런식으로 애러가 발생해서 값이 들어갔나 확인좀 가능할까요? orderId입니다 0b156b4d-5580-493b-a13d-0e911b91cf6d 일단 오류를 보니 orderId라는 변수 지정이 안된건 같습니다 변수 지정이 제대로 되어있는지 봐주세요

Did you find this page helpful?