Documentation

Go to Portal Website

Management API - Tenant And Features

This page covers tenant-level feature endpoints: Certificate Pinning certificates, custom messages, custom library generation, support tickets, billing helpers, tenant documents, sales contact requests, Tego Assistant, and AI Search.

All endpoints require an authenticated Management API caller and the tenant header unless stated otherwise.


Certificate Pinning Certificates

Certificate Pinning certificate endpoints update the CertificatePinning section of a tenant configuration version. They require the Certificates permission.

Update Certificates

Endpoint: POST /frontend/certificates_update

Permission: update_certificates

Updates the certificate list for one configuration version.

Request:

{
  "version": "1.2.3",
  "use_builtin_cas": true,
  "certificates": [
    {
      "name": "Example API",
      "thumbprint": "A1B2C3D4E5F60718293A4B5C6D7E8F9012345678",
      "algorithm": "sha256",
      "expires": 1767225600,
      "domains": [
        "api.example.com"
      ],
      "isdefault": false,
      "isca": false
    }
  ]
}

Response:

{
  "success": true
}

version must identify an existing tenant configuration version. certificates must be a list of custom certificate entries and can contain up to 50 entries. thumbprint is normalized to uppercase before storage.

Supported algorithms are:

domains may be supplied as a list or a single string. expires is a Unix timestamp.

use_builtin_cas controls whether built-in AppTego CA entries are included in the Certificate Pinning control. Built-in CA details can be inspected with /frontend/trusted_root_cas, documented in Configuration.

Delete Certificate

Endpoint: POST /frontend/certificates_delete

Permission: update_certificates

Deletes one certificate entry by name from a configuration version.

Request:

{
  "version": "1.2.3",
  "name": "Example API"
}

Response:

{
  "success": true
}

Custom Messages

Custom messages are available to Team and Enterprise tenants. Mutating endpoints require the Custom Messages permission.

Custom messages are stored per configuration version. The message body is a string and can be up to 5 MB (5,242,880 UTF-8 bytes), including HTML markup and inline CSS.

Get Custom Message

Endpoint: POST /frontend/get_custom_message

Permission: Any authenticated tenant user on a Team or Enterprise tenant

Request:

{
  "version": "1.2.3"
}

Response:

{
  "message": "Please contact your administrator.",
  "in_use": true
}

When no custom message exists for the version, the response is:

{
  "message": "",
  "in_use": false
}

Update Custom Message

Endpoint: POST /frontend/update_custom_message

Permission: manage_custom_messages

Request:

{
  "version": "1.2.3",
  "message": "Please contact your administrator."
}

Response:

{
  "success": true
}

Set Custom Message Active State

Endpoint: POST /frontend/set_custom_message_active

Permission: manage_custom_messages

Request:

{
  "version": "1.2.3",
  "in_use": true
}

Response:

{
  "success": true
}

Custom Library / BYOA

Custom Library generation is an Enterprise feature and must be enabled for the tenant. It generates Android and iOS library builds for approved application identifiers.

Get Custom Library Status

Endpoint: POST /frontend/custom_library_status

Permission: Any authenticated tenant user on an Enterprise tenant

Request:

{}

Response when enabled:

{
  "enabled": true,
  "max_identifiers": 3,
  "identifier_count": 1,
  "identifiers": [
    {
      "app_identifier": "com.example.production.app",
      "set_at": 1732740000,
      "set_by": "owner@example.com",
      "platform_cooldowns": {
        "android": {
          "cooldown_remaining_seconds": 0,
          "cooldown_remaining_days": 0
        },
        "ios": {
          "cooldown_remaining_seconds": 0,
          "cooldown_remaining_days": 0
        }
      },
      "builds": [
        {
          "build_id": "build-uuid",
          "platform": "android",
          "app_identifier": "com.example.production.app",
          "status": "success",
          "created_at": 1732740000,
          "completed_at": 1732740300,
          "error_message": null
        }
      ],
      "latest_by_platform": {
        "android": {
          "build_id": "build-uuid",
          "platform": "android",
          "app_identifier": "com.example.production.app",
          "status": "success",
          "created_at": 1732740000,
          "completed_at": 1732740300,
          "error_message": null
        }
      }
    }
  ]
}

