Skip to main content

API Reference

The Inhouse API provides programmatic access to all platform features, allowing you to integrate link management, app tracking, and customer data into your existing workflows and applications.
πŸš€ Getting Started? Check out our Quick Reference section below for the most common endpoints and authentication methods.

Quick Reference

πŸ” Authentication Methods

  • JWT Bearer Token: Authorization: Bearer {token} (24h expiry)
  • Project API Token: x-api-token-id: {id} + x-api-token-secret: {secret} (permanent)
  • Chrome Extension: x-inhouse-token-id: {id} + x-inhouse-token-secret: {secret} + x-inhouse-app: {app_id}

🌐 Base URLs

  • Production: https://api.tryinhouse.co/v1/api βœ… Recommended
  • Legacy: https://api.tryinhouse.co/api ⚠️ Deprecated

πŸ“Š Common Endpoints

MethodEndpointDescription
GET/projectsList projects
POST/links?project_id={id}Create link
GET/links?project_id={id}List links
GET/links/{id}Get link details
PATCH/links/{id}Update link
DELETE/links/{id}Archive link

πŸ› οΈ SDKs Available

  • JavaScript/Node.js: npm install @inhouse/sdk βœ…
  • Python: In development 🚧
  • Postman Collection: [email protected]

Table of Contents

Getting Started

Authentication

The Inhouse API supports multiple authentication methods to suit different use cases. Choose the method that best fits your needs:

1. JWT Bearer Tokens

For most applications, use JWT Bearer tokens which provide secure, time-limited access:
Authorization: Bearer YOUR_JWT_TOKEN
When to use:
  • Web applications with user sessions
  • Mobile applications
  • Short-lived API access
  • When you need automatic token expiration for security
Token Expiration: JWT tokens expire after 24 hours and must be refreshed using the refresh token. For server-to-server communication or long-running processes, use project API tokens:
x-api-token-id: YOUR_TOKEN_ID
x-api-token-secret: YOUR_TOKEN_SECRET
When to use:
  • Server-to-server communication
  • Background jobs and cron tasks
  • Long-running processes
  • When you need non-expiring tokens
Security Note: Project API tokens never expire and provide full access to the project. Keep them secure and rotate them regularly.

3. Chrome Extension Headers (For Browser Extensions)

For Chrome extensions and browser-based integrations:
x-inhouse-token-id: YOUR_TOKEN_ID
x-inhouse-token-secret: YOUR_TOKEN_SECRET
x-inhouse-app: YOUR_APP_ID
When to use:
  • Chrome browser extensions
  • Browser-based tools and integrations
  • Client-side applications that need persistent access
App ID: The x-inhouse-app header must match the Chrome extension ID registered in your project.

Base URL

# Production API (Recommended)
https://api.tryinhouse.co/v1/api

# Legacy endpoint (deprecated)
https://api.tryinhouse.co/api
Note: While both endpoints work, we recommend using the versioned API endpoint (/v1/api) for better stability and future compatibility.

Content Type

All API requests should include the Content-Type header:
Content-Type: application/json

Response Format

All API responses are returned in JSON format with the following structure: Success Response:
{
  "status": "success",
  "items": [ ... ],
  "item": { ... },
  "count": 10,
  "total": 100,
  "limit": 20,
  "offset": 0,
  "has_more": true,
  "next": "https://api.tryinhouse.co/v1/api/links?offset=20",
  "prev": "https://api.tryinhouse.co/v1/api/links?offset=0"
}
Error Response:
{
  "status": "error",
  "errors": [
    {
      "code": "VALIDATION_ERROR",
      "message": "Invalid request parameters",
      "loc": ["field_name"],
      "ctx": {
        "error": "Invalid email format"
      },
      "details": {}
    }
  ]
}

Authentication

Login

POST /auth/login
Request Body:
{
  "email": "[email protected]",
  "password": "your_password"
}
Response:
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "user_123",
    "email": "[email protected]",
    "first_name": "John",
    "last_name": "Doe"
  }
}

Request OTP for login

POST /auth/initiate-login
Request Body:
{
  "email": "[email protected]"
}

Refresh Token

POST /auth/refresh-token
Request Body:
{
  "refresh_token": "your_refresh_token"
}

Authentication Priority

The API checks authentication in the following order:
  1. JWT Bearer Token (Authorization header)
  2. Chrome Extension Headers (x-inhouse-token-id, x-inhouse-token-secret)
  3. Project API Tokens (x-api-token-id, x-api-token-secret)
