Threads API 활용 가이드: 앱 설정부터 OAuth, 게시 자동화까지

Threads 게시를 자동화하려고 Meta for Developers를 열면 가장 먼저 헷갈리는 부분이 있습니다. Threads API는 일반적인 서비스처럼 API Key 하나만 복사해 호출하는 구조가 아닙니다. 앱을 식별하는 Threads App ID와 App Secret, 사용자를 대신해 요청할 수 있는 Threads User Access Token, 그리고 기능별 권한 범위(scope)가 함께 필요합니다.

이 글은 Meta Threads API 공식 문서를 기준으로 앱 생성부터 OAuth, 장기 토큰, 텍스트 게시, 토큰 점검, 사용량 확인까지 실제 구현 순서대로 정리합니다. 예시는 Next.js 서버를 기준으로 하지만, 서버에서 비밀값과 토큰을 관리한다는 원칙은 다른 프레임워크에서도 같습니다.

먼저 바로잡을 내용

제공된 초안의 큰 흐름은 맞았습니다. 다만 현재 공식 문서와 비교하면 다음처럼 보완하는 편이 정확합니다.

  • Threads API의 중심 관리 화면은 Meta for Developers App Dashboard가 맞습니다.
  • 인증은 단일 API Key가 아니라 Threads App ID + Threads App Secret + 사용자 액세스 토큰 조합입니다.
  • 최신 공식 예제는 graph.threads.com을 사용합니다. 공식 개요에는 graph.threads.net도 지원된다고 명시되어 있지만, 새 구현에서는 문서 예제와 같은 .com 호스트를 사용하는 편이 이해하기 쉽습니다.
  • 단기 액세스 토큰은 1시간, 장기 액세스 토큰은 60일 동안 유효합니다. 장기 토큰은 발급 후 24시간이 지난 시점부터 만료 전까지 갱신할 수 있습니다.
  • Graph API Explorer는 테스트 단계에서 토큰과 권한을 시험하는 용도로 사용할 수 있습니다. 실제 서비스의 OAuth 흐름과 안전한 토큰 저장을 대신하지는 않습니다.
  • 앱 역할이 없는 일반 사용자의 데이터에 접근하려면 필요한 권한에 대한 App Review와 공개 상태가 필요합니다. 본인 계정과 Threads 테스터 계정만 다루는 개발 단계는 범위가 다릅니다.

Threads API에서 사용하는 세 가지 인증 값

항목용도확인·발급 위치
Threads App IDOAuth와 API가 어떤 앱의 요청인지 식별App Dashboard의 Threads 설정 또는 App settings → Basic
Threads App Secret인증 코드를 토큰으로 교환하고 장기 토큰을 발급할 때 서버 인증App Dashboard의 Threads 설정 또는 App settings → Basic
Threads User Access Token특정 Threads 사용자를 대신해 API 호출OAuth 인증 흐름 또는 개발용 도구

App Secret은 앱 자체의 비밀값이고, User Access Token은 사용자와 앱의 권한 관계를 나타냅니다. 둘은 서로 대체할 수 없습니다. Threads API 시작하기에서도 Threads 구현에는 Threads 전용 App ID와 App Secret을 사용하도록 안내합니다.

1. Meta 앱과 Threads Use Case 만들기

  1. Meta for Developers에 로그인합니다.
  2. My Apps → Create App으로 이동합니다.
  3. 앱 생성 과정에서 Threads API Use Case를 선택합니다.
  4. Use cases에서 필요한 Threads 권한을 추가합니다.
  5. Settings에서 OAuth 리디렉션 URI, 승인 취소 콜백 URL, 데이터 삭제 요청 URL을 등록합니다.
  6. 개발에 사용할 계정을 Threads Tester로 추가하고 Threads에서 초대를 수락합니다.

대시보드 구조는 UI 개편에 따라 메뉴 이름이 조금 달라질 수 있습니다. 최신 절차는 Threads API 사용 사례 설정 가이드에서 확인할 수 있습니다.

Meta for Developers
└─ My Apps
   └─ 내 앱
      ├─ Use cases
      │  └─ Threads API
      │     ├─ Permissions
      │     └─ Settings
      ├─ App settings
      │  └─ Basic
      └─ App roles
         └─ Threads Testers

2. 필요한 권한을 최소한으로 선택하기

모든 Threads API 호출에는 threads_basic이 필요합니다. 그 밖의 권한은 기능별로 추가합니다.

하고 싶은 일필요한 권한
기본 프로필 조회threads_basic
게시물 발행threads_basic, threads_content_publish
답글 읽기threads_basic, threads_read_replies
답글 관리threads_basic, threads_manage_replies
인사이트 조회threads_basic, threads_manage_insights
키워드 검색threads_basic, threads_keyword_search

처음부터 모든 권한을 요청하지 말고 실제 기능에 필요한 범위만 선택하는 것이 좋습니다. 본인과 테스터 계정으로 개발할 때는 테스트가 가능하지만, 앱 역할이 없는 일반 사용자에게 기능을 제공하려면 해당 권한의 Advanced Access 승인과 App Review가 필요할 수 있습니다.