Response when disabled:

{
  "enabled": false,
  "max_identifiers": 0,
  "identifiers": []
}

Build status values include pending, building, success, failed, and deleted.

Set App Identifier

Endpoint: POST /frontend/custom_library_set_identifier

Permission: modify_tenant_settings

Adds an application identifier and starts library-only builds for Android and iOS.

Request:

{
  "app_identifier": "com.example.production.app"
}

Response:

{
  "message": "App identifier set successfully",
  "app_identifier": "com.example.production.app"
}

The identifier must be reverse-DNS style, contain at least three segments, and be no more than 255 characters. Segments must be no more than 63 characters, start with a letter, and cannot use reserved or blocked prefixes such as com.example, com.android, or java.

Download Custom Library

Endpoint: POST /frontend/custom_library_download

Permission: Any authenticated tenant user on an Enterprise tenant

Downloads the latest successful build for a platform, or a specific successful build when build_id is supplied.

Request:

{
  "platform": "android",
  "build_id": "build-uuid"
}

build_id is optional.

Response:

{
  "url": "https://presigned-download-url.example"
}

The returned URL expires after one hour.

Delete Custom Library Identifier

Endpoint: POST /frontend/custom_library_delete

Permission: build_applications

Deletes all custom library builds for an application identifier and removes the identifier record.

Request:

{
  "app_identifier": "com.example.production.app"
}

Response:

{
  "message": "Libraries for com.example.production.app deleted successfully"
}

Deletion is blocked while any library build for the identifier is pending or building. After a successful build, deletion is also blocked until the platform cooldown has expired. The implemented cooldown is 30 days.


Support Tickets

Support tickets are available for Team and Enterprise tenants. These endpoints do not require a specific tenant permission beyond authenticated tenant access.

Limits:

LimitValue
Open tickets per tenant10
Comments per ticket20
Subject length200 characters
Description length5000 characters
Comment length5000 characters
AttachmentsPNG or JPEG only, maximum 5 MB decoded size

Ticket statuses are Reported, With Support, For Customer Response, and Resolved.

List Tickets

Endpoint: GET /frontend/support/tickets

Response:

{
  "tickets": [
    {
      "ticket_id": "ticket-uuid",
      "tenant_id": "9f1c0a4e7b8d4a4db52e6a6d5c5c1f11",
      "tenant_name": "Example Tenant",
      "tenant_plan": "TEAM",
      "user_id": "owner@example.com",
      "subject": "Build question",
      "status": "Reported",
      "created_at": 1732740000,
      "updated_at": 1732740000
    }
  ]
}

Create Ticket

Endpoint: POST /frontend/support/tickets

Request:

{
  "subject": "Build question",
  "description": "Can you help us understand this build failure?",
  "attachment": "base64-encoded-png-or-jpeg",
  "attachment_name": "screenshot.png",
  "attachment_type": "image/png"
}

Attachment fields are optional. attachment must be Base64 encoded file content.

Response:

{
  "success": true,
  "ticket_id": "ticket-uuid"
}

New tickets start with status Reported.

Get Ticket

Endpoint: GET /frontend/support/tickets/{ticket_id}

Response:

{
  "ticket_id": "ticket-uuid",
  "tenant_id": "9f1c0a4e7b8d4a4db52e6a6d5c5c1f11",
  "tenant_name": "Example Tenant",
  "tenant_plan": "TEAM",
  "user_id": "owner@example.com",
  "subject": "Build question",
  "description": "Can you help us understand this build failure?",
  "status": "Reported",
  "created_at": 1732740000,
  "updated_at": 1732740000,
  "comments": [
    {
      "comment_id": "comment-uuid",
      "user_id": "owner@example.com",
      "comment_text": "Here is more context.",
      "created_at": 1732740600
    }
  ],
  "attachments": [
    {
      "attachment_id": "attachment-uuid",
      "comment_id": null,
      "file_name": "screenshot.png",
      "file_type": "image/png",
      "uploaded_by": "owner@example.com",
      "created_at": 1732740000
    }
  ]
}

