elliurl REST API

모든 엔드포인트는 HTTPS 위에서 동작하며, Bearer JWT 인증이 필요합니다. 모든 요청·응답 본문은 UTF-8 JSON입니다.

01 · 시작하기

elliurl 서비스 베이스 URL은 https://elliurl.com 입니다. 단축 URL 자체는 https://elliurl.kr/<code> 에서 서빙됩니다. 모든 API 요청은 브랜드 도메인 (elliurl.com) 아래 /api 경로로 보냅니다.

빠른 시작: 무료 가입 후 POST /api/shorten 에 JWT 인증과 함께 JSON을 보내면 즉시 단축 URL이 반환됩니다. 모든 API는 로그인이 필요합니다.

인증 방식

API 유형인증설명
사용자 APIJWTAuthorization: Bearer <token>

JWT 토큰 발급 방법

이메일로 가입 후 로그인하면 JWT 토큰이 발급됩니다. 유효기간 7일.

# 1. 회원가입
curl -X POST https://elliurl.com/api/auth/signup \
  -H "content-type: application/json" \
  -d '{"email": "you@example.com", "password": "mypassword"}'

# 응답에서 token 필드를 복사
# {"token": "eyJhbG...", "user": {"id": "...", "plan": "pro"}}

# 2. 이후 로그인 (토큰 만료 시)
curl -X POST https://elliurl.com/api/auth/login \
  -H "content-type: application/json" \
  -d '{"email": "you@example.com", "password": "mypassword"}'

# 3. 토큰 사용
curl https://elliurl.com/api/me \
  -H "Authorization: Bearer eyJhbG..."
Google 로그인도 지원합니다. 브라우저에서 /api/auth/google/start 접속 후 Google 인증 → 자동으로 JWT 발급 + 대시보드 리다이렉트.

02 · URL 단축 API

JWT 인증이 필요합니다. 플랜별 일일 호출 한도가 적용됩니다.

POST /api/shorten JWT

긴 URL을 받아서 elliurl.kr/<code> 단축 URL을 반환합니다. 생성된 링크는 계정에 자동 귀속됩니다.

요청 본문

targetstring필수. 단축할 원본 URL. http(s) 프로토콜만. 최대 2048자.
codestring커스텀 슬러그. 1~32자, [a-zA-Z0-9_-]. 생략 시 6자 nanoid 자동 생성.
titlestring관리용 제목. 최대 200자.

요청 예시

curl -X POST https://elliurl.com/api/shorten \
  -H "content-type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{"target":"https://ellilabs.com/blog/long-post"}'

응답 (201)

{
  "code":           "9fgGfh",
  "short_url":      "https://elliurl.kr/9fgGfh",
  "target":         "https://ellilabs.com/blog/long-post",
  "created_at":     1775901439,
  "scan_status":    "pending"
}
악성 URL 방어: 모든 요청은 Google Web Risk 블랙리스트를 즉시 조회합니다. 악성 판정 시 400 malicious_target을 반환하고 링크는 생성되지 않습니다. 이후 백그라운드에서 Cloudflare URL Scanner가 추가 검증하며, flagged 시 자동 비활성화됩니다.
GET /api/public/overview NO AUTH

프로덕션 실시간 통계(생성된 링크 수, 총 클릭, 국가 수, 최근 공개 링크 5건). KV 60초 캐시.

응답 (200)

{
  "total_links":  42,
  "total_clicks": 118,
  "countries":    3,
  "created_24h":  8,
  "recent": [
    { "code": "abc", "host": "ellilabs.com", "click_count": 5, "created_at": 1775900000 }
  ]
}

03 · 인증

이메일·비밀번호 또는 Google OAuth로 가입·로그인. 성공 시 JWT를 반환합니다.

POST /api/auth/signup NO AUTH

요청 본문

emailstring유효한 이메일.
passwordstring최소 8자, 최대 128자.

응답 (201)

{
  "token": "eyJhbGc...",
  "exp":   1776506564,
  "user": {
    "id":    "uuid",
    "email": "you@example.com",
    "plan":  "pro"
  }
}
Alpha 가입자 특혜: Alpha 기간 동안 가입하면 자동으로 plan_status = "alpha_grandfathered" 로 승급됩니다. 결제 시스템이 열린 뒤에도 Pro 월 ₩0 영구 유지.
POST /api/auth/login NO AUTH

로그인. signup과 동일한 응답 형태의 새 JWT를 반환합니다.

POST /api/auth/logout JWT

현재 JWT를 블랙리스트에 추가 (TTL = JWT 잔여 시간). 이후 해당 토큰은 401을 반환합니다.

GET /api/me JWT

현재 로그인한 사용자 정보.

{ "id": "uuid", "email": "you@example.com", "plan": "pro", "is_admin": false }

05 · 통계

GET /api/me/links/:code/stats JWT

특정 링크의 클릭 통계. 내가 소유한 링크만.