3. OAuth로 사용자 토큰 발급하기

전체 인증 흐름은 다음과 같습니다.

Threads App ID + Redirect URI + Scope

        Threads 사용자 동의

       Authorization Code
                ↓ 서버에서 교환
    Short-lived Access Token (1시간)
                ↓ 서버에서 교환
     Long-lived Access Token (60일)
                ↓ 만료 전 갱신
        다시 60일 동안 유효

사용자를 인증 화면으로 보내기

사용자를 다음 URL로 이동시킵니다. state는 로그인 요청과 콜백을 연결하고 CSRF 공격을 막기 위해 반드시 검증하는 편이 좋습니다.

https://threads.com/oauth/authorize
  ?client_id=<THREADS_APP_ID>
  &redirect_uri=<REDIRECT_URI>
  &scope=threads_basic,threads_content_publish
  &response_type=code
  &state=<RANDOM_STATE>

등록한 Redirect URI와 요청의 redirect_uri는 끝의 슬래시까지 정확히 일치해야 합니다. 인증이 성공하면 Meta가 code를 쿼리 파라미터로 전달합니다. 이 인증 코드는 1시간 동안 유효하며 한 번만 사용할 수 있습니다.

인증 코드를 단기 토큰으로 교환하기

이 요청에는 App Secret이 포함되므로 브라우저가 아니라 서버에서 실행해야 합니다.

curl -X POST \
  https://graph.threads.com/oauth/access_token \
  -F client_id="$THREADS_APP_ID" \
  -F client_secret="$THREADS_APP_SECRET" \
  -F grant_type=authorization_code \
  -F redirect_uri="$THREADS_REDIRECT_URI" \
  -F code="$AUTHORIZATION_CODE"

성공하면 단기 access_token과 앱 범위 user_id가 반환됩니다. 자세한 요청 매개변수는 액세스 토큰과 권한 가져오기에서 확인할 수 있습니다.

단기 토큰을 장기 토큰으로 교환하기

만료되지 않은 단기 토큰을 60일짜리 장기 토큰으로 교환합니다.

curl -G https://graph.threads.com/access_token \
  --data-urlencode grant_type=th_exchange_token \
  --data-urlencode client_secret="$THREADS_APP_SECRET" \
  --data-urlencode access_token="$SHORT_LIVED_ACCESS_TOKEN"

장기 토큰은 발급 후 24시간이 지난 시점부터 만료되기 전까지 갱신할 수 있습니다.

curl -G https://graph.threads.com/refresh_access_token \
  --data-urlencode grant_type=th_refresh_token \
  --data-urlencode access_token="$LONG_LIVED_ACCESS_TOKEN"

갱신하면 갱신 시점부터 다시 60일 동안 유효합니다. 만료된 토큰은 갱신할 수 없으므로 만료 전에 처리하는 작업이 필요합니다. 조건과 제한은 장기 액세스 토큰 공식 가이드를 기준으로 구현해야 합니다.

4. Next.js 서버에 비밀값 보관하기

THREADS_APP_ID=...
THREADS_APP_SECRET=...
THREADS_REDIRECT_URI=https://example.com/api/auth/threads/callback

THREADS_APP_SECRET이나 장기 Access Token에 NEXT_PUBLIC_ 접두사를 붙이면 안 됩니다. React 컴포넌트, 브라우저 번들, 모바일 앱 바이너리에도 넣지 않습니다.

권장 구조는 다음과 같습니다.

Browser
  └─ OAuth 동의와 콜백

Next.js Route Handler
  ├─ state 검증
  ├─ code → short-lived token
  ├─ short-lived → long-lived token
  └─ 암호화 저장

Database / Secret Storage

https://graph.threads.com

여러 사용자를 지원한다면 토큰을 사용자 레코드와 연결하고, 평문 대신 암호화해 저장하며, 만료 시점과 부여된 scope도 함께 기록하는 편이 좋습니다. 로그에는 토큰 전체를 남기지 마세요.

5. 텍스트 게시물 발행하기

Threads의 단일 게시물 발행은 컨테이너 생성게시의 두 단계로 이루어집니다. Threads 게시물 만들기 공식 문서의 기본 흐름입니다.

const THREADS_API = 'https://graph.threads.com/v1.0';

type ThreadsContainerResponse = { id: string };

export async function publishThreadsText({
  userId,
  accessToken,
  text,
}: {
  userId: string;
  accessToken: string;
  text: string;
}) {
  const createBody = new URLSearchParams({
    media_type: 'TEXT',
    text,
    access_token: accessToken,
  });

  const createResponse = await fetch(`${THREADS_API}/${userId}/threads`, {
    method: 'POST',
    body: createBody,
  });

  if (!createResponse.ok) {
    throw new Error(`Threads container creation failed: ${createResponse.status}`);
  }

  const container = (await createResponse.json()) as ThreadsContainerResponse;

  const publishBody = new URLSearchParams({
    creation_id: container.id,
    access_token: accessToken,
  });

  const publishResponse = await fetch(
    `${THREADS_API}/${userId}/threads_publish`,
    { method: 'POST', body: publishBody },
  );

  if (!publishResponse.ok) {
    throw new Error(`Threads publishing failed: ${publishResponse.status}`);
  }

  return publishResponse.json() as Promise<{ id: string }>;
}