Add Comment

Endpoint: POST /frontend/support/tickets/{ticket_id}/comments

Request:

{
  "comment_text": "Here is more context.",
  "attachment": "base64-encoded-png-or-jpeg",
  "attachment_name": "screenshot.jpg",
  "attachment_type": "image/jpeg"
}

Attachment fields are optional.

Response:

{
  "success": true,
  "comment_id": "comment-uuid"
}

Download Attachment

Endpoint: GET /frontend/support/attachments/{attachment_id}

Response:

{
  "file_name": "screenshot.png",
  "file_type": "image/png",
  "file_data": "base64-encoded-file-content"
}

Billing Helpers

Billing helper endpoints use Stripe subscription data for the current tenant. Mutating endpoints require Tenant Settings.

Check Subscription

Endpoint: POST /frontend/payment/check-subscription

Permission: Any authenticated tenant user

Request:

{}

Response:

{
  "subscription": "active"
}

subscription is active or inactive.

Create Checkout Session

Endpoint: POST /frontend/payment/create-checkout-session

Permission: modify_tenant_settings

Request:

{
  "subscription": "team"
}

Response:

{
  "url": "https://checkout.stripe.com/..."
}

subscription must match an available Stripe plan key, such as team or enterprise.

Update Subscription

Endpoint: POST /frontend/payment/update-subscription

Permission: modify_tenant_settings

Request:

{
  "subscription": "enterprise"
}

Response:

{
  "success": true,
  "message": "Subscription updated successfully"
}

Cancel Subscription

Endpoint: POST /frontend/payment/cancel-subscription

Permission: modify_tenant_settings

Request:

{}

Response:

{
  "success": true,
  "message": "Subscription will be cancelled at the end of the billing period"
}

Create Billing Portal Session

Endpoint: POST /frontend/payment/create-portal-session

Permission: modify_tenant_settings

Request:

{}

Response:

{
  "url": "https://billing.stripe.com/..."
}

List Invoices

Endpoint: POST /frontend/payment/list-invoices

Permission: modify_tenant_settings

Request:

{}

Response:

{
  "invoices": [
    {
      "id": "in_123",
      "number": "ABCD-0001",
      "amount_paid": 99.0,
      "currency": "USD",
      "status": "paid",
      "created": 1732740000,
      "period_start": 1732740000,
      "period_end": 1735332000,
      "invoice_pdf": "https://pay.stripe.com/invoice/.../pdf",
      "hosted_invoice_url": "https://invoice.stripe.com/..."
    }
  ]
}

Tenant Documents

Tenant document endpoints return standard legal documents and tenant-specific custom documents.

List Documents

Endpoint: GET /frontend/documents

Permission: Any authenticated tenant user

Response:

{
  "documents": [
    {
      "name": "Terms of Service",
      "filename": "terms.pdf",
      "category": "legal",
      "description": "Terms and conditions for using AppTego.",
      "base_url": "/documents/legal/team/",
      "type": "standard"
    },
    {
      "name": "Security Addendum",
      "filename": "security-addendum.pdf",
      "category": "custom",
      "description": "Tenant-specific document.",
      "type": "custom"
    }
  ]
}

Free tenants receive the standard Free-plan legal document list and a base_url for the static files. Paid tenants receive tier-specific standard documents plus any tenant custom documents.

Download Custom Document

Endpoint: GET /frontend/documents/download?filename={filename}

Permission: Any authenticated tenant user on a Team or Enterprise tenant

Response:

{
  "url": "https://presigned-download-url.example"
}

The returned URL expires after five minutes. Free-plan standard documents are served directly from the base_url returned by /frontend/documents and do not use this download endpoint.


Sales Contact Requests

Sales contact requests let an authenticated tenant user request AppTego sales follow-up for Team or Enterprise plans. Requests have a seven-day per-user cooldown.

