Suture Platform API Reference
Base URL
Platform: https://api.suture.dev
Hub: https://hub.suture.dev
Self-hosted: configured via --addr flag
Authentication
All protected endpoints accept a JWT Bearer token in the Authorization header:
Authorization: Bearer <jwt_token>
Tokens are obtained via /auth/login or OAuth callbacks. Token expiry: 7 days.
All protected endpoints are rate-limited.
Endpoints
Health
GET /healthz
Health check endpoint.
Auth: None
Response: 200 OK
"ok"
Auth
POST /auth/register
Register a new account.
Auth: None
Request:
{
"email": "user@example.com",
"password": "at-least-8-chars",
"display_name": "Alice"
}
emailpassworddisplay_nameResponse: 201 Created
{
"token": "eyJ...",
"user": {
"user_id": "uuid",
"email": "user@example.com",
"display_name": "Alice",
"tier": "free",
"created_at": "2026-01-01T00:00:00+00:00"
}
}
Error Codes:
POST /auth/login
Authenticate and receive a JWT.
Auth: None
Request:
{
"email": "user@example.com",
"password": "secret"
}
Response: 200 OK
{
"token": "eyJ...",
"user": {
"user_id": "uuid",
"email": "user@example.com",
"display_name": "Alice",
"tier": "free",
"created_at": "2026-01-01T00:00:00+00:00"
}
}
Error Codes:
GET /auth/oauth/start?provider=<provider>
Start an OAuth flow.
Auth: None
Query Parameters:
providergoogle or githubResponse: 200 OK
{
"url": "https://accounts.google.com/o/oauth2/v2/auth?..."
}
GET /auth/google/callback
Google OAuth callback. Redirects with JWT on success.
Auth: None
GET /auth/github/callback
GitHub OAuth callback. Redirects with JWT on success.
Auth: None
GET /auth/me
Get the current authenticated user.
Auth: Bearer token required
Response: 200 OK
{
"user_id": "uuid",
"email": "user@example.com",
"display_name": "Alice",
"tier": "free",
"created_at": "2026-01-01T00:00:00+00:00"
}
Error Codes:
POST /auth/logout
Revoke the current JWT.
Auth: Bearer token required
Response: 200 OK
{
"logged_out": true
}
Merge
GET /api/drivers
List all available merge drivers.
Auth: None
Response: 200 OK
{
"drivers": [
{
"name": "JSON",
"extensions": [".json"]
},
{
"name": "YAML",
"extensions": [".yaml", ".yml"]
}
]
}
POST /api/merge
Perform a semantic three-way merge.
Auth: Bearer token required. Subject to billing limits.
Request:
{
"driver": "json",
"base": "{\"name\": \"base\", \"version\": 1}",
"ours": "{\"name\": \"ours\", \"version\": 2}",
"theirs": "{\"name\": \"theirs\", \"version\": 1}"
}
driverjson, yaml, toml, xml, csv, sql, html, markdown, svg, docx, xlsx, pptx, pdf, feed, ical, image, otio, properties)baseourstheirsResponse: 200 OK
{
"result": "{\"name\":\"ours\",\"version\":2}",
"driver": "json",
"conflicts": false
}
When conflicts cannot be automatically resolved, conflicts is true and result is null.
Error Codes:
Usage
GET /api/usage
Get current usage and billing limits.
Auth: Bearer token required
Response: 200 OK
{
"tier": "free",
"merges_used": 42,
"merges_limit": 100,
"storage_bytes": 5242880,
"storage_limit": 104857600,
"repos_count": 2,
"repos_limit": 5,
"api_calls": 150,
"period": "2026-01",
"utilization_percent": 42.0
}
Tier limits (merges_limit, repos_limit) are -1 for unlimited (Pro/Enterprise).
Analytics
GET /api/analytics
Get merge analytics. Pro tier or higher required.
Auth: Bearer token required (Pro+)
Response: 200 OK
{
"total_merges": 1234,
"merges_today": 15,
"merges_this_week": 87,
"merges_by_driver": {
"json": 500,
"yaml": 300,
"toml": 200
},
"merges_by_day": [
{"date": "2026-01-28", "count": 12},
{"date": "2026-01-29", "count": 15}
],
"conflicts_resolved": 1100,
"conflicts_detected": 134,
"avg_merge_time_ms": 2.5,
"active_users_today": 3
}
Error Codes:
Organizations
POST /api/orgs
Create an organization.
Auth: Bearer token required
Request:
{
"name": "my-org",
"display_name": "My Organization"
}
namedisplay_nameResponse: 201 Created
{
"org_id": "uuid",
"name": "my-org",
"display_name": "My Organization",
"tier": "free",
"member_count": 1,
"is_owner": true
}
Error Codes:
GET /api/orgs
List organizations the current user belongs to.
Auth: Bearer token required
Response: 200 OK — array of OrgInfo objects.
POST /api/orgs/{org_id}/invite
Invite a member or directly add an existing user.
Auth: Bearer token required (org admin/owner)
Request:
{
"email": "newuser@example.com",
"role": "member"
}
Valid roles: owner, admin, member, viewer.
Response: 200 OK
{
"status": "added",
"user_id": "uuid",
"email": "newuser@example.com"
}
If the email is not registered, status is "invited" and user_id is null.
Error Codes:
GET /api/orgs/{org_id}/members
List organization members.
Auth: Bearer token required (org member)
Response: 200 OK — array of MemberInfo objects:
[
{
"user_id": "uuid",
"role": "owner",
"joined_at": "2026-01-01T00:00:00+00:00",
"email": "owner@example.com",
"display_name": "Owner"
}
]
DELETE /api/orgs/{org_id}/members/{user_id}
Remove a member from an organization.
Auth: Bearer token required (org admin/owner)
Response: 204 No Content
Error Codes:
PUT /api/orgs/{org_id}/members/{user_id}/role
Update a member's role.
Auth: Bearer token required (org admin/owner)
Request:
{
"role": "admin"
}
Response: 204 No Content
GET /api/invitations
List pending invitations (sent by user or received by user).
Auth: Bearer token required
Response: 200 OK — array of InvitationInfo objects.
POST /api/invitations/{invite_id}/accept
Accept an invitation.
Auth: Bearer token required (email must match invitation)
Response: 204 No Content
Error Codes:
Plugins
GET /api/plugins
List loaded WASM plugins.
Auth: None
Response: 200 OK
{
"plugins": [
{
"name": "custom-driver",
"version": "1.0.0"
}
],
"count": 1
}
POST /api/plugins/upload
Upload a WASM plugin. Enterprise tier required.
Auth: Bearer token required (Enterprise)
Request: multipart/form-data with a .wasm file field.
Response: 201 Created
{
"name": "custom-driver.wasm",
"status": "loaded",
"driver": "plugin-custom-driver"
}
Error Codes:
POST /api/plugins/merge
Merge using a custom plugin driver.
Auth: Bearer token required
Request:
{
"driver": "plugin-custom-driver",
"base": "...",
"ours": "...",
"theirs": "..."
}
Response: Same shape as POST /api/merge.
Error Codes:
Billing
POST /billing/checkout
Create a Stripe Checkout session for upgrading.
Auth: Bearer token required
Request:
{
"tier": "pro",
"success_url": "https://example.com/success",
"cancel_url": "https://example.com/cancel"
}
tierpro or enterprisesuccess_urlcancel_urlResponse: 200 OK
{
"url": "https://checkout.stripe.com/c/pay/cs_test_..."
}
Error Codes:
GET /billing/subscription
Get current subscription status.
Auth: Bearer token required
Response: 200 OK
{
"tier": "pro",
"status": "active",
"current_period_end": null,
"cancel_at_period_end": false
}
POST /billing/portal
Create a Stripe Customer Portal session for managing subscriptions.
Auth: Bearer token required
Response: 200 OK
{
"url": "https://billing.stripe.com/p/session_..."
}
Error Codes:
POST /billing/webhook
Receive Stripe webhook events. Called by Stripe, not by clients.
Auth: Stripe-Signature header verification (HMAC-SHA256)
Handles: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, invoice.payment_failed.
Response: 200 OK
{
"received": true
}
Admin
GET /admin/users
List all users. Admin role required.
Auth: Bearer token required (admin)
Response: 200 OK — array of UserInfo objects.
Error Codes:
Error Response Format
All errors return a consistent JSON body:
{
"error": "Human-readable error message"
}
Rate Limiting
All protected endpoints are rate-limited. Responses include standard RateLimit-* headers when limits are approached or exceeded.