Techtales.

API Documentation

v1https://techtales.vercel.app/api/v1

The TechTales REST API lets you programmatically access blogs, search content, and manage your account. All endpoints return JSON.

Last updated: March 01, 2026

/me

Access and manage the authenticated user's own account data.

GET/api/v1/me
Session or API Key

Returns the authenticated user's full profile data.

Sample Response

{
  "data": {
    "id": 1,
    "username": "The Don",
    "email": "thedon@example.com",
    "handle": "thedon",
    "role": "user",
    "picture": "https://res.cloudinary.com/example/image.jpg",
    "bio": "Just surfing the web",
    "skills": "TypeScript, Next.js",
    "branding": "#01142d",
    "socials": [],
    "preferences": {
      "cookies": true,
      "analytics": false,
      "email_notifications": false,
      "newsletter_subscription": false
    },
    "status": "ACTIVE",
    "email_verified": true,
    "auth_provider": "email",
    "keep_blogs_on_delete": false,
    "keep_comments_on_delete": false,
    "createdAt": "2024-01-15T10:00:00.000Z",
    "updatedAt": "2024-06-01T12:00:00.000Z"
  }
}
PATCH/api/v1/me
Session Only

Update the authenticated user's profile. Session only — API keys cannot update account details.

Request Body

ParameterTypeRequiredDescription
usernamestringOptionalDisplay name. Min 3, max 50 characters.
handlestringOptionalUnique handle. Min 3, max 50 characters.
biostring | nullOptionalShort biography. Max 500 characters.
skillsstring | nullOptionalSkills or tagline. Max 200 characters.
brandingstring | nullOptionalProfile accent color as a valid hex code e.g. #01142d.
picturestring | nullOptionalAvatar URL. Must be a valid URL.
keep_blogs_on_deletebooleanOptionalWhether to keep blogs if account is deleted.
keep_comments_on_deletebooleanOptionalWhether to keep comments if account is deleted.
preferencesobjectOptionalNotification and cookie preferences.
preferences.cookiesbooleanOptional
preferences.analyticsbooleanOptional
preferences.email_notificationsbooleanOptional
preferences.newsletter_subscriptionbooleanOptional

Important Notes

  • At least one field must be provided.
  • Returns 409 if username or handle is already taken.
  • Fields like role, email, password_digest, and auth_provider cannot be updated via this route.
DELETE/api/v1/me
Session or API Key

Account deletion is not available via the API. Returns a redirect to the security settings page.

Important Notes

  • Visit /me/settings#security to delete your account.

/me/blogs

Manage blogs belonging to the authenticated user.

GET/api/v1/me/blogs
Session or API Key

Returns a paginated list of all blogs for the authenticated user across all statuses.

Query Parameters

ParameterTypeRequiredDescription
page
e.g., 1
numberOptionalPage number. Defaults to 1.
limit
e.g., 15
numberOptionalResults per page. Min 1, max 50. Defaults to 15.
orderBy
e.g., views
stringOptionalSort field. One of createdAt, views, likes. Defaults to createdAt.
status
e.g., DRAFT
stringOptionalFilter by status. One of PUBLISHED, DRAFT, UNPUBLISHED, ARCHIVED.
from
e.g., 2024-01-01T00:00:00Z
stringOptionalFilter blogs created after this date. ISO 8601 format.
to
e.g., 2024-12-31T23:59:59Z
stringOptionalFilter blogs created before this date. ISO 8601 format.

Sample Response