If the first method fails, the API automatically falls back to the next method.

Authentication Examples

Example 1: Using JWT Bearer Token

Step 1: Login to get JWT token
curl -X POST https://api.tryinhouse.co/v1/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "your_password"
  }'
Response:
{
  "status": "success",
  "item": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": {
      "id": "user_123",
      "email": "[email protected]",
      "first_name": "John",
      "last_name": "Doe"
    }
  }
}
Step 2: Use JWT token for API calls
curl -X GET https://api.tryinhouse.co/v1/api/links?project_id=proj_123 \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json"

Example 2: Using Project API Tokens

** Use project token for API calls**
curl -X GET https://api.tryinhouse.co/v1/api/links?project_id=proj_123 \
  -H "x-api-token-id: token_123456" \
  -H "x-api-token-secret: secret_abcdef123456" \
  -H "Content-Type: application/json"

Using Chrome Extension Headers

curl -X POST https://api.tryinhouse.co/v1/api/chrome/events/track \
  -H "x-inhouse-token-id: token_123456" \
  -H "x-inhouse-token-secret: secret_abcdef123456" \
  -H "x-inhouse-app: app_789012" \ 
  -H "Content-Type: application/json" \
  -d '{
    "event_name": "user_action",
    "properties": {
      "action": "click",
      "screen": "home"
    }
  }'

Core Endpoints

Projects Management

List Projects

Retrieve all projects accessible to the authenticated user.
GET /projects
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Response:
{
  "status": "success",
  "items": [
    {
      "id": "proj_123456",
      "name": "Marketing Campaign 2024",
      "slug": "marketing-2024",
      "logo": "https://example.com/logo.png",
      "plan": "free"
    }
  ],
  "count": 1
}

Create Project

Create a new project.
POST /projects
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Request Body:
{
  "name": "Marketing Campaign 2024",
  "slug": "marketing-2024",
  "logo": "https://example.com/logo.png"
}
Response:
{
  "status": "success",
  "item": {
    "id": "proj_123456",
    "name": "Marketing Campaign 2024",
    "slug": "marketing-2024",
    "logo": "https://example.com/logo.png",
    "plan": "free",
    "created_at": 1705312200,
    "updated_at": 1705312200
  }
}

Get Project Details

Retrieve details for a specific project.
GET /projects/{project_id}
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • project_id (string, required): The unique identifier of the project
Response:
{
  "item": {
    "id": "proj_123456",
    "name": "Marketing Campaign 2024",
    "slug": "marketing-2024",
    "logo": "https://example.com/logo.png",
    "plan": "free",
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-01-15T10:30:00Z"
  },
  "message": "Success",
  "status": "ok"
}

Update Project

Update an existing project.
PUT /projects/{project_id}
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • project_id (string, required): The unique identifier of the project
Request Body:
{
  "name": "Updated Project Name",
  "logo": "https://example.com/new-logo.png"
}
Response:
{
  "item": {
    "id": "proj_123456",
    "name": "Updated Project Name",
    "slug": "marketing-2024",
    "logo": "https://example.com/new-logo.png",
    "plan": "free",
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-01-15T11:45:00Z"
  },
  "message": "Project updated successfully",
  "status": "ok"
}

List Project Members

Retrieve all members of a specific project.
GET /projects/{project_id}/members
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • project_id (string, required): The unique identifier of the project
Response:
{
  "items": [
    {
      "id": "member_123",
      "user_id": "user_456",
      "email": "[email protected]",
      "role": "admin",
      "joined_at": "2024-01-15T10:30:00Z"
    }
  ],
  "message": "Success",
  "status": "ok"
}

List Project Invites

Retrieve all pending invites for a project.
GET /projects/{project_id}/invites
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • project_id (string, required): The unique identifier of the project
Response:
{
  "items": [
    {
      "id": "invite_123",
      "email": "[email protected]",
      "role": "member",
      "status": "pending",
      "created_at": "2024-01-15T10:30:00Z",
      "expires_at": "2024-01-22T10:30:00Z"
    }
  ],
  "message": "Success",
  "status": "ok"
}

Create Project Invite

Send an invitation to join a project.
POST /projects/{project_id}/invites
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • project_id (string, required): The unique identifier of the project
Request Body:
{
  "email": "[email protected]",
  "role": "member"
}
Response:
{
  "item": {
    "id": "invite_123",
    "email": "[email protected]",
    "role": "member",
    "status": "pending",
    "created_at": "2024-01-15T10:30:00Z",
    "expires_at": "2024-01-22T10:30:00Z"
  },
  "message": "Invitation sent successfully",
  "status": "ok"
}