텍스트 게시물은 500자로 제한됩니다. 이미지나 동영상 게시물은 media_typeimage_url 또는 video_url을 사용하며, Meta 서버가 미디어를 가져갈 수 있도록 URL이 외부에서 접근 가능해야 합니다. 미디어는 처리 시간이 필요하므로 상태를 확인한 뒤 게시하는 방식이 안전합니다.

6. 토큰 상태 디버깅하기

Access Token Debugger를 사용하거나 /debug_token 엔드포인트를 호출할 수 있습니다.

curl -G https://graph.threads.com/v1.0/debug_token \
  --data-urlencode access_token="$THREADS_TESTER_ACCESS_TOKEN" \
  --data-urlencode input_token="$TOKEN_TO_INSPECT"

여기서 다음 정보를 확인할 수 있습니다.

is_valid
issued_at
expires_at
data_access_expires_at
user_id
scopes
application

중요한 점은 access_token과 검사 대상인 input_token이 같은 앱에 연결되어 있어야 한다는 것입니다. 자세한 조건은 Threads 토큰 디버깅 가이드에 나와 있습니다.

7. 게시 한도와 검색 한도 확인하기

프로필은 API를 통해 연속 24시간 동안 최대 250개의 게시물을 발행할 수 있으며, 슬라이드는 한 개의 게시물로 계산됩니다. 현재 사용량은 다음 엔드포인트로 확인합니다.

curl -G \
  "https://graph.threads.com/v1.0/$THREADS_USER_ID/threads_publishing_limit" \
  --data-urlencode fields=quota_usage,config \
  --data-urlencode access_token="$THREADS_ACCESS_TOKEN"

응답의 quota_usage는 최근 24시간의 게시 수, config는 전체 한도와 기간을 보여줍니다. 자세한 제한은 Threads API 사용 제한User 엔드포인트 레퍼런스를 함께 확인하세요.

Keyword Search API는 사용자 기준 연속 24시간 동안 최대 2,200개의 쿼리를 허용합니다. 이 한도는 여러 앱에서 같은 사용자를 사용해도 합산되며, 같은 키워드를 반복해도 차감됩니다. 공개 게시물 검색에는 threads_keyword_search 권한 승인도 필요합니다.

8. 개발과 운영을 구분하는 체크리스트

개발 단계

  • Threads Tester 초대를 보내고 Threads에서 수락했는지 확인합니다.
  • Redirect URI가 등록값과 정확히 같은지 확인합니다.
  • threads_basic과 필요한 최소 권한만 요청합니다.
  • Graph API Explorer와 본인·테스터 계정으로 호출을 검증합니다.
  • 토큰의 is_valid, expires_at, scopes를 확인합니다.

운영 단계

  • 일반 사용자가 필요하면 App Review와 Advanced Access 범위를 확인합니다.
  • App Secret과 토큰 교환 코드는 서버에서만 실행합니다.
  • 장기 토큰을 암호화해 저장하고 만료 전 갱신 작업을 둡니다.
  • OAuth state를 생성하고 콜백에서 일치 여부를 검증합니다.
  • 게시 재시도에는 지수 백오프를 적용하고 중복 게시를 막는 키를 둡니다.
  • 게시·검색 사용량과 API 오류 응답을 모니터링합니다.
  • 개인정보처리방침, 데이터 삭제 요청 URL, 승인 취소 콜백을 준비합니다.

자주 발생하는 오류

증상확인할 항목
OAuth 후 redirect_uri 오류등록 URI와 요청 URI의 프로토콜·경로·끝 슬래시가 완전히 같은지 확인
Matching code was not found or was already used인증 코드가 만료됐거나 이미 한 번 사용됐는지 확인
권한 오류토큰의 scopes, 테스터 역할, App Review·Advanced Access 상태 확인
이미지·동영상 컨테이너 실패미디어 URL이 로그인 없이 공개 접근 가능한지 확인
장기 토큰 갱신 실패발급 후 24시간이 지났는지, 아직 만료되지 않았는지 확인
게시 한도 오류threads_publishing_limitquota_usageconfig 확인

마무리

Threads API 통합의 핵심은 API 호출 코드보다 앱·사용자·권한·토큰의 관계를 분리해서 이해하는 것입니다. App Dashboard에서 Threads Use Case를 설정하고, OAuth로 사용자 동의를 얻고, 서버에서 코드를 장기 토큰으로 교환한 뒤, 컨테이너 생성과 게시의 두 단계를 호출하면 기본 게시 자동화가 완성됩니다.

처음에는 본인과 테스터 계정으로 최소 권한만 검증하세요. 이후 일반 사용자 지원, 토큰 갱신, 안전한 저장, 사용량 모니터링을 단계적으로 추가하면 운영 가능한 구조로 확장할 수 있습니다.