Introduction
This documentation aims to provide all the information you need to work with our API.
Mail test server: https://backend-staging.subsig.com:8025 (HTTP only)
Postman collection: https://backend-staging.subsig.com/docs.postman
OpenAPI spec: https://backend-staging.subsig.com/docs.openapi
Test Users (Development Only)
The following test accounts are available for testing purposes:
| Password | Organisation | Role | |
|---|---|---|---|
admin@acme.com |
password |
Acme Corporation | admin |
admin@acme.com |
password |
Acme Corporation | organisation_owner |
member@acme.com |
password |
Acme Corporation | organisation_member |
project@acme.com |
password |
Acme Corporation | project_member (CRM & Analytics only) |
alice@techstart.com |
password |
TechStart Inc | organisation_owner |
Note: admin@acme.com is also a member of TechStart Inc for testing multi-organisation switching.
Authenticating requests
To authenticate requests, include an Authorization header with the value "Bearer 1|abc123...".
All authenticated endpoints are marked with a requires authentication badge in the documentation below.
You can retrieve your token by visiting your dashboard and clicking Generate API token.
Registration
Create a new user account to access the application.
Create Account
Register a new user account. After successful registration, the user will be automatically logged in and redirected to the dashboard.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/register"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "John Doe",
"email": "john@example.com",
"password": "SecurePass123!",
"password_confirmation": "SecurePass123!"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, Account created. User logged in and redirected.):
Example response (422, Validation error.):
{
"message": "The email has already been taken.",
"errors": {
"email": [
"The email has already been taken."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Authentication
APIs for user authentication
Create API Token
Generate an API token for authenticated requests. Requires a verified email address.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/sanctum/token"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "john@example.com",
"password": "SecurePass123!"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"token": "1|abc123..."
}
Example response (422, Invalid credentials):
{
"message": "The provided credentials are incorrect.",
"errors": {
"email": [
"The provided credentials are incorrect."
]
}
}
Example response (422, Email not verified):
{
"message": "Please verify your email address before logging in.",
"errors": {
"email": [
"Please verify your email address before logging in."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Verify Email
Verify user's email address using the 4-digit code sent via email. Returns an API token on successful verification. Verification link is sent via email. /verify-email?code=1234&email=john@example.com
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/email/verify"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "john@example.com",
"code": "1234"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "Email verified successfully.",
"token": "1|abc123..."
}
Example response (200, Already verified):
{
"message": "Email already verified.",
"token": "1|abc123..."
}
Example response (422, Invalid code):
{
"message": "Invalid verification code.",
"errors": {
"code": [
"Invalid verification code."
]
}
}
Example response (422, Expired code):
{
"message": "Verification code has expired. Please request a new one.",
"errors": {
"code": [
"Verification code has expired. Please request a new one."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Resend Verification Code
Send a new 4-digit verification code to the user's email. Code expires in 60 minutes.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/email/resend"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "john@example.com"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "Verification code sent."
}
Example response (200, Already verified):
{
"message": "Email already verified."
}
Example response (422, User not found):
{
"message": "No account found with this email.",
"errors": {
"email": [
"No account found with this email."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Register with Invite
Accept an invitation and create a new user account. The email address must match the email address on the invite. After successful registration, the user will be added to the organisation or project and will receive an email verification code.
Note: This endpoint bypasses the business email requirement since the invitation itself validates the user's legitimacy.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/invites/accept"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"token": "eEtgjrcdtubjCu4817MfGiimvC2DQLBgaI7LpY1g5kdDMK5wJlQank7ZJ6PWurmb",
"name": "John Doe",
"email": "user@example.com",
"password": "SecurePass123!",
"password_confirmation": "SecurePass123!"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201):
{
"message": "Registration successful. Please check your email to verify your account."
}
Example response (404, Token not found):
{
"message": "Invite not found.",
"errors": {
"token": [
"The invite token is invalid or does not exist."
]
}
}
Example response (410, Invite expired):
{
"message": "Invite has expired.",
"errors": {
"token": [
"This invite has expired. Please request a new invitation."
]
}
}
Example response (410, Invite already accepted):
{
"message": "Invite has already been accepted.",
"errors": {
"token": [
"This invite has already been accepted."
]
}
}
Example response (422, Email mismatch):
{
"message": "The email address does not match the invitation.",
"errors": {
"email": [
"The email address must match the email on the invitation."
]
}
}
Example response (422, Validation error):
{
"message": "The name field is required.",
"errors": {
"name": [
"The name field is required."
]
}
}
Example response (422, Email already registered):
{
"message": "The email has already been taken.",
"errors": {
"email": [
"The email has already been taken."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get Current User
requires authentication
Get the authenticated user's details including organisation and subscription information.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/user"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"name": "John Doe",
"email": "john@example.com",
"email_verified_at": "2025-12-04T12:00:00.000000Z",
"created_at": "2025-12-04T10:00:00.000000Z",
"organisation": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Inc",
"website": "https://acme.com",
"product_logo": "https://example.com/logo.png"
},
"role": "organisation_owner",
"subscription": {
"id": 1,
"stripe_price_id": "price_1234567890",
"name": "Pro Plan",
"status": "active",
"expiration_date": "2025-12-31T23:59:59.000000Z",
"trial_end_date": "2025-12-11T23:59:59.000000Z"
}
}
Example response (401, Unauthenticated):
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Log In
Authenticate with your email and password to start a session. On success, you receive a token for subsequent requests.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/login"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "john@example.com",
"password": "SecurePass123!",
"remember": true
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Login successful. Session started.):
Example response (422, Invalid credentials.):
{
"message": "These credentials do not match our records.",
"errors": {
"email": [
"These credentials do not match our records."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Log Out
requires authentication
End your current session. You will need to log in again to access protected resources.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/logout"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200, Logged out successfully.):
Example response (401, Not logged in.):
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Password Reset
Recover access to your account if you forgot your password.
Request Password Reset
Send a password reset link to your email. The link expires after 60 minutes. Same response for security even if email not found.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/forgot-password"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "john@example.com"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Reset link sent.):
{
"status": "We have emailed your password reset link."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Reset Password
Set a new password using the token from your email. Token is valid for 60 minutes.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/reset-password"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"token": "a1b2c3d4e5f6g7h8i9j0",
"email": "john@example.com",
"password": "NewSecurePass123!",
"password_confirmation": "NewSecurePass123!"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Password reset successful.):
{
"status": "Your password has been reset."
}
Example response (422, Invalid or expired token.):
{
"message": "This password reset token is invalid.",
"errors": {
"email": [
"This password reset token is invalid."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Reviews
APIs for fetching aggregated reviews from multiple platforms, scoped to organizations.
Get Organization Reviews
requires authentication
Fetch and aggregate reviews from multiple projects/brands within an organization. Reviews are fetched from external API, persisted to database, and returned with filters applied. Supports filtering by multiple brands (projects), platforms, ratings, languages, and more.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/660e8400-e29b-41d4-a716-446655440001/reviews"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"brands": [
"uuid-1",
"uuid-2"
],
"view_uuid": "a1b2c3d4-e5f6-g7h8-i9j0",
"platforms": [
"G2",
"Capterra"
],
"date_range": {
"type": "all_time",
"value": "all_time"
},
"date_range_custom": {
"start": "2026-02-03T13:58:49",
"end": "2052-02-27"
},
"date_from": "2026-01-01",
"date_to": "2026-01-24",
"rating_buckets": [
"5.0",
"4.0-4.9"
],
"languages": [
"en",
"de"
],
"read_status": "unread",
"search": "customer support",
"sort_by": "review_date",
"sort_direction": "desc",
"period_in_days": 30,
"page": 1
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"data": {
"organisation_id": "660e8400-e29b-41d4-a716-446655440001",
"organisation_name": "Acme Corp",
"reviews": {
"current_page": 1,
"data": [
{
"id": 1,
"scraper_review_id": 10452,
"organisation_id": 5,
"project_id": 30,
"platform": "Capterra",
"platform_icon": null,
"rating": 5,
"content": "Great product with excellent features...",
"author": "John Smith",
"job_role": "Product Manager",
"language": "en",
"date": "2026-01-13",
"link_url": "https://www.capterra.com/reviews/",
"direct_review_url": "https://scraper.example.com/reviews",
"created_at": "2026-01-15T09:30:21.000000Z"
}
],
"per_page": 10,
"total": 150
}
}
}
Example response (403):
{
"message": "You do not have access to this organisation."
}
Example response (404):
{
"message": "Organisation not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get Review Analytics
requires authentication
Calculate analytics metrics for reviews including new reviews count, average rating, reviews per month, with comparison to previous period. Also includes rating distribution and platform breakdown.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/660e8400-e29b-41d4-a716-446655440001/reviews/analytics"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"brands": [
"uuid-1",
"uuid-2"
],
"compare_products": [
"uuid-1",
"uuid-2"
],
"platforms": [
"G2",
"Capterra"
],
"date_range": {
"type": "preset",
"value": "last_3_months"
},
"date_range_custom": {
"start": "2025-10-01",
"end": "2026-01-27"
}
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"data": [
{
"product_uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Acme Product",
"product_logo": "https://...",
"period": {
"start": "2025-10-28",
"end": "2026-01-27",
"duration": 3
},
"metrics": {
"new_reviews": {
"current": 2,
"previous": 10,
"change_percentage": -80,
"trend": "down"
},
"average_rating": {
"current": 4.1,
"previous": 4.4,
"change_percentage": -6.8,
"trend": "down"
},
"reviews_per_month": {
"current": 2,
"previous": 6,
"change_percentage": -68.3,
"trend": "down"
},
"review_velocity": {
"interval": "week",
"data": [
{
"group": "2025-10-W5",
"count": 1,
"cumulative_before": 0,
"rating": 4.2
}
]
}
},
"breakdown": {
"ratings": {
"5.0": 0,
"4.0": 2,
"3.0": 0,
"2.0": 0,
"1.0": 0
},
"platforms": {
"G2": 1,
"Capterra": 1
}
}
}
],
"competitors": [
{
"project_uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Base Product",
"product_logo": "https://...",
"is_competitor": false,
"total_reviews": {
"current": 10,
"previous": 5,
"change_percentage": 100,
"trend": "up"
},
"average_rating": {
"current": 4.3,
"previous": 4.1,
"change_percentage": 4.9,
"trend": "up"
},
"rank": 1
}
],
"applied_filters": {
"brands": [
"uuid-1"
],
"platforms": [
"G2",
"Capterra"
],
"date_range": {
"type": "preset",
"value": "last_3_months"
}
},
"organisation_id": "660e8400-e29b-41d4-a716-446655440001",
"organisation_name": "Acme Corp"
}
Example response (200, Multi-product comparison):
{
"data": [
{
"product_uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Product 1",
"product_logo": "https://...",
"period": {
"start": "2025-10-28",
"end": "2026-01-27",
"duration": 3
},
"metrics": {
"new_reviews": {...},
"average_rating": {...},
"reviews_per_month": {...},
"review_velocity": {"interval": "week", "data": [{"group": "...", "count": 0, "cumulative_before": 0, "rating": 4.1}]}
},
"breakdown": {
"ratings": {"5.0": 0, "4.0": 2, "3.0": 0, "2.0": 0, "1.0": 0},
"platforms": {"G2": 1, "Capterra": 1}
}
},
{
"product_uuid": "770e8400-e29b-41d4-a716-446655440002",
"product_name": "Product 2",
"product_logo": "https://...",
"period": {...},
"metrics": {...},
"breakdown": {...}
}
],
"competitors": [
{
"project_uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Base Product",
"product_logo": "https://...",
"is_competitor": false,
"total_reviews": {"current": 10, "previous": 5, "change_percentage": 100.0, "trend": "up"},
"average_rating": {"current": 4.3, "previous": 4.1, "change_percentage": 4.9, "trend": "up"},
"rank": 1
}
],
"applied_filters": {
"brands": ["660e8400-e29b-41d4-a716-446655440001", "770e8400-e29b-41d4-a716-446655440002"],
"platforms": [],
"date_range": {"type": "preset", "value": "last_3_months"}
},
"organisation_id": "660e8400-e29b-41d4-a716-446655440000",
"organisation_name": "Acme Corp"
}
Example response (403):
{
"message": "You do not have access to this organisation."
}
Example response (404):
{
"message": "Organisation not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Social Posts
APIs for fetching and filtering social media mentions from multiple platforms, scoped to organizations.
Get Organization Social Posts
requires authentication
Fetch and aggregate social posts from multiple projects/brands within an organization. Posts are fetched from external Scraper API, persisted to database, and returned with filters applied. Supports filtering by brands, platforms, types, sentiments, keywords, and more.
Organisation-level social analytics.
Returns mention count and average sentiment with period-over-period comparison. Filters: brands (social_posts.brand_id), platforms, date_range, date_range_custom (start/end, same as social posts), or custom_date_range (from/to).
List Social Post Views
requires authentication
Get all saved filter views for the current user in this organization.
Store Social Post View
requires authentication
Create a new saved filter view for social posts.
Show Social Post View
requires authentication
Get a specific saved filter view.
Update Social Post View
requires authentication
Update a saved filter view.
Delete Social Post View
requires authentication
Delete a saved filter view.
Endpoints
POST api/webhook
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/webhook"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Invites
APIs for managing invites
Validate Invite
Validate an invite token and return the associated email if the invite is valid. This endpoint is public and does not require authentication.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/invites/validate"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"token": "abc123def456..."
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"email": "user@example.com"
}
Example response (404, Invite not found):
{
"message": "Invite not found."
}
Example response (410, Invite expired):
{
"message": "This invite has expired."
}
Example response (410, Invite no longer valid):
{
"message": "This invite is no longer valid."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List Invites
requires authentication
Get invites based on context:
- Organisation level (no project_id): Returns all organisation invites + all project invites for the organisation
- Project level (with project_id): Returns only invites for the specified project
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/invites"
);
const params = {
"project_id": "660e8400-e29b-41d4-a716-446655440001",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
[
{
"id": 1,
"email": "user@example.com",
"type": "organisation",
"status": "pending",
"expires_at": "2025-12-31T10:00:00.000000Z",
"organisation_id": "550e8400-e29b-41d4-a716-446655440000",
"organisation": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Corp"
},
"project_id": null,
"project": null,
"inviter": {
"name": "John Admin",
"email": "admin@acme.com"
},
"created_at": "2025-12-24T10:00:00.000000Z",
"updated_at": "2025-12-24T10:00:00.000000Z"
},
{
"id": 2,
"email": "developer@example.com",
"type": "project",
"status": "pending",
"expires_at": "2025-12-31T10:00:00.000000Z",
"organisation_id": null,
"organisation": null,
"project_id": "660e8400-e29b-41d4-a716-446655440001",
"project": {
"uuid": "660e8400-e29b-41d4-a716-446655440001",
"name": "My Product"
},
"inviter": {
"name": "John Admin",
"email": "admin@acme.com"
},
"created_at": "2025-12-24T10:00:00.000000Z",
"updated_at": "2025-12-24T10:00:00.000000Z"
}
]
Example response (403, No access to project):
{
"message": "You do not have access to this project."
}
Example response (404, Project not found):
{
"message": "Project not found."
}
Example response (422, No organisation context):
{
"message": "No organisation context found.",
"errors": {
"organisation": [
"Please select an organisation or set current organisation."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create Invite
requires authentication
Create a new invite for a user to join an organisation or project. For organisation invites, the organisation is automatically derived from the authenticated user's current organisation context.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/invites"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "user@example.com",
"type": "organisation",
"project_id": "660e8400-e29b-41d4-a716-446655440001"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201):
{
"message": "Invite created successfully.",
"data": {
"id": 1,
"email": "user@example.com",
"type": "organisation",
"status": "pending",
"token": "abc123...",
"expires_at": "2025-12-31T10:00:00.000000Z",
"organisation_id": "550e8400-e29b-41d4-a716-446655440000",
"project_id": null,
"created_at": "2025-12-24T10:00:00.000000Z",
"updated_at": "2025-12-24T10:00:00.000000Z"
}
}
Example response (422, No organisation context):
{
"message": "No organisation context found.",
"errors": {
"organisation": [
"Please select an organisation or set current organisation."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete Invite
requires authentication
Delete an invite. Only the inviter or organisation owners can delete invites.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/invites/1"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (200):
{
"message": "Invite deleted successfully."
}
Example response (403, Not authorized):
{
"message": "You are not authorized to delete this invite."
}
Example response (404, Invite not found):
{
"message": "Invite not found."
}
Example response (422, No organisation context):
{
"message": "No organisation context found.",
"errors": {
"organisation": [
"Please select an organisation or set current organisation."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Links
APIs for managing project links
List Project Links
requires authentication
Get all links associated with a specific project.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/projects/660e8400-e29b-41d4-a716-446655440001/links"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"platform": "g2",
"url": "https://g2.com/products/acme",
"enabled": true,
"created_at": "2026-01-22T10:00:00.000000Z",
"updated_at": "2026-01-22T10:00:00.000000Z"
}
]
}
Example response (403, No Access):
{
"message": "You do not have access to this project."
}
Example response (404, Project Not Found):
{
"message": "Project not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Notifications
APIs for managing notification rules
List Notifications
requires authentication
Get all notification rules for the current organisation.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/notifications"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
[
{
"uuid": "770e8400-e29b-41d4-a716-446655440000",
"name": "Daily Review Alerts",
"trigger_type": "new_review",
"languages": [
"en",
"es"
],
"auto_translate": true,
"rating_filters": [
1,
2,
3
],
"sentiment_filters": [
"negative"
],
"condition_filters": {
"logic": "and",
"rules": [
{
"field": "platforms",
"operator": "contains",
"value": [
"g2"
]
}
]
},
"notification_frequency": "instant",
"read_status": "all",
"is_active": true,
"channels": [],
"projects": [],
"created_at": "2025-12-31T12:00:00.000000Z",
"updated_at": "2025-12-31T12:00:00.000000Z"
}
]
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create Notification
requires authentication
Create a new notification rule with channels and project mappings.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/notifications"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Daily Review Alerts",
"trigger_type": "new_review",
"is_active": true,
"languages": [
"en",
"es",
"fr",
"de"
],
"auto_translate": true,
"rating_filters": [
1,
2,
3,
4,
5
],
"sentiment_filters": [
"positive",
"neutral",
"negative"
],
"keyword": [
"ai",
"support"
],
"content_type": "post",
"notification_frequency": "instant",
"read_status": "all",
"condition_filters": {
"logic": "and",
"rules": [
{
"field": "platforms",
"operator": "contains",
"value": "[\"g2\", \"capterra\"]",
"logic": "or",
"rules": [
[]
]
}
]
},
"channels": [
{
"channel_type": "slack",
"is_active": true,
"config": {
"channel_names": [
"alerts",
"incidents"
],
"channel_url": "https:\/\/hooks.slack.com\/services\/xxx",
"recipients": [
"alerts@company.com"
],
"url": "https:\/\/your-server.com\/webhook\/notifications"
}
}
],
"projects": [
{
"project_uuid": "5f1812b1-15f7-432d-996a-9ab5cfbe01d6",
"is_active": true,
"platforms": {
"review": [
"g2",
"capterra",
"product_hunt",
"google_play"
],
"social": [
"reddit",
"hackernews",
"linkedin"
]
},
"product_logo": "https:\/\/cdn.example.com\/logo.png"
}
]
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, Success):
{
"message": "Notification created successfully.",
"data": {
"uuid": "770e8400-e29b-41d4-a716-446655440000",
"name": "Daily Review Alerts",
"trigger_type": "new_review",
"languages": [
"en",
"es"
],
"auto_translate": true,
"rating_filters": [
1,
2,
3,
4,
5
],
"sentiment_filters": [
"positive",
"neutral",
"negative"
],
"condition_filters": {
"logic": "and",
"rules": [
{
"field": "platforms",
"operator": "contains",
"value": [
"g2",
"capterra"
]
},
{
"field": "sentiment",
"operator": "contains",
"value": [
"negative"
]
}
]
},
"notification_frequency": "instant",
"read_status": "unread",
"keyword": [
"ai",
"support"
],
"content_type": "post",
"is_active": true,
"channels": [
{
"uuid": "880e8400-e29b-41d4-a716-446655440001",
"channel_type": "slack",
"is_active": true,
"config": {
"channel_names": [
"alerts",
"incidents"
],
"channel_url": "https://hooks.slack.com/services/xxx",
"recipients": [
"alerts@company.com"
],
"url": "https://your-server.com/webhook/notifications"
}
}
],
"projects": [
{
"uuid": "990e8400-e29b-41d4-a716-446655440002",
"project_uuid": "5f1812b1-15f7-432d-996a-9ab5cfbe01d6",
"project_name": "Acme App",
"is_active": true,
"product_logo": "https://cdn.example.com/logo.png",
"platforms": {
"review": [
"g2",
"capterra"
],
"social": [
"reddit"
]
}
}
],
"created_at": "2025-12-31T12:00:00.000000Z",
"updated_at": "2025-12-31T12:00:00.000000Z"
}
}
Example response (422, Validation Error):
{
"message": "The name field is required. (and 2 more errors)",
"errors": {
"name": [
"The name field is required."
],
"channels": [
"At least one channel is required."
],
"projects": [
"Select at least one brand."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get Notification
requires authentication
Get details of a specific notification.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/notifications/770e8400-e29b-41d4-a716-446655440000"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"uuid": "770e8400-e29b-41d4-a716-446655440000",
"name": "Daily Review Alerts",
"trigger_type": "new_review",
"languages": [
"en",
"es"
],
"auto_translate": true,
"rating_filters": [
1,
2,
3
],
"sentiment_filters": [
"negative"
],
"condition_filters": {
"logic": "and",
"rules": [
{
"field": "platforms",
"operator": "contains",
"value": [
"g2"
]
}
]
},
"notification_frequency": "instant",
"read_status": "all",
"is_active": true,
"channels": [],
"projects": [],
"created_at": "2025-12-31T12:00:00.000000Z",
"updated_at": "2025-12-31T12:00:00.000000Z"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update Notification
requires authentication
Update an existing notification rule with channels and project mappings.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/notifications/770e8400-e29b-41d4-a716-446655440000"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Daily Review Alerts",
"trigger_type": "new_review",
"is_active": true,
"languages": [
"en",
"es",
"fr",
"de"
],
"auto_translate": true,
"rating_filters": [
1,
2,
3,
4,
5
],
"sentiment_filters": [
"positive",
"neutral",
"negative"
],
"keyword": [
"ai",
"support"
],
"content_type": "post",
"notification_frequency": "instant",
"read_status": "all",
"condition_filters": {
"logic": "and",
"rules": [
{
"field": "platforms",
"operator": "contains",
"value": "[\"g2\", \"capterra\"]"
}
]
},
"channels": [
{
"channel_type": "slack",
"is_active": true,
"config": {
"channel_names": [
"alerts",
"incidents"
],
"channel_url": "https:\/\/hooks.slack.com\/services\/xxx",
"recipients": [
"alerts@company.com"
],
"url": "https:\/\/your-server.com\/webhook\/notifications"
}
}
],
"projects": [
{
"project_uuid": "5f1812b1-15f7-432d-996a-9ab5cfbe01d6",
"is_active": true,
"platforms": {
"review": [
"software_advice"
],
"social": [
"reddit"
]
},
"product_logo": "g"
}
]
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Success):
{
"message": "Notification updated successfully.",
"data": {
"uuid": "770e8400-e29b-41d4-a716-446655440000",
"name": "Updated Review Alerts",
"trigger_type": "new_review",
"languages": [
"en"
],
"auto_translate": false,
"rating_filters": [
1,
2
],
"sentiment_filters": [
"negative"
],
"condition_filters": {
"logic": "and",
"rules": [
{
"field": "sentiment",
"operator": "contains",
"value": [
"negative"
]
}
]
},
"notification_frequency": "daily",
"read_status": "unread",
"keyword": [
"ai",
"support"
],
"content_type": "comment",
"is_active": true,
"channels": [],
"projects": [],
"created_at": "2025-12-31T12:00:00.000000Z",
"updated_at": "2025-12-31T13:00:00.000000Z"
}
}
Example response (404, Not Found):
{
"message": "Notification not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete Notification
requires authentication
Delete a notification and all associated channels and project mappings.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/notifications/770e8400-e29b-41d4-a716-446655440000"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (200):
{
"message": "Notification deleted successfully."
}
Example response (404):
{
"message": "Notification not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Onboarding
APIs for user onboarding flow
Complete Onboarding
requires authentication
Create an organisation and project in a single step during onboarding. The authenticated user becomes the organisation owner.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/onboarding"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"organisation_name": "Acme Inc",
"product_name": "Acme CRM",
"product_website": "https:\/\/acme.com",
"product_logo": "https:\/\/cdn.brandfetch.io\/acme.com\/fallback\/lettermark\/icon?c=BRANDFETCH_CLIENT_ID",
"review_platforms": {
"g2": {
"enabled": true,
"url": "https:\/\/g2.com\/products\/acme"
},
"capterra": {
"enabled": false,
"url": null
}
},
"reddit_keywords": [
"acme",
"acme crm"
],
"reddit_brand_name": "Acme"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201):
{
"message": "Onboarding completed successfully.",
"data": {
"organisation_uuid": "550e8400-e29b-41d4-a716-446655440000",
"product_uuid": "660e8400-e29b-41d4-a716-446655440001",
"organisation": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Inc",
"website": "https://acme.com"
},
"project": {
"uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Acme CRM",
"product_website": "https://acme.com",
"product_logo": "https://cdn.brandfetch.io/acme.com/fallback/lettermark/icon?c=BRANDFETCH_CLIENT_ID",
"review_platforms": {},
"reddit_keywords": [
"acme",
"acme crm"
],
"reddit_brand_name": "Acme"
},
"scraper_sync": {
"success": true,
"synced_platforms": [
"g2",
"capterra"
],
"errors": []
},
"brand_sync": {
"success": true,
"brand_id": "12345",
"error": null
}
}
}
Example response (422, Validation error):
{
"message": "The organisation name field is required.",
"errors": {
"organisation_name": [
"The organisation name field is required."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update Onboarding
requires authentication
Update the current organisation and project for the authenticated user.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/onboarding"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"organisation_name": "Acme Inc",
"product_name": "Acme CRM",
"product_website": "https:\/\/acme.com",
"product_logo": "https:\/\/cdn.brandfetch.io\/acme.com\/fallback\/lettermark\/icon?c=BRANDFETCH_CLIENT_ID",
"review_platforms": {
"g2": {
"enabled": true,
"url": "https:\/\/g2.com\/products\/acme"
},
"capterra": {
"enabled": false,
"url": null
}
},
"reddit_keywords": [
"acme",
"acme crm"
],
"reddit_brand_name": "Acme"
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "Onboarding updated successfully.",
"data": {
"organisation": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Inc",
"website": "https://acme.com"
},
"project": {
"uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Acme CRM",
"product_website": "https://acme.com",
"product_logo": "https://cdn.brandfetch.io/acme.com/fallback/lettermark/icon?c=BRANDFETCH_CLIENT_ID",
"review_platforms": {},
"reddit_keywords": [
"acme",
"acme crm"
],
"reddit_brand_name": "Acme"
},
"scraper_sync": {
"success": true,
"synced_platforms": [
"g2",
"capterra"
],
"errors": []
},
"brand_sync": {
"success": true,
"brand_id": "12345",
"error": null
}
}
}
Example response (404, No organisation or project found):
{
"message": "No organisation or project found for the current user."
}
Example response (422, Validation error):
{
"message": "The organisation name field is required.",
"errors": {
"organisation_name": [
"The organisation name field is required."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Search Platform URLs
requires authentication
Search for a product's listing pages across multiple review platforms using Perplexity AI-powered web search. Each URL is validated and assigned a status: valid, invalid, or needs_review.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/platform-urls"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"product_name": "Slack",
"product_website": "https:\/\/slack.com",
"platform": "g2"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, All platforms):
{
"product_name": "Slack",
"product_website": "https://slack.com",
"reviews": {
"g2": {
"url": "https://www.g2.com/products/slack/reviews",
"status": "valid"
},
"capterra": {
"url": "https://www.capterra.com/p/135003/Slack/",
"status": "valid"
},
"software_advice": {
"url": "https://www.softwareadvice.com/team-communication/slack-profile/",
"status": "needs_review"
},
"trustpilot": {
"url": "https://www.trustpilot.com/review/slack.com",
"status": "valid"
},
"omr_reviews": {
"url": "https://omr.com/reviews/product/slack",
"status": "valid"
},
"clutch": {
"url": null,
"status": "invalid"
},
"sourceforge": {
"url": "https://sourceforge.net/software/product/Slack/",
"status": "valid"
},
"product_hunt": {
"url": "https://www.producthunt.com/products/slack",
"status": "valid"
},
"hubspot_directory": {
"url": null,
"status": "invalid"
},
"goodfirms": {
"url": "https://www.goodfirms.co/software/slack",
"status": "valid"
},
"chrome_web_store": {
"url": null,
"status": "invalid"
},
"google_workspace_marketplace": {
"url": "https://workspace.google.com/marketplace/app/slack/429783454934",
"status": "needs_review"
},
"app_store": {
"url": null,
"status": "invalid"
},
"play_store": {
"url": null,
"status": "invalid"
},
"subscribed_fyi": {
"url": "https://subscribed.fyi/slack/reviews/",
"status": "valid"
}
}
}
Example response (200, Filtered by platform):
{
"product_name": "Slack",
"product_website": "https://slack.com",
"reviews": {
"g2": {
"url": "https://www.g2.com/products/slack/reviews",
"status": "valid"
}
}
}
Example response (422, Validation error):
{
"message": "The product name field is required.",
"errors": {
"product_name": [
"The product name field is required."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Generate Reddit Keywords
requires authentication
Generate commonly used variations of a brand name for Reddit tracking, including misspellings, abbreviations, and nicknames.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/reddit-keywords"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"brand_name": "Salesforce"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"brand_name": "Salesforce",
"top_variations": {
"exact": "Salesforce",
"misspellings": [
"Salesfoce",
"Salseforce",
"Saleforce"
],
"abbreviations": [
"SF",
"SFDC"
],
"nicknames": [
"The Force",
"SF CRM",
"Sales Cloud"
]
}
}
Example response (422, Validation error):
{
"message": "The brand name field is required.",
"errors": {
"brand_name": [
"The brand name field is required."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Organisations
APIs for managing organisations
List Organisations
requires authentication
Get all organisations the authenticated user belongs to.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Inc",
"website": "https://acme.com",
"role": "organisation_owner",
"created_at": "2025-12-10T10:00:00.000000Z",
"updated_at": "2025-12-10T10:00:00.000000Z"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create Organisation
requires authentication
Create a new organisation. The authenticated user becomes the admin.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Acme Inc",
"website": "https:\/\/acme.com"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201):
{
"message": "Organisation created successfully.",
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Inc",
"website": "https://acme.com",
"role": "organisation_owner",
"created_at": "2025-12-10T10:00:00.000000Z",
"updated_at": "2025-12-10T10:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get Organisation
requires authentication
Get details of a specific organisation.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/b47b1b40-d5f7-4e9c-959a-b7affbc9965c"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Inc",
"website": "https://acme.com",
"role": "organisation_owner",
"created_at": "2025-12-10T10:00:00.000000Z",
"updated_at": "2025-12-10T10:00:00.000000Z"
}
}
Example response (403, No access):
{
"message": "You do not have access to this organisation."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update Organisation
requires authentication
Update an organisation's details. Requires admin role.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/b47b1b40-d5f7-4e9c-959a-b7affbc9965c"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Acme Corp",
"website": "https:\/\/acme.com"
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "Organisation updated successfully.",
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Corp",
"website": "https://acme.com",
"role": "organisation_owner",
"created_at": "2025-12-10T10:00:00.000000Z",
"updated_at": "2025-12-10T10:00:00.000000Z"
}
}
Example response (403, Not admin):
{
"message": "You must be an organisation admin to perform this action."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Switch Current Organisation
requires authentication
Set the user's current organisation for subsequent requests.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/b47b1b40-d5f7-4e9c-959a-b7affbc9965c/switch"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200):
{
"message": "Switched to organisation successfully.",
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Inc"
}
}
Example response (403, No access):
{
"message": "You do not have access to this organisation."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Platforms
APIs for managing platforms
List All Platforms
requires authentication
Get all platforms.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/platforms"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
[
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "G2",
"created_at": "2026-01-08T10:00:00.000000Z",
"updated_at": "2026-01-08T10:00:00.000000Z"
}
]
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create Platform
requires authentication
Create a new platform.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/platforms"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "G2"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201):
{
"message": "Platform created successfully.",
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "G2",
"created_at": "2026-01-08T10:00:00.000000Z",
"updated_at": "2026-01-08T10:00:00.000000Z"
}
}
Example response (422, Validation Error):
{
"message": "The name has already been taken.",
"errors": {
"name": [
"The name has already been taken."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update Platform
requires authentication
Update a platform's details.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/platforms/550e8400-e29b-41d4-a716-446655440000"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Capterra"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "Platform updated successfully.",
"data": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Capterra",
"created_at": "2026-01-08T10:00:00.000000Z",
"updated_at": "2026-01-08T10:30:00.000000Z"
}
}
Example response (404, Not Found):
{
"message": "Platform not found."
}
Example response (422, Validation Error):
{
"message": "The name has already been taken.",
"errors": {
"name": [
"The name has already been taken."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete Platform
requires authentication
Delete a platform.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/platforms/550e8400-e29b-41d4-a716-446655440000"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (200):
{
"message": "Platform deleted successfully."
}
Example response (404, Not Found):
{
"message": "Platform not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Profiles
APIs for managing product claims and product profile data.
The Profiles API group covers two related workflows:
- Claim Profiles - Submit and manage ownership claims for products
- Product Profiles - Edit and sync detailed product information
Claim Profiles
Claim profiles allow users to claim ownership of products listed in the system.
Once a claim is submitted, it goes through a review process. Approved claims grant access to edit the product's profile data.
Claim Statuses:
unclaimed- Product not yet claimedclaim_started- Claim submitted, awaiting reviewconfirmed_claimed- Approved (free plan)confirmed_verified- Approved (paid/verified plan)rejected- Claim was rejected
Staging Environment:
In staging, use test products from Curiosity (names ending with _test):
- Test Alpha _test, Test Beta _test, Test Gamma _test, etc.
Configure via CURIOSITY_TEST_PRODUCT_IDS and CURIOSITY_RESTRICT_TO_TEST_PRODUCTS environment variables.
Search Products
requires authentication
Search for products in the Curiosity database to claim.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/products/search"
);
const params = {
"q": "slack",
"limit": "10",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": {
"products": [
{
"id": 123,
"name": "Slack",
"url": "https://slack.com",
"logo_path": "products/slack-logo.png"
}
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List All Claim Profiles
requires authentication
Get all claim profiles across all organisations. Intended for admin panel usage.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/claim-profiles"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
[
{
"uuid": "880e8400-e29b-41d4-a716-446655440000",
"business_email": "john@company.com",
"job_title": "Product Manager",
"business_phone": "+1234567890",
"status": "pending",
"project": {
"uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Acme App"
},
"organisation": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Corp"
},
"status_updated_by": null,
"created_at": "2026-01-03T12:00:00.000000Z",
"updated_at": "2026-01-03T12:00:00.000000Z"
}
]
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create Claim Profile
requires authentication
Create a new claim profile for a project. The organisation is automatically derived from the authenticated user's current organisation context.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/claim-profiles"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"project_id": "660e8400-e29b-41d4-a716-446655440001",
"scraper_product_id": 123,
"product_name": "Slack",
"product_url": "https:\/\/slack.com",
"business_email": "john@company.com",
"job_title": "Product Manager",
"business_phone": "+1234567890"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, Success):
{
"message": "Claim profile created successfully.",
"data": {
"uuid": "880e8400-e29b-41d4-a716-446655440000",
"scraper_product_id": 123,
"product_name": "Slack",
"product_url": "https://slack.com",
"business_email": "john@company.com",
"job_title": "Product Manager",
"business_phone": "+1234567890",
"status": "pending",
"created_at": "2026-01-03T12:00:00.000000Z",
"updated_at": "2026-01-03T12:00:00.000000Z"
}
}
Example response (403, No organisation context):
{
"message": "This action is unauthorized."
}
Example response (422, Validation Error):
{
"message": "The project is required. (and 1 more error)",
"errors": {
"project_id": [
"The project is required."
],
"business_email": [
"Please use a business email address."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create Claim Profile (External)
Create a new claim profile from an external website. This endpoint does not require user authentication but requires a valid external API key.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/external/claim-profiles"
);
const headers = {
"Authorization": "required The external API key. Example: Bearer your-secure-external-api-key",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"scraper_product_id": 123,
"product_name": "Lovable",
"product_url": "https:\/\/lovable.dev",
"business_email": "john@company.com",
"job_title": "Product Manager",
"business_phone": "+1234567890"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, Success):
{
"message": "Claim profile submitted successfully.",
"data": {
"uuid": "880e8400-e29b-41d4-a716-446655440000",
"product_name": "Lovable",
"business_email": "john@company.com",
"status": "pending"
}
}
Example response (401, Unauthorized):
{
"message": "Unauthorized."
}
Example response (422, Validation Error):
{
"message": "The business email is required.",
"errors": {
"business_email": [
"The business email is required."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Product Profiles
Product profiles contain detailed information about claimed products, synced bidirectionally with the Curiosity database.
Product profiles are created automatically when a claim is approved. They include:
- Basic Info: Name, URL, logo, subtitle, overview
- Categorization: Parent category, sub-categories, segments, search fields
- Reviews: G2, Capterra (editable URLs), Trustpilot (read-only scores)
- Content: Pricing, analysis, FAQ, pros/cons, alternatives
- SEO: Meta titles and descriptions for main, deals, and cancellation pages
Sync Operations:
pull- Fetch latest data from Curiosity (overwrites local changes)push- Send local changes to Curiosity
Staging Environment:
Sync operations are restricted to test products. Configure via:
CURIOSITY_TEST_PRODUCT_IDS- Comma-separated list of allowed product IDsCURIOSITY_RESTRICT_TO_TEST_PRODUCTS- Set totrueto enable restriction
Get Product Profile
requires authentication
Get the product profile for a specific project. Returns all profile data including content, SEO meta, categories, and sync status.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/projects/660e8400-e29b-41d4-a716-446655440001/profile"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": {
"uuid": "770e8400-e29b-41d4-a716-446655440002",
"curiosity_product_id": 123,
"name": "Slack",
"url": "https://slack.com",
"logo_path": "products/slack-logo.png",
"local_logo": null,
"subtitle": "<p>Where work happens</p>",
"overview": "<p>Slack is a messaging platform...</p>",
"pricing": "<p>Free, Pro $7.25/user, Business+ $12.50/user</p>",
"verified_badge": true,
"parent_category": {
"id": 5,
"name": "Communication"
},
"review_platforms": {
"g2": {
"enabled": true,
"url": "https://g2.com/products/slack",
"score": 4.5,
"reviews_count": 120
},
"capterra": {
"enabled": true,
"url": "https://capterra.com/p/123/slack",
"score": 4.6,
"reviews_count": 85
},
"trustpilot": {
"score": 3.6,
"reviews_count": 11218
}
},
"categories": [
{
"id": 1,
"name": "Communication"
}
],
"segments": [
{
"id": 1,
"name": "Enterprise"
}
],
"search_fields": {
"built_for": [
{
"id": 1,
"name": "Marketing Teams"
}
],
"platform": [
{
"id": 2,
"name": "Web"
}
],
"pricing_model": [
{
"id": 3,
"name": "Subscription"
}
]
},
"competitors": [
{
"id": 456,
"name": "Microsoft Teams",
"url": "https://teams.microsoft.com",
"logo_path": null
}
],
"videos": [
"https://www.youtube.com/watch?v=abc"
],
"awards": [
{
"id": 1,
"name": "Best Communication Tool 2025"
}
],
"deal": "Get 20% off annual plans",
"deals_meta_title": "Best Slack Deals",
"deals_meta_description": null,
"cancellation_content": "<p>To cancel your subscription...</p>",
"cancellation_content_summary": "<p>Cancel anytime from settings</p>",
"book_demo_url": "https://slack.com/demo",
"pricing_url": "https://slack.com/pricing",
"pros_cons": "Pros: Easy to use\nCons: Can be expensive",
"analysis": "<p>Detailed analysis of Slack...</p>",
"faq": "Q: How much does it cost?\nA: Free tier available",
"alternatives_text": "<p>Consider Microsoft Teams or Discord...</p>",
"pricing_range": "$0-$15/user/mo",
"is_ai_powered": false,
"meta": {
"main_page": {
"title": "Slack - Where Work Happens",
"description": "Team messaging platform"
},
"deals": {
"title": "Slack Deals",
"description": "Best Slack discounts"
},
"cancellation": {
"title": "Cancel Slack",
"description": "How to cancel"
}
},
"sync_status": "synced",
"synced_at": "2026-01-06T10:00:00.000000Z",
"local_changes_at": null,
"last_change_request": {
"uuid": "880e8400-e29b-41d4-a716-446655440003",
"status": "pending",
"requested_at": "2026-01-06T11:00:00.000000Z",
"reviewed_at": null
},
"created_at": "2026-01-06T09:00:00.000000Z",
"updated_at": "2026-01-06T10:00:00.000000Z"
}
}
Example response (404):
{
"message": "Project not found."
}
Example response (404):
{
"message": "This project does not have a product profile yet."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update Product Profile
requires authentication
Submit a change request for the product profile. Changes are stored as a pending request for admin review. Once approved, changes will be applied and synced to Curiosity. Fields like subtitle, overview, pricing, analysis, and alternatives_text support HTML/richtext.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/projects/660e8400-e29b-41d4-a716-446655440001/profile"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"subtitle": "<p>Where work happens<\/p>",
"overview": "<p>Slack is a messaging platform...<\/p>",
"pricing": "<p>Free, Pro $7.25\/user<\/p>",
"parent_category_id": 5,
"review_platforms": [],
"videos": [
"architecto"
],
"categories": [
[]
],
"segments": [
[]
],
"search_fields": [],
"competitors": [
[]
],
"deal": "architecto",
"deals_meta_title": "Best Slack Deals 2026",
"deals_meta_description": "architecto",
"cancellation_content": "architecto",
"cancellation_content_summary": "architecto",
"book_demo_url": "https:\/\/slack.com\/demo",
"pricing_url": "https:\/\/slack.com\/pricing",
"pros_cons": "architecto",
"analysis": "architecto",
"faq": "architecto",
"alternatives_text": "architecto",
"pricing_range": "$99-$999\/mo",
"is_ai_powered": true,
"meta": []
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "Change request submitted for review.",
"data": {
"change_request_uuid": "880e8400-e29b-41d4-a716-446655440003",
"status": "pending"
}
}
Example response (404):
{
"message": "This project does not have a product profile yet."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Upload Product Logo
requires authentication
Upload a new logo image for the product profile. The logo is stored locally and will be synced to Curiosity when you push changes.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/projects/660e8400-e29b-41d4-a716-446655440001/profile/logo"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "multipart/form-data",
"Accept": "application/json",
};
const body = new FormData();
body.append('logo', document.querySelector('input[name="logo"]').files[0]);
fetch(url, {
method: "POST",
headers,
body,
}).then(response => response.json());Example response (200):
{
"message": "Logo uploaded successfully.",
"data": {
"local_logo": "product-logos/abc123.png",
"sync_status": "local_changes",
"local_changes_at": "2026-01-06T11:00:00.000000Z"
}
}
Example response (404):
{
"message": "This project does not have a product profile yet."
}
Example response (422):
{
"message": "The logo field is required.",
"errors": {
"logo": [
"The logo field is required."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get Sync Status
requires authentication
Get the current sync status of a project's product profile.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/projects/660e8400-e29b-41d4-a716-446655440001/profile/status"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": {
"has_profile": true,
"has_curiosity_link": true,
"sync_status": "local_changes",
"synced_at": "2026-01-06T10:00:00.000000Z",
"local_changes_at": "2026-01-06T11:00:00.000000Z",
"last_change_request": {
"uuid": "880e8400-e29b-41d4-a716-446655440003",
"status": "pending",
"requested_at": "2026-01-06T11:00:00.000000Z",
"reviewed_at": null
}
}
}
Example response (200):
{
"data": {
"has_profile": false,
"has_curiosity_link": true,
"sync_status": null,
"synced_at": null,
"local_changes_at": null,
"last_change_request": null
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Catalog
Reference data for product categorization and filtering.
These endpoints provide access to taxonomy data from Curiosity used when editing product profiles.
Available Data:
- Parent Categories - Top-level categories (e.g., Communication, Marketing)
- Categories - Detailed sub-categories
- Segments - Market segments (e.g., Enterprise, SMB)
- Search Fields - Filter attributes grouped by type (built_for, platform, pricing_model)
List Parent Categories
requires authentication
Get all top-level parent categories for product classification. Parent categories represent broad product domains.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/catalog/parent-categories"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"id": 1,
"name": "Analytics"
},
{
"id": 2,
"name": "Communication"
},
{
"id": 3,
"name": "Marketing"
},
{
"id": 4,
"name": "Project Management"
},
{
"id": 5,
"name": "Sales"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List Categories
requires authentication
Get all detailed categories for product classification. Categories are more specific than parent categories and can be assigned to products.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/catalog/categories"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"id": 1,
"name": "Video Conferencing"
},
{
"id": 2,
"name": "Team Chat"
},
{
"id": 3,
"name": "Email Marketing"
},
{
"id": 4,
"name": "CRM"
},
{
"id": 5,
"name": "Task Management"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List Segments
requires authentication
Get all market segments for product targeting. Segments define the target audience or market size for products.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/catalog/segments"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"id": 1,
"name": "Enterprise"
},
{
"id": 2,
"name": "Mid-Market"
},
{
"id": 3,
"name": "SMB"
},
{
"id": 4,
"name": "Startup"
},
{
"id": 5,
"name": "Freelancer"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List Search Fields
requires authentication
Get all search field options grouped by type. Search fields are structured attributes used for filtering and discovery.
Field Types:
built_for- Target user roles or teams (e.g., "Marketing Teams", "Developers")platform- Deployment platforms (e.g., "Web", "iOS", "Android", "Desktop")pricing_model- Business models (e.g., "Subscription", "One-time", "Freemium")
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/catalog/search-fields"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": {
"built_for": [
{
"id": 1,
"name": "Marketing Teams"
},
{
"id": 2,
"name": "Sales Teams"
},
{
"id": 3,
"name": "Developers"
},
{
"id": 4,
"name": "HR Teams"
}
],
"platform": [
{
"id": 1,
"name": "Web"
},
{
"id": 2,
"name": "iOS"
},
{
"id": 3,
"name": "Android"
},
{
"id": 4,
"name": "Desktop"
}
],
"pricing_model": [
{
"id": 1,
"name": "Subscription"
},
{
"id": 2,
"name": "One-time Purchase"
},
{
"id": 3,
"name": "Freemium"
},
{
"id": 4,
"name": "Usage-based"
}
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Projects
APIs for managing projects within organisations
List Projects
requires authentication
Get all projects in an organisation that the user has access to.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/b47b1b40-d5f7-4e9c-959a-b7affbc9965c/projects"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Acme App",
"product_website": "https://acme.com",
"review_platforms": {
"g2": {
"enabled": true,
"url": "https://g2.com/products/acme"
}
},
"reddit_keywords": [
"acme",
"acme app"
],
"created_at": "2025-12-10T10:00:00.000000Z",
"updated_at": "2025-12-10T10:00:00.000000Z"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create Project
requires authentication
Create a new project in an organisation. Requires organisation admin role.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/b47b1b40-d5f7-4e9c-959a-b7affbc9965c/projects"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"product_name": "Acme App",
"product_website": "https:\/\/acme.com",
"product_logo": "https:\/\/cdn.brandfetch.io\/acme.com\/fallback\/lettermark\/icon?c=BRANDFETCH_CLIENT_ID",
"review_platforms": {
"g2": {
"enabled": true,
"url": "https:\/\/g2.com\/products\/acme"
},
"capterra": {
"enabled": false,
"url": null
}
},
"reddit_keywords": [
"acme",
"acme app"
],
"reddit_brand_name": "Acme",
"social_platform": {
"twitter": {
"enabled": true,
"url": "https:\/\/twitter.com\/acme"
}
}
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201):
{
"message": "Project created successfully.",
"data": {
"uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Acme App",
"product_website": "https://acme.com",
"product_logo": "https://cdn.brandfetch.io/acme.com/fallback/lettermark/icon?c=BRANDFETCH_CLIENT_ID",
"review_platforms": {},
"reddit_keywords": [
"acme"
],
"reddit_brand_name": "Acme",
"created_at": "2025-12-10T10:00:00.000000Z",
"updated_at": "2025-12-10T10:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get Project
requires authentication
Get details of a specific project.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/b47b1b40-d5f7-4e9c-959a-b7affbc9965c/projects/d94fca2e-1789-491b-88a9-03b5738dd218"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": {
"uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Acme App",
"product_website": "https://acme.com",
"review_platforms": {
"g2": {
"enabled": true,
"url": "https://g2.com/products/acme"
}
},
"reddit_keywords": [
"acme",
"acme app"
],
"created_at": "2025-12-10T10:00:00.000000Z",
"updated_at": "2025-12-10T10:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update Project
requires authentication
Update a project's details. Requires organisation admin role.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/b47b1b40-d5f7-4e9c-959a-b7affbc9965c/projects/d94fca2e-1789-491b-88a9-03b5738dd218"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"product_name": "Acme App Pro",
"product_website": "https:\/\/acme.com",
"product_logo": "https:\/\/cdn.brandfetch.io\/acme.com\/fallback\/lettermark\/icon?c=BRANDFETCH_CLIENT_ID",
"review_platforms": {
"g2": {
"enabled": true,
"url": "https:\/\/g2.com\/products\/acme"
},
"capterra": {
"enabled": false,
"url": null
}
},
"reddit_keywords": [
"acme",
"acme pro"
],
"reddit_brand_name": "Acme",
"social_platform": {
"twitter": {
"enabled": true,
"url": "https:\/\/twitter.com\/acme"
}
}
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "Project updated successfully.",
"data": {
"uuid": "660e8400-e29b-41d4-a716-446655440001",
"product_name": "Acme App Pro",
"product_website": "https://acme.com",
"product_logo": "https://cdn.brandfetch.io/acme.com/fallback/lettermark/icon?c=BRANDFETCH_CLIENT_ID",
"review_platforms": {},
"reddit_keywords": [
"acme",
"acme pro"
],
"reddit_brand_name": "Acme",
"created_at": "2025-12-10T10:00:00.000000Z",
"updated_at": "2025-12-10T10:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete Project
requires authentication
Delete a project. Requires organisation admin role.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/b47b1b40-d5f7-4e9c-959a-b7affbc9965c/projects/d94fca2e-1789-491b-88a9-03b5738dd218"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (200):
{
"message": "Project deleted successfully."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Review Views
APIs for managing saved review filter views (organization-scoped).
Get All Review Views
requires authentication
List all saved review views for the authenticated user in a specific organisation. Views are ordered by sort_order and creation date.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/660e8400-e29b-41d4-a716-446655440001/review-views"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"uuid": "a1b2c3d4-...",
"name": "Critical Reviews",
"sort_order": 0,
"filters": {
"brands": [
"uuid-1",
"uuid-2"
],
"platforms": [
"G2",
"Capterra"
],
"rating_buckets": [
"1.0-1.9",
"2.0-2.9"
],
"date_range": {
"type": "preset",
"value": "last_3_months"
}
},
"created_at": "2026-01-15T10:30:00.000Z",
"updated_at": "2026-01-20T14:22:00.000Z"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create Review View
requires authentication
Create a new saved review view for the authenticated user.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/660e8400-e29b-41d4-a716-446655440001/review-views"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "High Priority Reviews",
"filters": {
"platforms": [
"G2"
],
"rating_buckets": [
"1.0-1.9"
],
"brands": [
"uuid-1",
"uuid-2"
],
"date_range": {
"type": "preset",
"value": "last_3_months"
},
"date_range_custom": {
"start": "2026-01-01",
"end": "2026-01-24"
},
"languages": [
"en",
"de",
"es"
],
"read_status": "unread",
"search": "customer support",
"sort_by": "platform",
"sort_direction": "asc"
}
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201):
{
"data": {
"uuid": "e5f6g7h8-...",
"name": "High Priority Reviews",
"sort_order": 1,
"filters": {...},
"created_at": "2026-01-24T10:00:00.000Z",
"updated_at": "2026-01-24T10:00:00.000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get Review View
requires authentication
Get a specific saved review view.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/660e8400-e29b-41d4-a716-446655440001/review-views/a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": {
"uuid": "a1b2c3d4-...",
"name": "Critical Reviews",
"sort_order": 0,
"filters": {...},
"created_at": "2026-01-15T10:30:00.000Z",
"updated_at": "2026-01-20T14:22:00.000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update Review View
requires authentication
Update an existing saved review view. Can update name and/or filters.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/660e8400-e29b-41d4-a716-446655440001/review-views/a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Critical Reviews - Updated",
"filters": {
"platforms": [
"G2"
],
"brands": [
"a4855dc5-0acb-33c3-b921-f4291f719ca0"
],
"date_range": {
"type": "all_time",
"value": "last_3_months"
},
"date_range_custom": {
"start": "2026-02-03T13:58:49",
"end": "2052-02-27"
},
"rating_buckets": [
"5.0"
],
"languages": [
"architecto"
],
"read_status": "all",
"search": "n",
"sort_by": "created_at",
"sort_direction": "asc"
}
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"data": {
"uuid": "a1b2c3d4-...",
"name": "Critical Reviews - Updated",
"sort_order": 0,
"filters": {...},
"created_at": "2026-01-15T10:30:00.000Z",
"updated_at": "2026-01-24T11:15:00.000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete Review View
requires authentication
Delete a saved review view.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/organisations/660e8400-e29b-41d4-a716-446655440001/review-views/a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (204):
Empty response
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Slack Integration
APIs for connecting and managing Slack workspace integration
Slack OAuth Callback
Handles the OAuth callback from Slack after user authorization. Exchanges the authorization code for an access token. This endpoint is unauthenticated - uses cached state for auth context.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/integrations/slack/callback"
);
const params = {
"code": "123456789.abcdef",
"state": "abc123...",
"error": "access_denied",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"code": "architecto",
"state": "ngzmiyvdljnikhwaykcmyuwpwlvqwrsitcpscqldzsnrwtujwvlxjklqppwqbewt",
"error": "architecto"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (302, Success):
Redirects to /dashboard/notification/overview?slack_connected=true&workspace={name}
Example response (302, Error):
Redirects to /dashboard/notification/overview?slack_error={error_code}
Example response (302):
Show headers
cache-control: no-cache, private
location: https://subsig-frontend.vercel.app/dashboard/notification/overview?slack_error=architecto
content-type: text/html; charset=utf-8
vary: Origin
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url='https://subsig-frontend.vercel.app/dashboard/notification/overview?slack_error=architecto'" />
<title>Redirecting to https://subsig-frontend.vercel.app/dashboard/notification/overview?slack_error=architecto</title>
</head>
<body>
Redirecting to <a href="https://subsig-frontend.vercel.app/dashboard/notification/overview?slack_error=architecto">https://subsig-frontend.vercel.app/dashboard/notification/overview?slack_error=architecto</a>.
</body>
</html>
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Initiate Slack OAuth
requires authentication
Starts the OAuth flow to connect a Slack workspace. Redirects to Slack's authorization page.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/integrations/slack/connect"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (302, Redirect to Slack):
Redirects to Slack OAuth page
Example response (400, Not configured):
{
"error": "configuration",
"message": "Slack integration is not configured."
}
Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
vary: Origin
{
"message": "Unauthenticated."
}
Example response (403, No organisation):
{
"message": "Organisation context required."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get Slack Connection Status
requires authentication
Returns the current Slack connection status for the organisation.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/integrations/slack/status"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Connected):
{
"connected": true,
"team_id": "T123456789",
"team_name": "My Workspace",
"scopes": "chat:write,channels:read",
"connected_at": "2025-01-01T12:00:00Z"
}
Example response (200, Not connected):
{
"connected": false
}
Example response (200, Invalid token):
{
"connected": false,
"error": "token_invalid",
"message": "Slack connection needs to be re-authorized."
}
Example response (403, No organisation):
{
"message": "Organisation context required."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Disconnect Slack
requires authentication
Removes the Slack workspace connection for the organisation.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/integrations/slack/disconnect"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200, Success):
{
"success": true,
"message": "Slack connection removed."
}
Example response (200, Not connected):
{
"success": true,
"message": "No Slack connection found."
}
Example response (403, No organisation):
{
"message": "Organisation context required."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List Slack Channels
requires authentication
Fetches the list of channels from the connected Slack workspace.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/integrations/slack/channels"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"ok": true,
"channels": [
{
"id": "C123456789",
"name": "general",
"is_member": true
},
{
"id": "C987654321",
"name": "random",
"is_member": false
}
]
}
Example response (401, Not connected):
{
"ok": false,
"error": "not_connected",
"message": "Not connected to Slack."
}
Example response (401, Invalid token):
{
"ok": false,
"error": "token_invalid",
"message": "Slack connection needs to be re-authorized."
}
Example response (403, No organisation):
{
"message": "Organisation context required."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Subscriptions
APIs for managing subscriptions
List Subscription Plans
requires authentication
Get all available subscription plans.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/subscription-plans"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"id": 1,
"stripe_price_id": "price_1234567890",
"name": "Pro Plan",
"description": "Professional features",
"amount": 2999,
"currency": "usd",
"interval": "month"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create Checkout Session
requires authentication
Create a Stripe Checkout session for subscribing to a plan.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/subscriptions/checkout"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"plan_id": 1,
"success_url": "https:\/\/app.example.com\/subscription\/success",
"cancel_url": "https:\/\/app.example.com\/subscription\/cancel"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"checkout_url": "https://checkout.stripe.com/pay/cs_test_..."
}
Example response (403, No organisation access):
{
"message": "You do not have access to this organisation."
}
Example response (404, Plan not found):
{
"message": "Subscription plan not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get Current Subscription
requires authentication
Get the current subscription for the organisation.
Example request:
const url = new URL(
"https://backend-staging.subsig.com/api/subscriptions/current"
);
const headers = {
"Authorization": "Bearer 1|abc123...",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": {
"id": 1,
"stripe_subscription_id": "sub_1234567890",
"status": "active",
"current_period_start": "2025-12-01T00:00:00.000000Z",
"current_period_end": "2026-01-01T00:00:00.000000Z",
"plan": {
"id": 1,
"stripe_price_id": "price_1234567890",
"description": "Professional features",
"name": "Pro Plan",
"amount": 2999,
"currency": "usd",
"interval": "month",
"features": [
"Feature 1",
"Feature 2"
]
}
}
}
Example response (403, No organisation access):
{
"message": "You do not have access to this organisation."
}
Example response (404, No subscription):
{
"message": "No subscription found for this organisation."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.