Questions? Contact support
Public API & Webhooks
Connect ACOS to Zapier, Make, and your own backend using API keys and real-time webhook events. Available on Growth and above.
Overview
The ACOS public API lets you read and write data programmatically using standard REST conventions. All endpoints live at https://api.acos.auricorium.com/api/v1/ and accept application/json.
Webhooks let ACOS push events to your server the moment something happens — a deal is won, an invoice is paid, a task is completed. You subscribe to exactly the events you care about per webhook endpoint.
API keys and webhooks are available on the Growth plan and above. Growth plan keys are limited to read-only scopes. Write scopes and higher rate limits require the Scale plan.
Authentication
Pass your API key in the X-API-Key header on every request. Keys are created in Settings → API & Webhooks and shown exactly once at creation — store them in a secret manager immediately.
GET /api/v1/crm/contacts/ Host: api.acos.auricorium.com X-API-Key: acos_myorg_a1b2c3d4e5f6a1b2c3d4e5f6
Never expose API keys in client-side code or version control. Treat them like passwords. Rotate them immediately if compromised via Settings → API & Webhooks → Revoke.
Key format
Every key follows the pattern acos_{org_slug}_{ 24 hex chars}. The first 16 characters are the key prefix shown in the dashboard — useful for identifying which key made a request.
Rate limits
| Plan | Requests per day | Scope access |
|---|---|---|
| Growth | 1,000 | Read-only scopes |
| Scale | 10,000 | Read + write scopes |
| Enterprise | 10,000 | Read + write scopes |
When you exceed the daily limit, the API returns 429 Too Many Requests. The counter resets at midnight UTC.
Scopes
Each API key is issued with a set of scopes that control which endpoints it can access. You choose scopes at key creation time — a key cannot access anything outside its declared scopes.
| Scope | What it allows | Plan required |
|---|---|---|
read:crm | Read contacts, deals, proposals, activities | Growth+ |
write:crm | Create and update contacts and deals | Scale+ |
read:projects | Read projects, tasks, team members | Growth+ |
write:projects | Create and update projects and tasks | Scale+ |
read:finance | Read invoices, expenses, retainers | Growth+ |
write:time | Create time entries | Scale+ |
API Endpoints
The public API exposes the same endpoints your ACOS dashboard uses. All responses are JSON. List endpoints return plain arrays (no pagination wrapper). All data is scoped to your organization automatically.
CRM
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/crm/contacts/ | read:crm |
| GET | /api/v1/crm/contacts/{id}/ | read:crm |
| POST | /api/v1/crm/contacts/ | write:crm |
| GET | /api/v1/crm/deals/ | read:crm |
| GET | /api/v1/crm/deals/{id}/ | read:crm |
| POST | /api/v1/crm/deals/ | write:crm |
| PATCH | /api/v1/crm/deals/{id}/ | write:crm |
Projects & Tasks
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/projects/ | read:projects |
| GET | /api/v1/projects/{id}/ | read:projects |
| POST | /api/v1/projects/ | write:projects |
| GET | /api/v1/tasks/ | read:projects |
| POST | /api/v1/tasks/ | write:projects |
| PATCH | /api/v1/tasks/{id}/ | write:projects |
Finance
| Method | Path | Scope |
|---|---|---|
| GET | /api/v1/finance/invoices/ | read:finance |
| GET | /api/v1/finance/invoices/{id}/ | read:finance |
| GET | /api/v1/finance/expenses/ | read:finance |
Time
| Method | Path | Scope |
|---|---|---|
| POST | /api/v1/time/entries/ | write:time |
Example: create a contact
curl -X POST https://api.acos.auricorium.com/api/v1/crm/contacts/ \
-H "X-API-Key: acos_myorg_a1b2c3d4e5f6a1b2c3d4e5f6" \
-H "Content-Type: application/json" \
-d '{
"name": "Sarah Ahmed",
"email": "[email protected]",
"company": "Acme Corp"
}'Webhooks
Webhooks deliver a signed JSON POST request to your server URL every time a subscribed event occurs in ACOS. You can have multiple webhooks, each subscribed to a different set of events.
Setting up a webhook
- Go to Settings → API & Webhooks
- Click Add webhook
- Enter your HTTPS endpoint URL
- Select the events you want to receive
- Click Create webhook — your signing secret is shown immediately
Webhook endpoints must use HTTPS. HTTP endpoints are rejected at creation time. Your server must respond with a 2xx status code within 10 seconds or the delivery is marked as failed.
Event catalogue
| Event | Fires when |
|---|---|
deal.created | A new deal is added to the pipeline |
deal.stage_changed | A deal moves to a different pipeline stage |
deal.won | A deal is marked as Won |
deal.lost | A deal is marked as Lost |
proposal.sent | A proposal is sent to a client |
proposal.accepted | A client accepts a proposal |
project.created | A new project is created |
project.status_changed | A project status changes |
task.completed | A task is moved to Done |
invoice.created | An invoice is created |
invoice.sent | An invoice is sent to a client |
invoice.paid | An invoice is fully paid |
invoice.overdue | An invoice passes its due date unpaid |
time_entry.created | A time entry is logged |
Payload structure
Every webhook POST body follows the same envelope:
{
"event": "invoice.paid",
"organization_id": "a1b2c3d4-...",
"timestamp": "2026-06-30T14:22:01Z",
"data": {
"id": "inv_...",
"number": "INV-0042",
"total": "4500.00",
"currency": "USD"
// full object varies by event type
}
}Verifying signatures
Every request includes an X-ACOS-Signature header with an HMAC-SHA256 signature of the raw request body using your webhook secret. Always verify this before processing the payload.
import hmac
import hashlib
def verify_webhook(secret: str, payload: bytes, header: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), payload, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, header)
# Flask example
@app.route("/webhooks/acos", methods=["POST"])
def handle():
sig = request.headers.get("X-ACOS-Signature", "")
if not verify_webhook(WEBHOOK_SECRET, request.data, sig):
return "", 401
event = request.json
# process event["event"] ...
return "", 200// Node.js example
const crypto = require("crypto");
function verifyWebhook(secret, rawBody, header) {
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(header)
);
}
app.post("/webhooks/acos", express.raw({ type: "*/*" }), (req, res) => {
const sig = req.headers["x-acos-signature"] ?? "";
if (!verifyWebhook(process.env.WEBHOOK_SECRET, req.body, sig)) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body);
// process event.event ...
res.sendStatus(200);
});Retries
If your endpoint does not return a 2xx within 10 seconds, ACOS retries the delivery up to 3 times with exponential backoff: 1 minute, 5 minutes, then 30 minutes. After 3 failures the delivery is marked as failed — check the delivery log in Settings → API & Webhooks to inspect the response body.
Testing
Click the Play button next to any webhook in Settings → API & Webhooks to fire a test event. The delivery log below each webhook row shows all recent attempts with HTTP status codes and response bodies.
Managing Keys & Webhooks
Everything is managed in Settings → API & Webhooks. You must be an Owner to access this section.
- Create multiple keys with different scope sets — e.g. one read-only key for Zapier, one write key for your backend sync
- Revoke a key instantly; integrations using it stop working immediately
- Enable or disable individual webhooks without deleting them
- View the last 100 delivery attempts per webhook with full response bodies
Full API keys are shown exactly once at creation. If you lose a key, revoke it and create a new one — there is no way to retrieve a key after the creation dialog is closed.
FAQ
Can I use the API without creating an API key?
No. The public API requires an X-API-Key header on every request. JWT session tokens from the web app are not accepted on public API endpoints.
Why can't I create write-scope keys on the Growth plan?
Write access carries a higher risk profile. To keep Growth tier safe for smaller teams, write scopes are gated to Scale and above. Read-only keys on Growth cover most integration use cases (Zapier triggers, dashboards, reporting).
Do webhooks fire for events caused by API key requests?
Yes. If your API key creates a deal, the deal.created webhook fires just as it would from a human action in the dashboard.
What happens if my webhook endpoint is down for an extended period?
Deliveries are retried 3 times over ~36 minutes. After that, they are marked as failed and no further retries occur. There is no dead-letter queue — if you need guaranteed delivery, build idempotent reconciliation using the read API.
Is there an OpenAPI / Swagger spec?
A machine-readable OpenAPI 3.1 spec is on our roadmap. For now, this documentation and the endpoint tables above are the canonical reference.