{
  "data": [
    {
      "uuid": "75374219-c45c-43b5-8640-e50ca2e77874",
      "title": "How to Write Clean Code",
      "slug": "how-to-write-clean-code",
      "description": "Tips and best practices for writing clean code.",
      "tags": "javascript, programming",
      "status": "PUBLISHED",
      "likes": 12,
      "views": 1129,
      "reading_time": 6,
      "show_comments": true,
      "image": {
        "public_id": "tech-tales/cover-images/abc123",
        "secure_url": "https://res.cloudinary.com/example/image.jpg"
      },
      "path": "thedon/how-to-write-clean-code",
      "createdAt": "2024-10-24T12:34:19.557Z",
      "updatedAt": "2024-11-01T08:00:00.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 15,
    "total": 42,
    "totalPages": 3,
    "hasNextPage": true,
    "nextPage": 2
  }
}
POST/api/v1/me/blogs
Session or API Key

Creates a new blog. Always created as DRAFT. Body is optional — you can create a blank blog and fill it in the editor.

Request Body

ParameterTypeRequiredDescription
titlestring | nullOptionalBlog title. Min 3, max 200 characters.
descriptionstring | nullOptionalShort description. Max 500 characters.
tags
e.g., javascript, webdev
string | nullOptionalComma-separated tags. Max 200 characters.
show_commentsbooleanOptionalWhether to show comments. Defaults to true.

Important Notes

  • body, slug, path, image, and audio can only be set via the blog editor.
  • Blogs are always created with status DRAFT.
  • Returns the blog uuid — use this to open the editor at /write/:uuid.

/me/blogs/[id]

Read, update, or delete a specific blog by its integer ID.

GET/api/v1/me/blogs/:id
Session or API Key

Returns full metadata for a single blog belonging to the authenticated user.

Sample Response

{
  "data": {
    "uuid": "75374219-c45c-43b5-8640-e50ca2e77874",
    "title": "How to Write Clean Code",
    "slug": "how-to-write-clean-code",
    "description": "Tips and best practices.",
    "tags": "javascript, programming",
    "status": "PUBLISHED",
    "likes": 12,
    "views": 1129,
    "reading_time": 6,
    "show_comments": true,
    "audio": null,
    "image": {
      "public_id": "abc",
      "secure_url": "https://res.cloudinary.com/example/image.jpg"
    },
    "path": "thedon/how-to-write-clean-code",
    "createdAt": "2024-10-24T12:34:19.557Z",
    "updatedAt": "2024-11-01T08:00:00.000Z"
  }
}
PATCH/api/v1/me/blogs/:id
Session or API Key

Update allowed fields on a blog. Status transitions are restricted based on current status.

Request Body

ParameterTypeRequiredDescription
descriptionstring | nullOptionalShort description. Max 500 characters.
tagsstring | nullOptionalComma-separated tags. Max 200 characters.
show_commentsbooleanOptionalToggle comments on the blog.
audiostring | nullOptionalAudio URL. Must be a valid URL.
statusstringOptionalStatus transition. Restricted by current status — see notes.

Important Notes

  • PUBLISHED blogs can transition to: UNPUBLISHED, ARCHIVED.
  • UNPUBLISHED blogs can transition to: DRAFT, ARCHIVED.
  • DRAFT blogs cannot change status via the API — publish via the editor.
  • ARCHIVED blogs cannot be updated at all.
  • body, slug, path, and image remain editor-only fields.
DELETE/api/v1/me/blogs/:id
Session or API Key

Deletes or archives a blog depending on its current status.

Important Notes

  • DRAFT blogs are permanently deleted.
  • PUBLISHED and UNPUBLISHED blogs are archived (to preserve comments).
  • ARCHIVED blogs cannot be deleted — contact support.
  • Returns 200 with a message indicating whether the blog was deleted or archived.

/blogs

Public blog endpoints. No authentication required. Only returns PUBLISHED blogs.

GET/api/v1/blogs
Public

Returns a paginated list of all published blogs. Supports filtering by author handle, tags, date range, and sort order.

Query Parameters

ParameterTypeRequiredDescription
page
e.g., 1
numberOptionalPage number. Defaults to 1.
limit
e.g., 15
numberOptionalResults per page. Min 1, max 50. Defaults to 15.
orderBy
e.g., views
stringOptionalSort field. One of createdAt, views, likes.
author
e.g., thedon
stringOptionalFilter by author handle (not display name).
tags
e.g., tags=typescript&tags=nextjs
string[]OptionalFilter by one or more tags. Pass multiple times for AND matching.
from
e.g., 2024-01-01T00:00:00Z
stringOptionalISO 8601 start date filter.
to
e.g., 2024-12-31T23:59:59Z
stringOptionalISO 8601 end date filter.

Sample Response

{
  "data": [
    {
      "id": 58,
      "uuid": "75374219-c45c-43b5-8640-e50ca2e77874",
      "title": "How to Write Clean Code",
      "path": "thedon/how-to-write-clean-code",
      "tags": "javascript, webdev, programming",
      "description": "Tips and best practices for writing clean code.",
      "reading_time": 6,
      "createdAt": "2024-10-24T12:34:19.557Z",
      "views": 1129,
      "likes": 1,
      "image": {
        "public_id": "abc",
        "secure_url": "https://res.cloudinary.com/example/image.jpg"
      },
      "author": {
        "username": "The Don",
        "picture": "https://res.cloudinary.com/example/avatar.jpg"
      },
      "_count": {
        "comments": 4
      }
    }
  ],
  "meta": {
    "page": 1,
    "limit": 15,
    "total": 120,
    "totalPages": 8,
    "hasNextPage": true,
    "nextPage": 2
  }
}
GET/api/v1/blogs/:id/comments
Public

Returns paginated comments for a published blog, including responses. HTML is stripped from comment bodies.

Query Parameters

ParameterTypeRequiredDescription
page
e.g., 1
numberOptionalPage number. Defaults to 1.
limit
e.g., 15
numberOptionalResults per page. Min 1, max 50. Defaults to 15.

Sample Response

{
  "data": [
    {
      "id": 12,
      "body": "Let me know what you think about AI getting self-conscious.",
      "createdAt": "2024-11-01T09:00:00.000Z",
      "updatedAt": "2024-11-01T09:00:00.000Z",
      "author": {
        "username": "The Don",
        "handle": "thedon",
        "picture": "https://res.cloudinary.com/example/avatar.jpg"
      },
      "responses": [
        {
          "id": 5,
          "body": "Great point! I think it's a fascinating topic.",
          "createdAt": "2024-11-01T10:00:00.000Z",
          "updatedAt": "2024-11-01T10:00:00.000Z",
          "author": {
            "username": "Jane Dev",
            "handle": "janedev",
            "picture": null
          }
        }
      ]
    }
  ],
  "meta": {
    "page": 1,
    "limit": 15,
    "total": 8,
    "totalPages": 1,
    "hasNextPage": false,
    "nextPage": null
  }
}

Important Notes

  • Returns 404 if the blog does not exist or is not published.
  • Returns an empty data array if comments are disabled for the blog.
  • Only VISIBLE comments and responses are returned.
  • Comment and response bodies are returned as plain text — HTML tags are stripped.