API

토큰 발급 및 연동

작성일 2026.11.13 | 수정일 2026.11.13

발급 방식

토큰을 만들 때 발급 방식을 고릅니다. 만든 뒤에는 바꿀 수 없습니다.

  • Google Apps Script: 스크립트에서 승인 주소를 열어 승인하면 토큰을 받습니다. 토큰이 사람 손을 거치지 않고 스크립트 저장소에만 남습니다. 스크립트 ID 를 넣어 만들고, redirect URI 는 그 ID 로 정해집니다.

  • 콘솔 발급: 승인 화면을 띄울 수 없는 서버리스용입니다. 만들 때 refresh token 을 한 번만 보여 줍니다. 잃어버리면 콘솔에서 다시 받아야 합니다.

토큰 만들기

  1. 콘솔 개발 > OAuth2 에서 새로운 토큰 을 누릅니다.

  2. 발급 방식을 고릅니다.

  3. 권한을 고릅니다. 내 역할로 고를 수 있는 것만 고를 수 있습니다.

  4. Apps Script 면 스크립트 ID 와 메모를 넣습니다. 메모는 목록과 알림에서 토큰을 구분하는 이름입니다.

  5. 2차 인증을 마치면 토큰이 만들어집니다.

계정마다 토큰은 20개까지 만들 수 있습니다(구성원 전체 합계). 권한과 발급 방식은 만든 뒤 바꿀 수 없습니다. 다른 권한이 필요하면 새로 만듭니다. 메모는 목록의 정보 · 메모 수정 에서 바꿀 수 있습니다.

Google Apps Script 에서 쓰기

토큰을 만들면 연동 설정 창이 4단계로 안내합니다. 목록의 설정 보기 에서 다시 열 수 있습니다.

1. OAuth2 라이브러리 추가

Google 이 공개한 Apps Script OAuth2 라이브러리를 씁니다. 편집기 왼쪽 라이브러리 옆 + 를 누르고 아래 스크립트 ID 로 찾아 가장 큰 버전을 추가합니다. 식별자는 OAuth2 그대로 둡니다. PKCE(generateCodeVerifier)를 지원하는 판이어야 합니다.

1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF

2. 코드 붙여 넣기

설정 창의 코드는 client_id 와 주소가 이미 들어 있어 그대로 붙여 넣으면 됩니다. 모양은 아래와 같습니다. authorize 를 맨 위에 둔 것은 편집기가 첫 함수를 실행 대상으로 고르기 때문입니다.

function authorize() {
  const service = getSolapiService()
  if (service.hasAccess()) return console.log('이미 승인했습니다.')
  console.log(service.getAuthorizationUrl())
}

function callSolapi() {
  const service = getSolapiService()
  if (!service.hasAccess()) return console.log('먼저 authorize 를 실행해 주세요.')
  const res = UrlFetchApp.fetch('https://api.solapi.com/cash/v1/balance', {
    headers: { Authorization: 'Bearer ' + service.getAccessToken() },
    muteHttpExceptions: true
  })
  console.log(res.getResponseCode() + ' ' + res.getContentText())
}

function resetSolapi() {
  getSolapiService().reset()
}

function getSolapiService() {
  return OAuth2.createService('solapi')
    .setAuthorizationBaseUrl('https://api.solapi.com/oauth2/v1/authorize')
    .setTokenUrl('https://api.solapi.com/oauth2/v1/access_token')
    .setClientId('CID…')
    // client secret 이 없어 라이브러리가 싣는 값을 지웁니다.
    .setTokenPayloadHandler(function (payload) {
      delete payload.client_secret
      return payload
    })
    .generateCodeVerifier()
    .setScope('personal')
    .setCallbackFunction('authCallback')
    .setPropertyStore(PropertiesService.getUserProperties())
    .setLock(LockService.getUserLock())
}

function authCallback(request) {
  const ok = getSolapiService().handleCallback(request)
  return HtmlService.createHtmlOutput(ok ? '승인했습니다. 이 창을 닫으세요.' : '승인하지 못했습니다.')
}

client_secret 을 지우는 줄은 빼면 안 됩니다. 개인 연동은 secret 이 없는 공개 클라이언트라, 라이브러리가 빈 secret 을 실으면 토큰을 받지 못합니다.

3. 승인하기

  1. 함수 목록에서 authorize 를 골라 실행합니다.

  2. 처음이면 Google 의 권한 검토 창이 뜹니다. 허용합니다. "확인되지 않은 앱" 이 보이면 고급 → (안전하지 않음)으로 이동 을 누릅니다. 직접 만든 스크립트라서 나오는 안내입니다.

  3. 실행 로그의 https://api.solapi.com/oauth2/v1/authorize?… 주소를 브라우저에서 엽니다.

  4. 토큰을 만든 회원으로 SOLAPI 에 로그인돼 있으면 승인 화면 없이 바로 "승인했습니다" 가 뜹니다.

authCallback 은 직접 실행하지 않습니다. 4번에서 돌아올 때 Google 이 부르는 함수라, 편집기에서 실행하면 Cannot read properties of undefined (reading 'parameter') 오류가 납니다.

4. 확인하기

callSolapi 를 실행해 실행 로그에 200 이 나오면 끝입니다. 예시 호출은 토큰의 조회 권한에 맞춰 잔액 조회, 메시지 목록 조회, 발신번호 조회 가운데 하나로 들어갑니다.

서버리스에서 쓰기 (콘솔 발급)