Get Project Invite

Retrieve details of a specific project invite.
GET /projects/invites/{invite_id}
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • invite_id (string, required): The unique identifier of the invite
Response:
{
  "item": {
    "id": "invite_123",
    "email": "[email protected]",
    "role": "member",
    "status": "pending",
    "created_at": "2024-01-15T10:30:00Z",
    "expires_at": "2024-01-22T10:30:00Z"
  },
  "message": "Success",
  "status": "ok"
}

Remove Project Invite

Cancel a pending project invitation.
DELETE /projects/{project_id}/invites/{invite_id}
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • project_id (string, required): The unique identifier of the project
  • invite_id (string, required): The unique identifier of the invite
Response:
{
  "message": "Invitation cancelled successfully",
  "status": "ok"
}

List Project Tokens

Retrieve all API tokens for a project.
GET /projects/{project_id}/settings/tokens
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • project_id (string, required): The unique identifier of the project
Response:
{
  "status": "success",
  "items": [
    {
      "id": "token_123",
      "name": "API Token",
      "description": "Token for server-to-server communication",
      "permissions": ["read", "write"],
      "created_at": "2024-01-15T10:30:00Z",
      "updated_at": "2024-01-15T10:30:00Z",
      "user_id": "user_123"
    }
  ],
  "count": 1
}

Create Project Token

Generate a new API token for a project. You can also create tokens through the dashboard at app.tryinhouse.co in the project settings. (preferably use the dashboard)
POST /projects/{project_id}/settings/tokens
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • project_id (string, required): The unique identifier of the project
Request Body:
{
  "name": "API Token",
  "description": "Token for server-to-server communication",
  "permissions": ["read", "write"]
}
Response:
{
  "status": "success",
  "item": {
    "id": "token_123456",
    "token": "ihp_abcdef123456789",
    "name": "API Token",
    "description": "Token for server-to-server communication",
    "permissions": ["read", "write"],
    "user_id": "user_123"
  }
}
Important: The token is only shown once when created. Store it securely as it cannot be retrieved later. Alternative: Create tokens through the dashboard at app.tryinhouse.co β†’ Project Settings β†’ API Tokens Create a new shortened link with optional tracking and customization features.
POST /links?project_id={project_id}
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Query Parameters:
  • project_id (string, required): The unique identifier of the project
Request Body:
{
  "url": "https://example.com/product/smartphone-2024",
  "title": "Latest Smartphone 2024",
  "description": "Check out our newest smartphone with advanced features",
  "domain": "yourdomain.com",
  "key": "smartphone-2024",
  "folder_id": "referrals",
  "expires_at": 1735689600,
  "password": "secure123",
  "track_conversion": true,
  "proxy": false,
  "android": "intent://example.com/product/smartphone-2024#Intent;scheme=https;package=com.example.app;end",
  "ios": "example://product/smartphone-2024",
  "utm_source": "email",
  "utm_medium": "newsletter",
  "utm_campaign": "smartphone_launch",
  "utm_term": "smartphone",
  "utm_content": "banner_ad",
  "public_stats": false,
  "playstore": "https://play.google.com/store/apps/details?id=com.example.app",
  "appstore": "https://apps.apple.com/app/example-app/id123456789",
  "deeplink_path": "/product/smartphone-2024",
  "website_link": "https://example.com",
  "link_data": {
    "category": "electronics",
    "price": "999.99",
    "brand": "ExampleBrand"
  },
  "refer_code": "SAVE20"
}
Response:
{
  "item": {
  "id": "link_123456",
  "short_url": "https://yourdomain.com/smartphone-2024",
  "url": "https://example.com/product/smartphone-2024",
  "title": "Latest Smartphone 2024",
  "key": "smartphone-2024",
  "clicks": 0,
  "unique_clicks": 0,
  "conversion_rate": 0.0,
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z"
  },
  "message": "Link created successfully",
  "status": "ok"
}
Retrieve detailed information about a specific link.
GET /links/{link_id}
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • link_id (string, required): The unique identifier of the link
Response:
{
  "item": {
  "id": "link_123456",
  "short_url": "https://yourdomain.com/summer-sale-2024",
  "destination_url": "https://example.com/landing-page",
  "custom_key": "summer-sale-2024",
    "title": "Summer Sale Campaign",
    "description": "Limited time summer sale with up to 50% off",
  "clicks": 150,
  "unique_clicks": 120,
  "conversion_rate": 0.08,
    "status": "active",
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z"
  },
  "message": "Success",
  "status": "ok"
}
Retrieve all links for a specific project with optional filtering and pagination.
GET /links?project_id={project_id}
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Query Parameters:
  • project_id (string, required): Project ID to filter links
  • limit (number, optional): Items per page (default: 100, max: 100)
  • offset (number, optional): Number of items to skip (default: 0)
  • archived (boolean, optional): Filter by archived status
  • link_type (string, optional): Filter by link type
  • slug (boolean, optional): Filter by slug presence
