*Gap samples / Gap 9 - API (developers)*

# Which EULER API to use, and your first three calls

The help center documents two different APIs without saying so. This page tells them apart, says which one new work should start on, and takes you from an API key to a submitted referral in three calls.

**Gap:** 9 of 13 · **Reader:** Developer, RevOps engineer · **Result:** A working key and one referral created

## Why this page needs to exist

The API overview exists: the [API Reference](https://api.eulerapp.com/docs) is thorough, with keys, scopes, errors, rate limits and OpenAPI. The gap is what sits next to it. The help center's [API & Webhooks > Authentication](https://support.eulerapp.com/en/c/api/authentication) article, updated 27 Aug 2026, documents a different API: you send a user's email and password to `eulerapp.com/api/1.1/wf/generate-api-token` and get a token valid for a year. A developer who starts in the help center builds on that one, and puts a password into a script to do it.

---

*Sample documentation starts here*

## The two APIs

|  | API v1 | Workflow endpoints |
| --- | --- | --- |
| **Base URL** | `https://api.eulerapp.com/v1` | `https://eulerapp.com/api/1.1/wf/...` |
| **Auth** | API key from **Settings > API access**, sent as `Authorization: Bearer` | A user's email and password, exchanged for a token |
| **Lifetime** | No scheduled expiry. Revoke one key without touching others. | Token valid one year |
| **Scope** | Full access, or restricted to chosen endpoints | Acts as the user |
| **Documented in** | api.eulerapp.com/docs | Help center: Authentication, Charges, eid, HubSpot Charges |

New integrations **should** start on API v1: it is the API the help center's own "API Reference" link points to, and it never needs a password. API access is in beta. If **API access** is missing under Settings, ask EULER support in your shared Slack channel to turn it on.

## Before you start

- API access is enabled on your account.
- You will call the API from a server. A full-access key acts as you, so it never goes in browser code.

## What can go wrong

- A key is shown once, when you create it. Lost it? Create a new one and revoke the old.
- Creating a referral is asynchronous. A retry without an `Idempotency-Key` can create a second referral.
- An expired key and a revoked key both return `401 invalid_token`. The `message` tells them apart. Retrying an expired key never helps.

## Steps

1. **Create a key and confirm it works**

   In **Settings > API access**, click **New key** and name it after the integration. Create one key per integration, so you can revoke them one at a time. Then call `GET /v1/me`.

   **REQUEST**

   ```
   curl https://api.eulerapp.com/v1/me \
     -H "Authorization: Bearer $EULER_API_KEY"
   ```

   **Check:** a `200` whose `data` names you and your company. Every successful response has a top-level `data` field.
2. **Find the form and its questions**

   A referral answers a partner's referral form. List the partner's forms, then fetch the questions of the one you want. Each question's `input_type` says which field carries its answer.

   **REQUESTS**

   ```
   curl "https://api.eulerapp.com/v1/referrals/forms?partner_id=$PARTNER_ID&referral_type=received" \
     -H "Authorization: Bearer $EULER_API_KEY"

   curl "https://api.eulerapp.com/v1/referrals/forms/$FORM_ID/questions?partner_id=$PARTNER_ID" \
     -H "Authorization: Bearer $EULER_API_KEY"
   ```

   **Check:** you have a form `id`, and a `question_id` for every question marked `required`.
3. **Create the referral, then poll it**

   Send one answer per question, with a unique `Idempotency-Key`. Free-text answers go in `answer_text`, dropdown and multiselect answers in `selected_options`.

   **REQUEST**

   ```
   curl -X POST https://api.eulerapp.com/v1/referrals \
     -H "Authorization: Bearer $EULER_API_KEY" \
     -H "Content-Type: application/json" \
     -H "Idempotency-Key: $(uuidgen)" \
     -d '{
       "partner_id": "'"$PARTNER_ID"'",
       "referral_form_id": "'"$FORM_ID"'",
       "answers": [
         { "question_id": "Q_FIRST_NAME", "answer_text": "Dana" },
         { "question_id": "Q_EMAIL", "answer_text": "dana.reyes@northwindfreight.example" },
         { "question_id": "Q_SIZE", "selected_options": ["11-50"] }
       ]
     }'
   ```

   The response is `202 Accepted` with the referral's `id`, while EULER runs its checks. Poll `GET /v1/referrals/{id}` until `status` is no longer `creating`.

   **Check:** the referral reaches `pending` and appears in the web app's approvals queue.

Question ids above are placeholders. Use the ids step 2 returned.

## What wrong looks like

**WRONG - AUTH IN A SCHEDULED SCRIPT**

```
curl -X POST https://eulerapp.com/api/1.1/wf/generate-api-token \
  -d '{"email":"ops-lead@yourco.example","password":"..."}'

Why it fails: a person's password now lives in a script,
the token acts as that person for a year, and revoking it
means changing their password. With API v1, create a key
restricted to the endpoints the script calls, and revoke
just that key when the script retires.
```

## Errors to branch on

| Response | Meaning | Do |
| --- | --- | --- |
| `401 invalid_token`, "invalid or revoked" | Wrong secret, or revoked | Check which key you send |
| `401 invalid_token`, "can no longer authenticate" | Key expired | Create a new key, switch, revoke the old |
| `403 insufficient_scope` | A restricted key called an endpoint it was not granted | Add the endpoint to the key's scopes |
| `409 idempotency_conflict` | A retry arrived while the first request was still running | Retry later with the same key |
| `422 validation_failed` | An answer is missing or invalid. `details` names each `question_id`. | Fix those answers |

## Confirm with engineering

1. The workflow endpoints are [deprecated on date / supported], and the help center articles should say so. Correct me.
2. `POST /v1/payments` replaces the workflow Charges endpoint. Yes / no / correct me.
3. The HubSpot-Reward webhook has a v1 equivalent at [endpoint], or stays on the workflow API. Correct me.
4. The API & Webhooks collection can link each legacy article to its v1 page. Yes / no.

### Related documentation

- [EULER API Reference](https://api.eulerapp.com/docs): [restricted keys](https://api.eulerapp.com/docs#restricting-keys), [errors](https://api.eulerapp.com/docs#errors), [rate limits](https://api.eulerapp.com/docs#ratelimit), [OpenAPI file](https://api.eulerapp.com/openapi.json)
- [Webhooks: receive events from EULER](https://support.eulerapp.com/en/c/api/webhooks-receive-events-from-euler)
- [Authentication](https://support.eulerapp.com/en/c/api/authentication), [Charges](https://support.eulerapp.com/en/c/api/charges), [eid](https://support.eulerapp.com/en/c/api/eid), [Hubspot Charges](https://support.eulerapp.com/en/c/api/hubspot-charges) (workflow endpoints)
- [Connecting EULER MCP to Your AI Assistant](https://support.eulerapp.com/en/c/euler-mcp-customers/getting-started) (no API key needed)

### Sources for this page

- API Reference (api.eulerapp.com/docs): keys, beta, restricted keys, expiry messages, response shape, referral forms and questions, POST /v1/referrals (202, creating, Idempotency-Key, 422 details), errors.
- Help center: Authentication (workflow token endpoint, email and password, one-year token), Charges, eid, HubSpot Charges.

### Next

- Gap 11: [Release notes](12-releasenotes.md). The v1 changes the Change Log never recorded.
- Gap 8: [Referral statuses](09-statuses.md). What "creating" and "pending" mean.

---

*Independent writing sample by Bachtiar Widyantoro (bachwidy.site), November 2026. Not published or endorsed by EULER. Free to reuse and edit. Customer names in examples are fictional. Anything marked [VALIDATE ...] or [CONFIRM ...] is not settled by a public source and needs checking before publishing.*
