API Reference

Build on your CRM
with the Eutexa API

A versioned REST API for reading and writing your CRM from Make, n8n, Zapier, or your own code. JSON in, JSON out, over HTTPS.

https://api.eutexa.com/api/v1
Quick start

Your first request

  1. 1

    In Eutexa, open Settings → Developer and click New API key. Only the super administrator and admins can create one.

  2. 2

    Name it after the integration, pick its scopes, and create it. The key is shown once — copy it now, because it is stored only as a hash and can never be shown again.

  3. 3

    Send it as the X-Api-Key header on every request.

Check the key works. /ping needs no scope, so it is always a clean test of the credential itself:

curl https://api.eutexa.com/api/v1/ping \
  -H "X-Api-Key: eutx_live_your_key_here"

It answers with the workspace the key belongs to:

{
  "success": true,
  "data": {
    "workspaceId": "6650a1b2c3d4e5f600000099",
    "workspace": "Acme Corp",
    "email": "you@acme.com",
    "connectionLabel": "Acme Corp (you@acme.com)"
  }
}

Then read some data, or write some:

curl "https://api.eutexa.com/api/v1/contacts?limit=20" \
  -H "X-Api-Key: $EUTEXA_API_KEY"

curl -X POST https://api.eutexa.com/api/v1/contacts \
  -H "X-Api-Key: $EUTEXA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"firstName":"Jordan","email":"jordan@example.com"}'

Seeing /api/api/v1?

The base URL is https://api.eutexa.com/api/v1 — the host serves everything under /api, and this API's own prefix is /v1. If your URL has /api twice, you have appended the prefix to a base that already carried it. Strip one and the call will work.

Authentication

Two ways to authenticate

Both resolve to the same workspace context, so every endpoint behaves identically whichever you use.

API key — for Make, n8n and your own code

A workspace-scoped secret sent as a header. This is what you want for a server-side integration or a script.

X-Api-Key: eutx_live_xxxxxxxxxxxxxxxxxxxxxxxx
  • Shown once at creation and stored only as a hash — it cannot be recovered.
  • Limited to the scopes you choose, which cannot be edited afterwards. To change them, create a new key and revoke the old one.
  • Active keys per workspace: 2 on Starter, 10 on Pro, unlimited on Enterprise.
  • It authenticates as the whole workspace and carries no role, which is why creating one needs admin rights.
  • It is a secret. Keep it server-side — never in browser code, a mobile app, or a public repository.

OAuth2 — for platforms

Authorization Code grant, used by the official Zapier app. Your platform sends the user to Eutexa to log in, pick a workspace and approve; you receive an access token (valid one hour) and a rotating refresh token.

Authorization: Bearer <access_token>

GET  https://api.eutexa.com/api/v1/oauth/authorize
POST https://api.eutexa.com/api/v1/oauth/token

Clients are registered by us — get in touch for a client id and secret. The grant is a single crm scope; the API-key scopes below do not narrow an OAuth token, because its grant is agreed at authorize time and the user approves it in a browser. Access can be revoked from Eutexa settings at any time.

Scopes

What a key is allowed to reach

Every key carries the scopes you picked when you created it. Call an endpoint the key does not cover and you get 403 INSUFFICIENT_SCOPE, with the missing scope named in requiredScope so you know exactly what to add.

A scope narrows which endpoints, never which records: a key with contacts:readreads every contact in the workspace. Keys created before scopes existed keep full access and show as “Full access” in Developer settings.

Grant these three sparingly

email:send and sequences:write send mail to your contacts from your own mailbox, and ai:run spends AI credits. Everything else only moves data inside your CRM.

Read

contacts:readList, search and fetch contacts, including their email, phone and custom fields.
companies:readList, search and fetch companies.
opportunities:readList and fetch deals, including their value and stage-change history.
tasks:readList and fetch tasks and their assignees.
tickets:readList and fetch support tickets.
activities:readRead the timeline: notes, calls, meetings and logged emails.
products:readList, search and fetch products and their prices.
invoices:readList and fetch invoices and their totals.
meetings:readList and fetch meetings and their summaries.
sequences:readList email sequences.
forms:readRead submissions to your forms, including the raw answers.
email:readRead replies received against email you sent from Eutexa.
metadata:readRead pipeline and stage names plus workspace member names and emails, for dropdowns.

Write

contacts:writeCreate and update contacts. Counts against your plan contact limit.
companies:writeCreate companies.
opportunities:writeCreate deals in any pipeline.
tasks:writeCreate and update tasks.
tickets:writeCreate support tickets.
activities:writeLog notes and activities onto a contact or deal timeline.
products:writeCreate products in the catalog.
sequences:writeEnroll a contact into a sequence, which sends them email on your schedule.
email:sendSend email from your connected mailbox. Counts against your monthly send limit.
ai:runRun Co-Pilot, generate email copy and enrich contacts. Spends AI credits from your workspace pool.
Conventions

The same rules on every endpoint

  • Newest first. Lists are ordered so a polling integration sees new records at the top.
  • Stable ids. Every record carries a top-level id. Use it to de-duplicate.
  • Paging. limit is 1 to 100 (default 50), page is 1-based.
  • Incremental pulls. since takes an ISO 8601 timestamp and returns records at or after it. Add updated=true to work from last-updated instead of created.
  • Junk ids are ignored. An unparseable record id in a query parameter is dropped rather than erroring, so a stray dropdown value cannot break a request.
  • One error shape. Failures return { success: false, error: { code, message } } with a meaningful status. Stack traces are never returned.