Response:
{
  "status": "success",
  "items": [
    {
      "id": "link_123456",
      "short_link": "https://yourdomain.com/summer-sale-2024",
      "url": "https://example.com/landing-page",
      "title": "Summer Sale Campaign",
      "description": "Limited time summer sale with up to 50% off",
      "domain": "yourdomain.com",
      "folder": "",
      "key": "summer-sale-2024",
      "clicks": 150,
      "unique_clicks": 120,
      "leads": 12,
      "sales": 3,
      "sale_amount": 450,
      "archived": false,
      "created_at": 1705312200,
      "updated_at": 1705312200,
      "bundle_id": "com.example.app",
      "app_installs": 5,
      "first_app_open_count": 3,
      "session_created_count": 8,
      "link_type": "standard",
      "metadata_title": "Summer Sale Campaign",
      "metadata_description": "Limited time summer sale with up to 50% off",
      "metadata_image": "https://example.com/image.jpg"
    }
  ],
  "count": 1
}
Update an existing link’s properties.
PATCH /links/{link_id}
Headers:
  • Authorization: Bearer {jwt_token} (required)
  • Content-Type: application/json
Path Parameters:
  • link_id (string, required): The unique identifier of the link
Request Body:
{
  "destination_url": "https://example.com/updated-landing",
  "title": "Updated Summer Sale Campaign",
  "description": "Updated description for the campaign"
}
Response:
{
  "data": {
    "id": "link_123456",
    "short_url": "https://yourdomain.com/summer-sale-2024",
    "destination_url": "https://example.com/updated-landing",
    "title": "Updated Summer Sale Campaign",
    "description": "Updated description for the campaign",
    "clicks": 150,
    "unique_clicks": 120,
    "conversion_rate": 0.08,
    "updated_at": "2024-01-15T11:45:00Z"
  },
  "message": "Link updated successfully",
  "status": 200
}

Domains Management

Apps Tracking

coming soon

Get App Analytics

coming soon

Chrome Extensions Management

List Extensions

GET /chromextensions?project_id={project_id}

Create Extension

POST /chromextensions
Request Body:
{
  "name": "My Extension",
  "store_id": "extension_id_123",
  "project_id": "proj_123456"
}

Update Extension

PUT /chromextensions/{extension_id}
Request Body:
{
  "name": "Updated Extension Name"
}

Get Extension

GET /chromextensions/{extension_id}

Events Tracking

Track Chrome Event

POST /chrome/events/track
Headers:
x-inhouse-token-id: YOUR_TOKEN_ID
x-inhouse-token-secret: YOUR_TOKEN_SECRET
x-inhouse-app: YOUR_APP_ID
Request Body:
{
  "event_name": "user_action",
  "properties": {
    "action": "button_click",
    "screen": "home"
  }
}

Customer Management

TODO: coming soon

Analytics and Reporting

TODO: coming soon

Webhooks

Webhooks allow you to receive real-time notifications when events occur in your Inhouse project. This enables you to build integrations and automate workflows based on link activity, user actions, and system events.

Setting Up Webhooks

contact [email protected]

Webhook Events

EventDescriptionPayload
link.createdNew link createdLink object with full details
link.updatedLink updatedUpdated link object
link.clickedLink clickedClick event with analytics data
link.archivedLink archivedLink ID and metadata

App Events

EventDescriptionPayload
app.createdNew app addedApp object with details
app.eventApp event trackedEvent data and properties
app.updatedApp updatedUpdated app object

Customer Events

EventDescriptionPayload
customer.createdNew customer addedCustomer object with details
customer.updatedCustomer updatedUpdated customer object
customer.status_changedCustomer status changedCustomer ID and new status

Error Response Format