콘솔에서 받은 refresh token 을 서버 비밀 저장소에 넣고, 필요할 때 access token 으로 바꿔 씁니다.

토큰 갱신 요청

POST https://api.solapi.com/oauth2/v1/access_token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=solapi_prt_…

client_id 와 client_secret 은 보내지 않습니다. 응답은 아래 모양입니다.

{
  "access_token": "…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "solapi_prt_…",
  "scope": "message:send cash:read"
}

API 를 부를 때는 Authorization: Bearer <access_token> 을 싣습니다.

새 refresh token 을 반드시 저장합니다

refresh token 은 쓸 때마다 새 값으로 바뀝니다(회전). 응답의 refresh_token 을 저장소에 바로 덮어써야 합니다. 이전 값을 다시 쓰면 탈취로 보고 그 토큰을 모두 폐기합니다. 그러면 콘솔에서 토큰을 다시 받아야 합니다.

// Node 18 이상. loadRefreshToken · saveRefreshToken 은 쓰는 비밀 저장소에 맞게 만듭니다.
async function solapiAccessToken() {
  const res = await fetch('https://api.solapi.com/oauth2/v1/access_token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'refresh_token',
      refresh_token: await loadRefreshToken()
    })
  })
  const body = await res.json()
  if (!res.ok) throw new Error(`${body.errorCode}: ${body.errorMessage}`)
  await saveRefreshToken(body.refresh_token)
  return body.access_token
}

access token 은 1시간 동안 쓸 수 있습니다. 매 요청마다 갱신하지 말고, 받은 access token 을 만료 전까지 다시 쓰는 편이 좋습니다.

토큰 수명과 재승인

  • access token: 1시간

  • refresh token: 쓸 때마다 바뀝니다.

  • 미사용 만료: 마지막으로 쓴 날부터 30일 동안 쓰지 않으면 만료됩니다.

  • 승인 만료: 처음 승인(콘솔 발급은 발급)한 날부터 90일이 지나면 만료됩니다.

만료되면 사람이 다시 승인해야 합니다. 스크립트가 대신할 수 없습니다.

  • Apps Script: authorize 를 다시 실행해 주소를 열고 승인합니다. 새 refresh token 은 라이브러리가 저장소에 알아서 넣습니다. 라이브러리의 hasAccess() 는 갱신에 실패하면 false 를 돌려주므로, 예시 코드에서는 callSolapi 가 "먼저 authorize 를 실행해 주세요." 를 남깁니다.

  • 콘솔 발급: 콘솔 목록에서 토큰 다시 받기 를 누르고, 쓰던 곳의 값을 새 refresh token 으로 바꿉니다. 받는 순간 이전 토큰은 폐기됩니다.

목록의 상태 칸은 만료 7일 전부터 "곧 만료" 로 바뀝니다.

알림

계정 OWNER 전원과 토큰을 만든 회원에게 메일이 발송됩니다. 중요 알림이라 수신거부할 수 없습니다.

상황

제목

문자

토큰을 만들었을 때

토큰이 만들어졌습니다

없음

Apps Script 에서 승인했을 때

연동이 승인되었습니다

없음

콘솔에서 다시 받았을 때

토큰이 다시 발급되었습니다

없음

폐기했을 때

토큰이 폐기되었습니다

없음

탈취가 감지됐을 때

토큰 탈취가 감지되어 폐기되었습니다

함께 보냄

Apps Script 승인 만료 7일 · 1일 전

연동을 N일 안에 다시 승인해야 합니다

1일 전만

콘솔 발급 만료 7일 · 1일 전

토큰을 N일 안에 다시 받아야 합니다

1일 전만

미사용 만료 7일 · 1일 전

30일 동안 쓰지 않은 토큰이 곧 만료됩니다

1일 전만

만료 예고는 한국 시각 10시에서 18시 사이에 발송됩니다.

오류 코드

토큰 갱신 · 승인에서 나는 오류입니다. 응답 본문의 errorCode 로 구분합니다.

errorCode

상태

뜻

할 일

PersonalTokenExpired

400

30일 동안 쓰지 않아 만료

다시 승인 또는 다시 받기

PersonalReauthorizationRequired

400

승인 90일 지남

다시 승인 또는 다시 받기

PersonalTokenReused

400

바뀐 refresh token 을 다시 씀, 모두 폐기

다시 승인 또는 다시 받기, 새는 곳 확인

PersonalIntegrationRevoked

400

폐기된 토큰

새로 만들기

InvalidRefreshToken

400

모르는 refresh token

저장한 값 확인

PkceRequired

400

승인 요청에 code_challenge(S256) 없음

라이브러리 판 확인, generateCodeVerifier 확인

ScopeNotAllowed

403

내 역할로 고를 수 없는 권한

만들 때 권한 다시 고르기

PersonalIntegrationLimit

400

계정당 20개를 넘음

쓰지 않는 토큰 폐기

API 를 부를 때 401 이면 access token 이 만료됐거나 승인이 끝난 것이고, 403 이면 토큰에 없는 권한입니다.

주의할 점

  • refresh token 은 비밀번호처럼 다룹니다. 코드 · 저장소 · 로그에 남기지 않고 비밀 저장소에 둡니다. 새어 나갔다면 콘솔에서 바로 폐기합니다.

  • 콘솔 발급 refresh token 은 만들 때와 다시 받을 때 한 번만 볼 수 있습니다.

  • 승인은 토큰을 만든 회원만 할 수 있습니다. 다른 회원으로 로그인한 브라우저에서 승인 주소를 열면 승인되지 않습니다.