Check Sales Contact Cooldown

Endpoint: GET /frontend/sales_contact/status

Permission: Any authenticated tenant user

Response:

{
  "on_cooldown": false,
  "cooldown_until": null
}

Request Sales Contact

Endpoint: POST /frontend/sales_contact/request

Permission: Any authenticated tenant user

Request:

{
  "tier": "ENTERPRISE"
}

tier must be TEAM or ENTERPRISE.

Response:

{
  "message": "We'll contact you shortly.",
  "on_cooldown": true,
  "cooldown_until": 1733344800
}

When the user is still on cooldown, the endpoint returns 429 with on_cooldown and cooldown_until.


Tego Assistant

Tego Assistant endpoints are available on all plans. Default weekly tenant limits are 10 messages for Free, 100 for Team, and 1000 for Enterprise. Tenant-specific overrides may apply.

The response still includes a monthly_limit field for compatibility; it mirrors the active weekly limit.

Send Message

Endpoint: POST /frontend/helpbot/chat

Permission: Any authenticated tenant user

Request:

{
  "message": "How do I configure Certificate Pinning?"
}

Messages must be 2000 characters or less.

Response:

{
  "response": "Certificate Pinning is configured from the configuration controls...",
  "phases": [
    {
      "expert": "Tego",
      "status": "Analysing your question..."
    },
    {
      "expert": "Tego",
      "status": "Preparing your answer..."
    }
  ],
  "messages_used": 4,
  "weekly_limit": 100,
  "monthly_limit": 100,
  "allowed_again_at": 1733097600,
  "allowed_again_at_utc": "2024-12-02T00:00:00Z"
}

When the weekly limit is reached, the endpoint returns 429 with weekly_limit, monthly_limit, messages_used, allowed_again_at, and allowed_again_at_utc.

Get Conversation History

Endpoint: GET /frontend/helpbot/history

Response:

{
  "messages": [
    {
      "role": "user",
      "content": "How do I configure Certificate Pinning?"
    },
    {
      "role": "assistant",
      "content": "Certificate Pinning is configured from the configuration controls..."
    }
  ]
}

Clear Conversation History

Endpoint: POST /frontend/helpbot/clear

Response:

{
  "success": true
}

Get Usage Status

Endpoint: GET /frontend/helpbot/status

Response:

{
  "weekly_limit": 100,
  "monthly_limit": 100,
  "messages_used": 4,
  "messages_remaining": 96,
  "allowed_again_at": 1733097600,
  "allowed_again_at_utc": "2024-12-02T00:00:00Z"
}

AI Search converts natural language into query and time-window parameters for audit and device log searches. It does not return log rows directly.

AI Search is available for Team and Enterprise tenants. Monthly tenant limits are 100 queries for Team and 200 for Enterprise.

Convert Natural Language Query

Endpoint: POST /frontend/nl_search_query

Permission: Any authenticated tenant user on a Team or Enterprise tenant

Request:

{
  "mode": "audit",
  "query": "configuration changes from last week"
}

mode must be audit or device. query must be 500 characters or less.

Response:

{
  "query": "event_type = 'configuration_change'",
  "from_iso": "2024-11-18T00:00:00Z",
  "to_iso": "2024-11-25T00:00:00Z",
  "usage": {
    "used": 12,
    "limit": 100
  }
}

Use the returned query, from_iso, and to_iso values with the relevant log search endpoint in Monitoring and Logs. The endpoint may return 422 when the model cannot interpret the query reliably.


Common Errors

StatusMeaning
400Missing field, invalid field value, unsupported file type, exceeded feature limit, or blocked operation such as an active custom library cooldown.
401Authentication failed.
403Missing permission, missing feature enablement, or plan-gated feature.
404Requested ticket, attachment, document, custom library build, or identifier was not found.
409Custom library deletion was blocked by an in-progress build.
422AI Search could not interpret the natural language query.
429Tego Assistant limit or sales contact cooldown reached.
500Internal error.