Make your first call
This guide walks you from “I have credentials” to “I have data” in three steps. It assumes the onboarding team has already issued you a client_id, client_secret, and at least one test companyId. If not, contact support@estimateone.com.
Before you start
You need:
- Your
client_idandclient_secret. - A
companyIdyour application is registered against. - A terminal with
curl.
Set them in your shell so the snippets below stay copy-pasteable:
export E1_CLIENT_ID="<your_client_id>"export E1_CLIENT_SECRET="<your_client_secret>"export E1_COMPANY_ID="<your_company_id>"Step 1 — Exchange your credentials for a bearer token
curl -s -X POST https://auth.api.estimateone.com/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=$E1_CLIENT_ID" \ -d "client_secret=$E1_CLIENT_SECRET" \ -d "scope=speci-finder/read"You’ll get back something like:
{ "access_token": "eyJhbGc...", "token_type": "Bearer", "expires_in": 3600}The access_token is good for one hour. Cache it in memory; don’t persist it to disk. See Authentication — Token lifecycle.
To pipe the token into the next call, capture it in a shell variable:
export E1_TOKEN=$(curl -s -X POST https://auth.api.estimateone.com/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=$E1_CLIENT_ID" \ -d "client_secret=$E1_CLIENT_SECRET" \ -d "scope=speci-finder/read" | jq -r .access_token)Step 2 — Call the Supplier API
The endpoint requires two headers: the bearer token and a separate x-e1-client-id header that must match the client_id you used to obtain the token.
curl -s \ "https://api.estimateone.com/api/supplier/v1/companies/$E1_COMPANY_ID/speci-finder/results" \ -H "Authorization: Bearer $E1_TOKEN" \ -H "x-e1-client-id: $E1_CLIENT_ID"If you forget the x-e1-client-id header you’ll get 400 CLIENT_ID_HEADER_MISSING; if it doesn’t match the token you’ll get 401 CLIENT_ID_HEADER_MISMATCH. See Errors.
Step 3 — Read the response
A successful call returns a data array of matched projects:
{ "data": [ { "projectId": "12345", "projectName": "Main Street Development", "tenders": [ { "id": "67890", "name": "Bulk Earthworks", "type": "Tender", "status": "Open", "matchedKeywords": ["concrete", "formwork"] } ], "url": "https://app.estimateone.com/find-tenders?projectId=12345" } ]}Full response shape: Supplier API reference.
200 OK with data: [] is normal
An empty array means “the call succeeded but nothing matched right now.” It’s not an error — common reasons listed in Data freshness — Why your response might be empty.
Where to go next
- Code examples — the same call in Node and Python.
- Use the API from Zapier — wire a Zap up against the API.
- Conventions — JSON shapes, dates, identifiers.
- Errors — full catalogue with remediation guidance.
- Rate limits — 100 requests per 5 minutes per credential, plus fair-use guidance.