{
  "code": "abc",
  "summary": {
    "total":    42,
    "last_24h": 5,
    "last_7d":  18
  },
  "by_country": [{ "country": "KR", "n": 38 }],
  "by_device":  [{ "device":  "mobile", "n": 25 }]
}

06 · OG 오버라이드 — 카카오톡·슬랙 미리보기 A/B

elliurl의 핵심 차별점. 링크 생성 시 목적지 URL의 OG 태그가 서버사이드로 자동 fetch되어 D1에 캐시됩니다. PATCH /api/me/links/:code로 원하는 제목·설명·이미지로 덮어쓸 수 있고, 크롤러 UA (KakaoTalk, Slackbot, Twitterbot, facebookexternalhit 등)가 단축 URL을 방문하면 오버라이드된 메타가 반환됩니다. Bitly·TinyURL에서는 불가능한 동작.

사용 예: 같은 블로그 글을 elliurl.kr/a(커피 카피) 와 elliurl.kr/b(숫자 카피) 로 두 번 단축 → 각 링크의 og_title을 다르게 오버라이드 → 카카오톡 두 채널에 나눠 공유 → /api/me/links/:code/stats로 클릭률 비교.

07 · QR 코드

GET /qr/:code NO AUTH

단축 URL의 QR 코드 SVG. 512×512, error correction level M. 응답 헤더에 content-disposition: inline; filename="elliurl-:code.svg", KV 24h 캐시. 비활성 또는 미존재 코드는 404.

curl https://elliurl.com/qr/abc -o abc.svg

# HTML 임베드
<img src="https://elliurl.com/qr/abc" width="256" />

PNG가 필요하면 SVG를 브라우저 <canvas> 에 그려서 export 하거나 ImageMagick/rsvg 같은 도구로 로컬 변환하세요.

08 · 결제·플랜

GET /api/me/billing JWT

내 플랜·구독 상태.

{
  "plan":                   "pro",
  "plan_status":            "active",
  "plan_expires_at":        1778500000,
  "grandfathered":          false,
  "alpha_window_active":    true,
  "has_paid_subscription":  true
}

plan_status 값: free · alpha_grandfathered · active · past_due · cancelled · expired

POST /api/billing/toss/subscribe-init JWT

토스 정기결제 billing auth 초기화. 반환된 파라미터로 프론트엔드에서 TossPayments.requestBillingAuth('카드', {...})를 호출하세요.

POST /api/billing/lemonsqueezy/checkout JWT

해외 카드 결제용 LemonSqueezy checkout URL 생성.

POST /api/billing/toss/unsubscribe JWT

구독 해지. billing key를 제거하고 plan_status = "cancelled"로 전환. 현재 결제 주기 종료일까지는 Pro 기능 유지.

09 · 커스텀 도메인 (Pro)

Pro 플랜 유저는 자신의 도메인(go.yourbrand.com)을 elliurl에 연결해서 단축 링크를 자기 브랜드 도메인으로 서빙할 수 있습니다. Cloudflare for SaaS를 이용해 TLS 인증서가 자동 발급됩니다.

GET /api/me/custom-domains JWT

내가 등록한 커스텀 도메인 목록.

POST /api/me/custom-domains JWT

요청 본문

hostnamestring등록할 도메인. 예: go.ellilabs.com

응답의 instructions 필드에 DNS CNAME 설정 방법이 포함됩니다. CNAME 추가 후 Cloudflare가 소유권 확인 + TLS 인증서 발급까지 약 30초~5분.

GET /api/me/custom-domains/:id JWT

도메인 상태 조회. 호출 시 Cloudflare에서 최신 상태를 fresh fetch하여 DB에 반영합니다.

DELETE /api/me/custom-domains/:id JWT

도메인 등록 해제. Cloudflare에서도 함께 삭제됩니다.

10 · 에러·속도 제한

에러 응답 포맷

{
  "error": {
    "code":    "invalid_target",
    "message": "유효한 http(s) URL만 허용됩니다"
  }
}

주요 에러 코드

코드HTTP설명
invalid_target400스킴·형식 또는 내부 IP
invalid_code400슬러그 형식 위반
code_taken409슬러그 중복
malicious_target400Google Web Risk 차단
rate_limited429일일 한도 초과
free_link_quota402Free 플랜 월 50개 초과
unauthorized401JWT 누락·만료·블랙리스트
forbidden403관리자 권한 필요
not_found404리소스 없음
pro_required402Pro 플랜 전용 기능
domain_quota402커스텀 도메인 한도 초과

속도 제한

대상한도기준
로그인 POST /api/auth/login10/분IP 단위 sliding window
가입 POST /api/auth/signup5/분IP 단위 sliding window
JWT 사용자 API (Free)1,000/일유저 단위
JWT 사용자 API (Pro)10,000/일유저 단위
JWT 사용자 API (Business)100,000/일유저 단위
속도 제한 초과 시: 429 상태 코드가 반환됩니다. 자동화·배치 작업은 가입 후 JWT로 호출하세요.