{
  "status": "error",
  "errors": [
    {
      "code": "VALIDATION_ERROR",
      "message": "Invalid request parameters",
      "loc": ["email"],
      "ctx": {
        "error": "Invalid email format"
      },
      "details": {}
    }
  ]
}

Common Error Codes

Error CodeDescription
VALIDATION_ERRORRequest validation failed
AUTHENTICATION_REQUIREDAuthentication is required
INVALID_TOKENToken is invalid or expired
INSUFFICIENT_PERMISSIONSUser lacks required permissions
RESOURCE_NOT_FOUNDRequested resource doesn’t exist
RESOURCE_ALREADY_EXISTSResource with this identifier already exists
RATE_LIMIT_EXCEEDEDToo many requests
Best Practices:
  • Implement exponential backoff when receiving 429 responses
  • Monitor rate limit headers to avoid hitting limits
  • Consider upgrading your plan for higher limits

Best Practices

Authentication

  1. Use Project API Tokens for Server-to-Server Communication
    • More secure than JWT tokens for long-running processes
    • Never expire, reducing the need for token refresh logic
    • Store tokens securely using environment variables
  2. Implement Token Refresh for JWT Authentication
    • JWT tokens expire after 24 hours
    • Use refresh tokens to obtain new access tokens
    • Handle token expiration gracefully in your application
  3. Rotate API Tokens Regularly
    • Generate new tokens periodically
    • Revoke old tokens when no longer needed
    • Monitor token usage for security

Request Handling

  1. Use Appropriate HTTP Methods
    • GET for retrieving data
    • POST for creating resources
    • PATCH for partial updates
    • PUT for complete updates
    • DELETE for archiving resources
  2. Implement Proper Error Handling
    • Check HTTP status codes
    • Parse error messages for user feedback
    • Implement retry logic for transient errors
  3. Use Pagination for Large Datasets
    • Always specify limit parameter for list endpoints
    • Implement pagination in your UI
    • Use page parameter to navigate through results

Performance Optimization

  1. Cache Responses When Appropriate
    • Cache static data like project details
    • Implement cache invalidation strategies
    • Use appropriate cache headers
  2. Minimize API Calls
    • Batch operations when possible
    • Use filtering parameters to reduce data transfer
    • Implement client-side caching
  3. Monitor API Usage
    • Track rate limit consumption
    • Monitor response times
    • Set up alerts for errors

Security

  1. Never Expose API Tokens
    • Store tokens in environment variables
    • Never commit tokens to version control
    • Use different tokens for different environments
  2. Validate Input Data
    • Sanitize user input before sending to API
    • Validate required fields
    • Check data types and formats
  3. Use HTTPS Only
    • Always use HTTPS endpoints
    • Validate SSL certificates
    • Never send sensitive data over HTTP

Troubleshooting

Common Issues

πŸ” Authentication Problems

Issue: 401 Unauthorized errors
  • Cause: Invalid or expired token
  • Solution:
    • Check token format and validity
    • Refresh JWT tokens using /auth/refresh-token
    • Verify project API token credentials
Issue: 403 Forbidden errors
  • Cause: Insufficient permissions
  • Solution:
    • Check user role in project
    • Verify token has required permissions
    • Contact project admin for access

πŸ“ Validation Errors

Issue: 422 Unprocessable Entity errors
  • Cause: Invalid field values or missing required fields
  • Solution:
    • Check field validation rules in documentation
    • Ensure required fields are provided
    • Validate data types and formats

⏱️ Rate Limiting

Issue: 429 Too Many Requests errors
  • Cause: Exceeding rate limits
  • Solution:
    • Implement exponential backoff
    • Monitor rate limit headers
    • Consider upgrading plan for higher limits
Issue: Custom key conflicts
  • Cause: Key already exists in project
  • Solution:
    • Use unique custom keys
    • Let API generate random keys
    • Check existing links for conflicts

Debug Tips

  1. Enable Verbose Logging
    curl -v -X GET https://api.tryinhouse.co/v1/api/links \
      -H "Authorization: Bearer YOUR_TOKEN"
    
  2. Check Response Headers
    • Look for X-RateLimit-* headers
    • Check Content-Type is application/json
    • Verify X-Request-ID for support requests
  3. Validate JSON
    • Use JSON validators for request bodies
    • Check for trailing commas or syntax errors
    • Ensure proper escaping of special characters
  4. Test with Postman
    • Import our Postman collection
    • Use environment variables for tokens
    • Test authentication flows step by step

SDKs and Libraries

Official SDKs

TODO