Endpoints

Every route in v1

All paths are relative to https://api.eutexa.com/api/v1. The scope column is what an API key must hold to call it.

Contacts

GET/contactscontacts:readList contacts, newest first.
GET/contacts/searchcontacts:readFind by ?email= — pairs with create for find-or-create.
GET/contacts/:idcontacts:readFetch one contact.
POST/contactscontacts:writeCreate a contact. Dedupes by email, then phone.
PUT/contacts/:idcontacts:writeUpdate a contact. All fields optional.

Companies

GET/companiescompanies:readList companies.
GET/companies/searchcompanies:readFind by ?domain= or ?name=.
GET/companies/:idcompanies:readFetch one company.
POST/companiescompanies:writeCreate a company. Domain is derived from the website.

Opportunities

Deals. Omit pipelineId and stageId to use the workspace default pipeline.

GET/opportunitiesopportunities:readList deals. Filter by ?status= or ?pipelineId=.
GET/opportunities/changesopportunities:readEach stage transition as a dedupable record.
GET/opportunities/:idopportunities:readFetch one deal.
POST/opportunitiesopportunities:writeCreate a deal.

Tasks

GET/taskstasks:readList tasks.
GET/tasks/:idtasks:readFetch one task.
POST/taskstasks:writeCreate a task.
PUT/tasks/:idtasks:writeUpdate a task, including marking it complete.

Tickets

GET/ticketstickets:readList support tickets.
GET/tickets/:idtickets:readFetch one ticket.
POST/ticketstickets:writeCreate a ticket.

Activities

The contact and deal timeline: notes, calls, meetings and logged email.

GET/activitiesactivities:readList timeline entries. Filter by ?type= or ?contactId=.
POST/activitiesactivities:writeLog a note or activity onto a record.

Products

unitPrice is in whole currency units. Invoice and proposal totals use integer cents instead.

GET/productsproducts:readList catalog products.
GET/products/searchproducts:readFind by ?name= or ?sku=.
GET/products/:idproducts:readFetch one product.
POST/productsproducts:writeCreate a product.

Invoices

Read-only. Totals and line items are integer cents.

GET/invoicesinvoices:readList invoices. Filter by ?status=.
GET/invoices/:idinvoices:readFetch one invoice.

Meetings

Read-only.

GET/meetingsmeetings:readList meetings.
GET/meetings/:idmeetings:readFetch one meeting and its summary.

Sequences

Enrolling sends email to the contact on the sequence schedule, and counts against your monthly enrollment limit.

GET/sequencessequences:readList email sequences.
POST/sequences/:id/enrollsequences:writeEnroll a contact.

Form submissions

Read-only. Spam submissions are excluded.

GET/form-submissionsforms:readList submissions. Filter by ?formId=.

Email

Sending uses your connected mailbox and counts against your monthly send limit.

POST/email/sendemail:sendSend an email.
GET/email/repliesemail:readReplies received against email sent from Eutexa.

AI

Every AI endpoint spends credits from your workspace pool and needs a plan that includes AI. On Starter Lite they return PLAN_FEATURE_REQUIRED.

POST/ai/run-copilotai:runRun a Co-Pilot turn. 5 credits.
POST/ai/generate-emailai:runDraft email copy. 2 credits.
POST/ai/enrich-contactai:runEnrich a contact. 5 credits.

Metadata

For building dropdowns instead of asking people to paste record ids.

GET/pipelinesmetadata:readPipelines with their stages, default first.
GET/usersmetadata:readWorkspace owner and active members, for assignee pickers.
Errors

What a failure looks like

{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_SCOPE",
    "message": "This API key does not have the \"email:send\" scope.",
    "requiredScope": "email:send"
  }
}
400VALIDATION_ERRORBad or missing input.
401UNAUTHORIZEDCredential missing, invalid, expired or revoked.
402TRIAL_EXPIRED / PAYMENT_REQUIREDSubscription inactive. Reads may still work when only past due.
403INSUFFICIENT_SCOPEThe key lacks this endpoint's scope. The response names it in requiredScope.
403PLAN_LIMIT_REACHEDA plan resource limit was hit.
403PLAN_FEATURE_REQUIREDYour plan does not include this feature.
404NOT_FOUNDNo such record.
409DUPLICATEA matching record exists. The response carries existingId.
429RATE_LIMITEDMore than 300 requests in a minute from this IP.
500INTERNAL_ERRORUnexpected server error.
Limits and versioning

Staying inside the lines

Rate limits

300 requests per minute per IP across all v1 endpoints, returning 429 beyond it. The budget is per IP rather than per key, so several keys behind one server share it. Read ratelimit-remaining and ratelimit-reset from the response headers instead of guessing.

Versioning

This is v1. New fields are added without notice and are safe to ignore. Anything that would break an existing integration — a rename, a removal — only ever appears under a new prefix such as /api/v2.

Stuck on something?

Send us the endpoint, the status code and the correlation id from the response headers, and we will tell you exactly what happened.