API Reference

Integrate fwd.page into your workflow with our RESTful API. Create links, manage OG tags, and retrieve analytics programmatically.

API Reference

Integrate fwd.page into your application with our RESTful API. Create short links, manage OG tags, and retrieve analytics programmatically.

Base URL

All API requests are made to:

https://api.fwd.page/v1

Authentication

Authenticate your requests using an API key in the Authorization header:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://api.fwd.page/v1/links

You can generate API keys from your dashboard under Settings > API Keys.

i

Free plans are limited to 100 API requests per day. Pro plans get 10,000 req/day, and Business plans have unlimited access.


Rate Limits

| Plan | Requests/Day | Burst Limit | |----------|-------------|--------------| | Free | 100 | 10 req/min | | Pro | 10,000 | 100 req/min | | Business | Unlimited | 1,000 req/min|

Rate limit headers are included in every response:

X-RateLimit-Limit: 10000
X-RateLimit-Remaining: 9987
X-RateLimit-Reset: 1700000000

Endpoints

Links

Create a Short Link

POST /v1/links

Create a new shortened URL with optional custom OG tags.

Request Body:

{
  "url": "https://example.com/my-long-article-url",
  "slug": "my-brand",
  "og": {
    "default": {
      "title": "My Article Title",
      "description": "A compelling description of the article.",
      "image": "https://example.com/og-image.png"
    },
    "facebook": {
      "title": "Facebook-Optimized Title",
      "description": "Description tailored for Facebook's preview card.",
      "image": "https://example.com/fb-og-image.png"
    },
    "twitter": {
      "title": "Twitter-Optimized Title",
      "description": "Shorter description for Twitter cards.",
      "image": "https://example.com/twitter-og-image.png",
      "card": "summary_large_image"
    },
    "kakao": {
      "title": "KakaoTalk Preview Title",
      "description": "Description for KakaoTalk sharing.",
      "image": "https://example.com/kakao-og-image.png"
    }
  }
}

Response (201 Created):

{
  "id": "lnk_abc123",
  "shortUrl": "https://sho.rt/my-brand",
  "originalUrl": "https://example.com/my-long-article-url",
  "slug": "my-brand",
  "og": { ... },
  "createdAt": "2026-03-21T00:00:00Z",
  "clicks": 0
}

List All Links

GET /v1/links

Query Parameters:

| Parameter | Type | Default | Description | |-----------|--------|---------|--------------------------| | page | number | 1 | Page number | | limit | number | 20 | Items per page (max 100) | | search | string | β€” | Filter by slug or URL | | sort | string | created | Sort by created, clicks, or slug |

Response (200 OK):

{
  "data": [
    {
      "id": "lnk_abc123",
      "shortUrl": "https://sho.rt/my-brand",
      "originalUrl": "https://example.com/...",
      "clicks": 1234,
      "createdAt": "2026-03-21T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 142,
    "totalPages": 8
  }
}

Get Link Details

GET /v1/links/:id

Returns full link details including OG tag configuration.

Update a Link

PATCH /v1/links/:id

Update the destination URL, slug, or OG tags of an existing link.

Request Body (partial update):

{
  "og": {
    "twitter": {
      "title": "Updated Twitter Title"
    }
  }
}

Delete a Link

DELETE /v1/links/:id

Permanently deletes a link. This action cannot be undone.

Response (204 No Content)


Analytics

Get Link Analytics

GET /v1/links/:id/analytics

Query Parameters:

| Parameter | Type | Default | Description | |------------|--------|-----------|-------------------------------------| | period | string | 7d | Time period: 24h, 7d, 30d, 90d | | groupBy | string | day | Group by: hour, day, week |

Response (200 OK):

{
  "linkId": "lnk_abc123",
  "period": "7d",
  "totalClicks": 1234,
  "uniqueVisitors": 987,
  "timeSeries": [
    { "date": "2026-03-15", "clicks": 180, "unique": 145 },
    { "date": "2026-03-16", "clicks": 210, "unique": 168 }
  ],
  "referrers": [
    { "source": "twitter.com", "clicks": 456 },
    { "source": "facebook.com", "clicks": 312 }
  ],
  "countries": [
    { "code": "US", "clicks": 534 },
    { "code": "KR", "clicks": 287 }
  ],
  "devices": {
    "mobile": 678,
    "desktop": 489,
    "tablet": 67
  }
}

OG Tags

AI-Suggest OG Tags

POST /v1/og/suggest

Let our AI analyze a URL and suggest optimal OG tags for each platform.

Request Body:

{
  "url": "https://example.com/my-article",
  "platforms": ["facebook", "twitter", "kakao"]
}

Response (200 OK):

{
  "url": "https://example.com/my-article",
  "suggestions": {
    "facebook": {
      "title": "AI-suggested Facebook title",
      "description": "Optimized description for Facebook...",
      "image": "https://example.com/suggested-fb.png"
    },
    "twitter": {
      "title": "AI-suggested Twitter title",
      "description": "Concise description for Twitter...",
      "card": "summary_large_image"
    },
    "kakao": {
      "title": "AI-suggested KakaoTalk title",
      "description": "Description optimized for KakaoTalk..."
    }
  },
  "confidence": 0.92
}

Validate OG Tags

POST /v1/og/validate

Check if your OG tags meet platform requirements and best practices.

Request Body:

{
  "og": {
    "title": "My Title",
    "description": "My description...",
    "image": "https://example.com/image.png"
  },
  "platform": "twitter"
}

Response (200 OK):

{
  "valid": true,
  "warnings": [
    {
      "field": "description",
      "message": "Description is 180 characters. Twitter truncates at 200."
    }
  ],
  "suggestions": [
    {
      "field": "image",
      "message": "Consider using 1200x628px for optimal Twitter card display."
    }
  ]
}

Domains

List Custom Domains

GET /v1/domains

Add a Custom Domain

POST /v1/domains

Request Body:

{
  "domain": "go.yourbrand.com"
}

Verify Domain

POST /v1/domains/:id/verify

Triggers DNS verification for a custom domain.


Webhooks

Configure webhooks to receive real-time notifications when events occur.

Supported Events

| Event | Description | |------------------------|--------------------------------------| | link.created | A new link was created | | link.clicked | A link was clicked | | link.threshold | Click count exceeded a threshold | | domain.verified | Custom domain verification completed |

Webhook Payload

{
  "event": "link.clicked",
  "timestamp": "2026-03-21T12:00:00Z",
  "data": {
    "linkId": "lnk_abc123",
    "shortUrl": "https://sho.rt/my-brand",
    "referrer": "twitter.com",
    "country": "US",
    "device": "mobile"
  }
}

Error Handling

All errors follow a consistent format:

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "You have exceeded the rate limit for your plan.",
    "status": 429
  }
}

Common Error Codes

| Status | Code | Description | |--------|-----------------------|------------------------------------| | 400 | INVALID_REQUEST | Malformed request body | | 401 | UNAUTHORIZED | Missing or invalid API key | | 403 | FORBIDDEN | Insufficient plan permissions | | 404 | NOT_FOUND | Resource not found | | 409 | SLUG_CONFLICT | Custom slug already in use | | 429 | RATE_LIMIT_EXCEEDED | Rate limit exceeded | | 500 | INTERNAL_ERROR | Internal server error |


SDKs & Libraries

Official SDKs are coming soon for:

  • JavaScript/TypeScript β€” npm install @fwdpage/sdk
  • Python β€” pip install fwdpage-sdk
  • Go β€” go get github.com/fwdpage/go-sdk
i

In the meantime, you can use any HTTP client to interact with the API. All endpoints accept and return JSON.