This section covers the technical architecture behind servis.ai’s API and integration platform. It is intended for developers and technical architects who are building or maintaining integrations with external systems such as ERPs, data warehouses, or custom middleware.
Rate Limiting & Performance
Servis.ai protects API stability through Redis-backed token-bucket rate limiting via express-rate-limit with a Redis store. Rate limits vary by endpoint type to balance throughput with platform reliability.
Rate Limits & Performance
|
Endpoint Type
|
Rate Limit
|
Enforcement
|
|---|---|---|
|
Webhook Endpoints
|
100 requests / minute / IP
|
Gateway level
|
|
Bot & Tracking Endpoints
|
30 requests / minute / IP
|
Gateway level
|
|
GraphQL API
|
Configurable per deployment
|
Gateway level
|
Rate Limit Response: When a rate limit is exceeded, the API returns HTTP 429 Too Many Requests with a message indicating when to retry.
Recommendations for Bulk Operations
Follow these guidelines when performing bulk data operations such as initial migrations or periodic mass updates:
- Use Bulk API Endpoints — Endpoints such as bulkCreateEntityValues, bulkUpsertEntityValues, and bulkUpdateEntityValues accept arrays of records in a single request, dramatically reducing total API calls.
- Batch Your Records — Group records into batches of 100–500 per bulk call. Implement exponential backoff when receiving 429 responses.
- Use Upsert for Migrations — The bulkUpsertEntityValues endpoint updates existing records or creates new ones based on matching criteria, handling duplicates gracefully without manual deduplication.
- Schedule During Off-Peak Hours — Run large initial migrations during off-peak hours to avoid impacting interactive users.
- Consider CSV Import as an Alternative — For one-time data loads where programmatic API access is not required, the platform’s Import/Export subsystem supports CSV-based bulk imports directly through the UI.
Security & Authentication
Servis.ai supports both OAuth2 Authorization Code and Client Credentials grant types for API authentication. All OAuth tokens (access tokens and refresh tokens) are encrypted at rest using the platform’s encryptTokens() function before database storage.
OAuth2 Token Lifecycle
|
Token Type
|
Lifetime
|
Notes
|
|---|---|---|
|
Authorization Code
|
10 minutes
|
Single-use; exchanged for access + refresh tokens
|
|
Access Token
|
1 hour (default, configurable)
|
Included in the expires_in field of every token response
|
|
Refresh Token
|
No fixed expiry
|
Used to obtain new access tokens; stored encrypted per integration
|
Automated Token Refresh
Servis.ai runs a scheduled background job (refresh_integration_job) that proactively refreshes OAuth tokens for all active integrations. The job performs the following steps:
- Queries all integrations with a non-null oauth_refresh_token.
- Calls each integration’s authorization endpoint with the stored refresh token to obtain new access and refresh tokens.
- Updates the stored tokens (oauth_access_token, oauth_refresh_token, oauth_expires_at) — all encrypted at rest.
- If a refresh fails, the job nullifies the expired tokens and sends in-app notifications to tenant administrators with re-authorization instructions.
Integration Options for Your Middleware
Option A — Client Credentials Grant: Use grant_type: client_credentials with your client_id and client_secret to obtain fresh tokens programmatically. No user interaction is required. Best suited for server-to-server integrations.
Option B — Refresh Token Flow: When your middleware detects token expiry (via a 401 response or the expires_in field), call the /oauth/token endpoint with grant_type=refresh_token to obtain a new access token. The platform supports this natively through the OAuth2orize framework.
API Credential Scoping & Permissions
API credentials can be scoped to specific objects and operations. When generating an API key, only the scopes relevant to the integration are assigned. Three layers of access control are available:
- OAuth2 Scope-Based Permissions — API clients are created with a specific permissions array. Each permission maps to a defined set of GraphQL operations. For example, an integration scoped to account:read, account:create, deal:read, and deal:create would have zero access to Tasks, Activities, or other objects.
- Role-Based Access Control (RBAC) — The platform’s AuthorizationManager enforces role-level permissions at the entity and operation level. API credentials are associated with a specific user, and that user’s roles determine which Apps and records they can access.
- Access Control Lists (ACLs) — For fine-grained record-level access, ACLs can restrict which records within an App a given user (and therefore their API credentials) can see or modify. ACLs support conditions based on field values.
Available OAuth Scopes
|
Scope
|
Description
|
|---|---|
|
account:read / account:create
|
Read/write Accounts
|
|
deal:read / deal:create
|
Read/write Deals
|
|
lead:read / lead:create
|
Read/write Contacts/Leads
|
|
entity:read / entity:create
|
Generic entity access (all custom Apps)
|
|
activity:read / activity:create
|
Read/write Activities
|
|
field:read
|
Read field metadata and configurations
|
|
task:add
|
Create Tasks
|
Data Object Mapping: ERP ↔ Servis.ai
Servis.ai uses a metadata-driven architecture where all data objects are “Apps” (entities) with configurable fields. The following table shows how standard servis.ai Apps map to common ERP data objects. Custom Apps can be created to model any additional ERP objects (invoices, payments, AR balances, etc.) with fields that mirror your ERP’s data structure.
Standard Object Mapping
|
ERP Object
|
Servis.ai App
|
API Entity Name
|
Key API Operations
|
Notes
|
|---|---|---|---|---|
|
Customer Master
|
Accounts
|
logo
|
addLogo, updateLogo, updateLogoFields
|
Add ERP Customer ID as a custom field for cross-referencing
|
|
Contact Records
|
Contacts
|
contact
|
addLead, updateLead, updateLeadFields
|
Contacts can be associated with Accounts via reference fields
|
|
Sales Orders
|
Deals
|
deal
|
addDeal, updateDealFields
|
When a Deal stage moves to “Closed Won,” push to ERP
|
|
Activity Log
|
Tasks / Activities
|
task
|
addTask, updateTask
|
Includes follow-ups, calls, and meetings
|
|
Communication History
|
Emails
|
email_fa
|
CRUD via GraphQL
|
Sent/received emails with tracking data
|
|
Free-Text Attachments
|
Notes
|
note_fa
|
CRUD via GraphQL
|
Notes attached to any record type
|
Custom App Mapping (Examples)
For ERP objects that do not have a standard servis.ai equivalent, you can create custom Apps with fields that mirror your ERP’s data structure. The entity:read and entity:create OAuth scopes cover all custom Apps. Below are common examples:
|
ERP Object
|
Servis.ai Custom App (Example)
|
Suggested Fields
|
Sync Direction
|
|---|---|---|---|
|
Invoices
|
Invoices
|
Invoice Number, Amount, Status, Due Date, ERP Invoice ID, Account (reference)
|
ERP → Servis.ai
|
|
Payment Records
|
Payments
|
Payment Number, Amount, Date, Method, Invoice (reference), ERP Payment ID
|
ERP → Servis.ai
|
|
AR Balances
|
AR Balances
|
Account (reference), Balance Amount, Aging Bucket, Last Updated
|
ERP → Servis.ai
|
|
Price Lists
|
Price Lists
|
Product Name, Unit Price, Currency, ERP Product ID
|
ERP → Servis.ai
|
|
Shipping Status
|
Shipments
|
Order (reference), Tracking Number, Carrier, Status, ETA
|
ERP → Servis.ai
|
Note: The specific fields and mappings above are examples. Actual field configurations should be designed based on your ERP’s data model and business requirements during implementation.
Platform API Stability & Compatibility
Servis.ai’s API is designed for long-term integration stability. The following architectural mechanisms ensure that existing integrations continue to work as the platform evolves:
- Backward Compatibility Layer — The platform maintains an explicit backwardCompatibility module that preserves legacy API behaviors when schemas evolve. For example, task-related queries and mutations are aliased to their newer unified API equivalents, ensuring older integrations continue working without modification.
- Metadata-Driven Schema — Because the API is metadata-driven (field definitions and entity configurations are stored in the database, not hardcoded), structural changes to the data model do not break the API contract. New fields are additive — they appear in responses but do not remove existing fields.
- GraphQL Schema Stability — The GraphQL schema is generated dynamically from entity configurations. Adding new types, fields, or mutations is inherently non-breaking in GraphQL. Breaking changes (removing fields, changing types) are avoided.
- Migration Safeguards — Database migrations are applied incrementally with DDL/DML scripts, and the platform maintains full migration history. Any API-breaking schema changes would require coordinated migration and advance communication.
Integration Environments & Testing
Servis.ai provides multiple environments and tools for building, testing, and validating integrations before going live.
Staging Environment
A full staging environment is maintained that mirrors the production architecture. This environment is available for integration testing.
Tenant Isolation
Servis.ai is a multi-tenant platform with full tenant isolation. Data is partitioned per team via team_id sharding (e.g., fa_entity_values_{teamId}). Your development tenant is completely isolated from other customers’ data.
Clone Tenants
The platform supports tenant cloning, which can be used to create a duplicate of your production configuration for testing purposes without affecting live data.
Integration Test Modal
The Integration framework includes a test modal in the UI that lets you execute and debug integration connectors using real payloads before activating them.
Outbound Webhooks for Real-Time Triggers
Servis.ai supports outbound webhooks that enable real-time notifications to external systems when record events occur (create, update, delete).
- Webhook Endpoints — The platform exposes a dedicated webhook system at /webhook/{teamId}/{webhookId} that can be configured to fire when record events occur. For example, when a Deal closes, an automation rule can trigger an outbound HTTP call to your external system’s endpoint.
- Execution Modes — Webhooks support two execution modes — synchronous (the caller waits for a response) and asynchronous (fire-and-forget with job queuing). For most integration scenarios, async mode is recommended.
- Custom Payload Transformation — Webhook handlers can execute custom JavaScript code, giving full control over payload transformation. You can map servis.ai record fields directly to your external system’s expected schema before the HTTP request is sent.
- Security — Webhooks support signature verification (secure_webhook flag) to validate inbound requests to your systems.
- Execution Audit Trail — Every webhook execution is tracked with its own job_run record, including the automation triggered, response body, and links to workflow history — providing a complete audit trail for troubleshooting.
Monitoring & Diagnosis
The following monitoring and diagnostic capabilities are available to support integration reliability:
- Structured Logging — All API calls, webhook executions, integration runs, and OAuth flows are logged through the platform’s structured logging system (FALogger). Logs include contextual metadata for rapid diagnosis.
- Job Run History — Job runs (including webhook executions) are stored in the job_run table with full execution details, input/output payloads, and error information.
- Proactive Token Monitoring — The scheduled refresh_integration_job continuously monitors OAuth token health. If a token refresh fails (e.g., external credentials expire), the system automatically nullifies the expired tokens and sends in-app notifications to tenant administrators.