Skip to main content

Base URL

https://api.routera.io
All paths in this reference are relative to that base URL.

Authentication

Integrations authenticate using the OAuth 2.0 client credentials grant.

1. Obtain an access token

POST /oauth2/token exchanges client_id and client_secret for a JWT. See Obtain access token for the full request format.
POST https://api.routera.io/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET
The response includes access_token, expires_in, and token_type (Bearer). There is no refresh token — request a new access token when it expires.

2. Call the API

Every other route requires the access token:
Authorization: Bearer <access_token>
The JWT must include a valid account context (set automatically for integrations linked to your account). Requests without it receive 401 with:
{ "message": "Unauthorized: missing account context", "error": true }

Routes

Authentication

RouteHTTP
/oauth2/tokenPOST

Objects API

RouteHTTP
/contacts, /companies, /deals, /ticketsGET, POST
/contacts/{contactId}, /companies/{companyId}, /deals/{dealId}, /tickets/{ticketId}GET, PATCH, DELETE

Routers API

RouteHTTP
/routersGET
/routers/{routerId}GET

Dispatch

RouteHTTP
/dispatch/routerPOST

Object types

The object type is inferred from the path segment:
Path segmentObject typeDefault response fields
/contactscontactsid, first_name, last_name, email, contact_owner, external_id, archived
/companiescompaniesid, company_name, description, industry, company_owner, external_id, archived
/dealsdealsid, deal_name, pipeline, deal_stage, deal_owner, external_id, archived
/ticketsticketsid, ticket_name, pipeline, ticket_owner, external_id, archived
Every response also includes created_at and updated_at (ISO 8601 UTC). When an object is archived, archived_by is added automatically.

Response format

All object endpoints return a flat JSON object. Custom field values appear at the top level next to id and external_id (there is no nested fields object).

Archived objects

Statearchivedarchived_by
Activefalseomitted
ArchivedISO timestamp stringuser or API client id who archived
DELETE archives the object; the record is retained with archived set to a timestamp.

Default properties

When the properties query parameter is omitted, each type returns its default field set from the table above, plus created_at and updated_at. Use ?properties=phone to request additional fields beyond the defaults (not a replacement list). Invalid or disallowed property names return 400. Supported on GET list, GET by id, and PATCH update responses.

List pagination

GET on a collection returns:
{
  "data": [ /* objects */ ],
  "pagination": { "limit": 10, "offset": 0, "count": 1 }
}
Query parameters: limit (default 10, max 100), offset (default 0), archived=true to include archived rows.

Write requests

POST (create) and PATCH (update) use the same JSON shape: a top-level fields object whose keys are field internal names.
{
  "fields": {
    "external_id": "ext-001",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.com"
  }
}
On create, send the fields you want to set. On update, send only the fields you want to change. POST responds with 201 and the created object.

System-managed fields

These fields cannot be sent in body.fields. Attempts return 400 (for example Field cannot be set: record_id):
FieldWhen set automatically
record_idDatabase on create — not set by the Objects API
create_datePOST create
last_modified_dateEvery POST create and PATCH update
*_owner_assigned_dateWhen an owner field is included in the request
created_at, updated_atObject-table timestamps; always in responses, never writable via fields
These fields remain readable via ?properties= on GET and PATCH responses.

Field validation

Validation is atomic: if any field in body.fields fails, the entire create or update is rejected with 400 and nothing is written.
field_type_idAccepted inputStored value
stringString (or coercible)String (email lowercased; website_url stored as canonical host/domain)
numberFinite numberString
booltrue, false, "true", "false""true" or "false"
datetimeISO 8601, RFC 2822, or numeric timestampISO 8601 UTC string
enumerationinternal_name or display name (case-insensitive)internal_name from DB field values
userUser UUID or emailEmail string
Enumeration allowed values come from the database (field.values for that field), including options added in the app — not a fixed list in code.

Required fields (POST create only)

Object typeRequirement
contactsAt least one of email, first_name, last_name
companiesAt least one of company_name, website_url
dealsdeal_name, deal_stage, pipeline
ticketsticket_name, ticket_stage, pipeline
PATCH does not require these fields, but every key in fields must exist on the object type and pass type validation.

Duplicate prevention (POST / PATCH)

POST and PATCH reject duplicate active records (non-archived) within the same account and object type. Conflicts return 409 with field indicating which key collided.
Object typeUnique keys checked (when present in body.fields or as external_id)
contactsemail, external_id
companieswebsite_url, external_id
dealsexternal_id
ticketsexternal_id
Deals and tickets have no other business unique keys; duplicate deal_name / ticket_name values are allowed unless external_id is provided. Example responses:
{
  "message": "A contact with this email already exists",
  "error": true,
  "field": "email"
}
{
  "message": "A deal with this external_id already exists",
  "error": true,
  "field": "external_id"
}
  • Re-sending the same POST body with the same key does not create a second record.
  • website_url variants such as https://www.foo.com and foo.com are treated as the same company.
  • Archived records are ignored; a new active record may reuse a key from an archived one.
  • Concurrent requests with the same key may still race without a database unique constraint (application-level check only).

Routers

GET /routers returns a paginated list of routers for the authenticated account. GET /routers/{routerId} returns a single router with flattened settings, users, and teams. See List routers and Get router.

Dispatch

POST /dispatch/router runs router assignment for an object. The body must include router_id and object_id. See Dispatch router.

Create records

Product overview for records and fields in Routera.