API
Manage your blogs and posts programmatically.
Overview
The ULTRV API is a REST API that lets you create and manage blogs, publish posts, and update settings — all with a simple API key. Built for developers, scripts, and mobile apps.
Base URL: https://app.ultrv.com/api/v1
Authentication
Every request requires an API key sent as a Bearer token. You can find your API key in your account settings.
Authorization: Bearer ultrv_your_api_key_here Keep your API key secret. If compromised, regenerate it from your settings page.
Quick Start
List your blogs
curl -H "Authorization: Bearer $API_KEY" \
https://app.ultrv.com/api/v1/blogs Create a post
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"My Post","slug":"my-post","content":"<p>Hello world</p>","status":"draft"}' \
https://app.ultrv.com/api/v1/blogs/my-blog/posts Create a post with image upload
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-F "title=My Post" \
-F "slug=my-post" \
-F "content=<p>Hello world</p>" \
-F "status=draft" \
-F "featured_image_file=@/path/to/image.jpg" \
https://app.ultrv.com/api/v1/blogs/my-blog/posts Publish a post
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
https://app.ultrv.com/api/v1/blogs/my-blog/posts/42/publish Endpoints
Blogs
| Method | Path | Description |
|---|---|---|
GET | /blogs | List all your blogs |
POST | /blogs | Create a new blog |
GET | /blogs/{slug} | Get a blog |
PUT | /blogs/{slug} | Update a blog's settings |
DELETE | /blogs/{slug} | Delete a blog |
Posts
| Method | Path | Description |
|---|---|---|
GET | /blogs/{slug}/posts | List posts (filter with ?status=published) |
POST | /blogs/{slug}/posts | Create a post |
GET | /blogs/{slug}/posts/{id} | Get a post |
PUT | /blogs/{slug}/posts/{id} | Update a post |
DELETE | /blogs/{slug}/posts/{id} | Delete a post |
POST | /blogs/{slug}/posts/{id}/publish | Publish a post |
POST | /blogs/{slug}/posts/{id}/unpublish | Unpublish a post (back to draft) |
All paths are relative to /api/v1. Blogs are identified by slug, posts by numeric ID.
Post Fields
Fields accepted when creating or updating a post.
| Field | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Post title (max 255 characters) |
| slug | string | Yes | URL slug. Lowercase alphanumeric with hyphens (e.g. my-first-post). Must be unique within the blog. |
| content | string | No | Post body as HTML. Sanitized on the server. |
| excerpt | string | No | Short summary shown in post listings (max 1000 characters) |
| status | string | No | draft or published. You can also use the /publish and /unpublish endpoints. |
| tags | string[] | No | Array of tag names. Tags are created automatically if they don't exist. Replaces all existing tags on update. |
| featured_image | string | No | URL for the featured image (max 255 characters). Cannot be used with featured_image_file. |
| featured_image_file | file | No | Image upload via multipart form data. JPEG, PNG, GIF, or WebP, max 10 MB. Cannot be used with featured_image. |
Example: create a post with tags and excerpt
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Getting Started with ULTRV",
"slug": "getting-started",
"excerpt": "A quick guide to setting up your blog.",
"content": "<p>Welcome to ULTRV...</p>",
"tags": ["tutorial", "getting-started"],
"status": "draft"
}' \
https://app.ultrv.com/api/v1/blogs/my-blog/posts Example response
{
"data": {
"id": 1,
"title": "Getting Started with ULTRV",
"slug": "getting-started",
"excerpt": "A quick guide to setting up your blog.",
"content": "<p>Welcome to ULTRV...</p>",
"featured_image": null,
"status": "draft",
"published_at": null,
"tags": [
{ "id": 1, "name": "tutorial", "slug": "tutorial" },
{ "id": 2, "name": "getting-started", "slug": "getting-started" }
],
"created_at": "2026-02-26T12:00:00+00:00",
"updated_at": "2026-02-26T12:00:00+00:00"
}
} Blog Fields
Fields accepted when creating or updating a blog.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Blog display name (max 255 characters) |
| slug | string | Yes | URL slug. Lowercase alphanumeric with hyphens. Must be unique. |
| author_name | string | Yes | Author name displayed on the blog (max 255 characters) |
| description | string | No | Blog description (max 1000 characters) |
| discoverable | boolean | No | Whether the blog appears in the explore directory |
| custom_domain | string | No | Custom domain for the blog (update only) |
| theme | string | No | Blog theme identifier (update only) |
| meta_title | string | No | Custom SEO title (max 255 characters, update only) |
| meta_description | string | No | Custom SEO description (max 1000 characters, update only) |
| og_image | string | No | Social sharing image URL (update only) |
| language | string | No | Language code, e.g. en or en-US (update only) |
Example response
{
"data": {
"id": 1,
"name": "My Blog",
"slug": "my-blog",
"description": "A blog about things.",
"author_name": "Jane Doe",
"custom_domain": null,
"discoverable": true,
"theme": "default",
"meta_title": null,
"meta_description": null,
"og_image": null,
"language": "en",
"canonical_url": "https://my-blog.ultrv.com",
"created_at": "2026-01-15T08:00:00+00:00",
"updated_at": "2026-02-20T14:30:00+00:00"
}
} Image Uploads
You can upload featured images when creating or updating posts using the featured_image_file field with multipart form data.
Supported formats
- JPEG, PNG, GIF, WebP
- Maximum file size: 10 MB
Two ways to set featured images
1. Upload a file — Use featured_image_file with multipart/form-data:
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-F "title=My Post" \
-F "featured_image_file=@/path/to/image.jpg" \
https://app.ultrv.com/api/v1/blogs/my-blog/posts 2. Reference an existing URL — Use featured_image with JSON:
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"My Post","featured_image":"https://example.com/image.jpg"}' \
https://app.ultrv.com/api/v1/blogs/my-blog/posts Note: You cannot use both featured_image and featured_image_file in the same request.
Rate Limits
The API is rate-limited to 60 requests per minute per API key. Rate limit headers are included in every response:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
Retry-After: 30 # (only when rate limited) Errors
The API uses standard HTTP status codes. Error responses include a message field and optionally an errors object for validation failures:
{
"message": "The slug has already been taken.",
"errors": {
"slug": ["The slug has already been taken."]
}
} | Status | Meaning |
|---|---|
401 | Missing or invalid API key |
403 | Not authorized to access this resource |
404 | Resource not found |
422 | Validation error |
429 | Rate limit exceeded |
Pagination
List endpoints return paginated results (20 items per page). Use ?page=2 to navigate. Response metadata includes:
{
"data": [...],
"links": {
"first": "...?page=1",
"last": "...?page=5",
"prev": null,
"next": "...?page=2"
},
"meta": {
"current_page": 1,
"last_page": 5,
"per_page": 20,
"total": 100
}
}