Hanna CRM opportunities proposals
A Wantly proposal can be linked to one Hanna CRM opportunity (pardavimo galimybė). One opportunity can have many proposals, for example the versions V1, V2, V3 made by cloning. Hanna records are identified by their uuid, as returned by the Hanna API v4.
hanna_opportunity answer {"status":"error","data":"hanna integration disabled"}. Reading and filtering existing links works either way.All requests use your Wantly API key: the key body field, an X-Api-Key header, or Authorization: Bearer. See API key.
| Task | Request |
|---|---|
| Create a proposal for an opportunity | POST /api/createproposal with hanna_opportunity |
| Link, move or unlink an existing proposal | POST /api/editproposal with hanna_opportunity |
| List the proposals of an opportunity | GET /api/hanna/proposals?opportunity=, or POST /api/getproposals with hanna_opportunity |
| Open Wantly from a button in Hanna | Browser link /hanna/open?opportunity= |
Create a proposal for an opportunity
POST /api/createproposal accepts these fields on top of the usual ones. When hanna_opportunity is sent, entries may be left out (an empty proposal is created).
hanna_opportunityThe Hanna opportunity to link. Wantly reads it from Hanna and uses its subject as the proposal name unless you send one. An unknown uuid returns an error and nothing is created.
hanna_clientThe Hanna client. Default: the opportunity's client. Wantly reads the company name, company code, VAT code, e-mail, phone, address and the opportunity's contact person, and creates or updates the Wantly contact (matched by company code). A contact object you send yourself wins.
user_emailE-mail of the Wantly user who becomes the author. Default: the Wantly user with the same e-mail as an opportunity assignee in Hanna, else the first user. author (Wantly user id) also works.
{
"key": "YOUR_API_KEY",
"hanna_opportunity": "9b2f1c64-0e1a-4c7e-8a51-2f0d5e3b7a10",
"user_email": "manager@example.com"
}
With products from the start:
{
"key": "YOUR_API_KEY",
"hanna_opportunity": "9b2f1c64-0e1a-4c7e-8a51-2f0d5e3b7a10",
"name": "Client X - Christmas gifts V1",
"entries": [
{ "product": "Termopuodelis XYZ", "sku": "XYZ123", "price": 8.5, "ammount": 100, "pvm": 21 }
]
}
The response adds edit_url (the proposal editor) and hanna (the link, see below):
{
"status": "ok",
"data": {
"proposal": { "id": 812, "name": "Client X - Christmas gifts", "client": "Client X UAB", "url": "k3j9x0pq2m", ... },
"entries": [],
"url": "https://example.wantly.eu/offer/k3j9x0pq2m",
"edit_url": "https://example.wantly.eu/editproposalnew/k3j9x0pq2m",
"hanna": { "opportunity": "9b2f1c64-…", "opportunity_number": "GAL-0042", ... }
}
}
Link, move or unlink an existing proposal
POST /api/editproposal with the proposal id or url. Other edit fields can be sent in the same request.
hanna_opportunityA uuid links the proposal, or moves it to that opportunity. "" or null removes the link. Leave the field out to keep the current link. An unknown uuid returns an error and no other field in the request is applied. The client data of the proposal is not changed.
hanna_clientStored with the link. Default: the opportunity's client.
{ "key": "YOUR_API_KEY", "id": 812, "hanna_opportunity": "9b2f1c64-0e1a-4c7e-8a51-2f0d5e3b7a10" }
{ "key": "YOUR_API_KEY", "id": 812, "hanna_opportunity": "" }
The response has data.hanna with the new link, or null after unlinking. Moving a proposal to another opportunity resets its "sent to Hanna" state, so the approved lines are sent again to the new opportunity.
List the proposals of an opportunity
Option 1: GET /api/hanna/proposals
Made for Hanna's opportunity window: every linked proposal, newest first, with links to open it. Also accepts POST with a JSON body.
GET /api/hanna/proposals?opportunity=9b2f1c64-0e1a-4c7e-8a51-2f0d5e3b7a10
X-Api-Key: YOUR_API_KEY
{
"status": "ok",
"data": {
"opportunity": "9b2f1c64-0e1a-4c7e-8a51-2f0d5e3b7a10",
"latest": {
"id": 813, "nr": "2026-0143", "name": "Client X - Christmas gifts V2",
"status": 4, "status_name": "Confirmed", "accepted": true,
"total": 850.0, "currency": "EUR", "created": "2026-10-20", "linked_at": "2026-10-20 09:12:44",
"cloned_from": 812, "sent_to_hanna_at": "2026-10-21 10:14:03", "is_latest": true,
"offer_url": "https://example.wantly.eu/offer/…",
"edit_url": "https://example.wantly.eu/editproposalnew/…"
},
"proposals": [ { "id": 813, ... }, { "id": 812, ... } ],
"new_proposal_url": "https://example.wantly.eu/hanna/open?new=1&opportunity=9b2f1c64-…"
}
}
latest is null when the opportunity has no proposal yet. Deleted proposals are left out. total is without VAT.
Option 2: POST /api/getproposals with a filter
The full proposal list, filtered by the link. Pagination, sorting and the other filters work as usual.
hanna_opportunityOnly proposals linked to this opportunity.
hanna_clientOnly proposals linked to opportunities of this Hanna client. Can be combined with hanna_opportunity.
{
"key": "YOUR_API_KEY",
"hanna_opportunity": "9b2f1c64-0e1a-4c7e-8a51-2f0d5e3b7a10",
"orderby": "id",
"order": "desc"
}
The hanna object in responses
getproposals returns hanna on every proposal, getproposal returns it as data.proposal.hanna, and createproposal / editproposal return it as data.hanna. It is null when the proposal is not linked.
"hanna": {
"opportunity": "9b2f1c64-0e1a-4c7e-8a51-2f0d5e3b7a10",
"opportunity_number": "GAL-0042",
"opportunity_name": "Client X - Christmas gifts",
"client": "5d0c7a2e-6b1f-4f3a-9e0d-1a2b3c4d5e6f",
"client_name": "Client X UAB",
"cloned_from": 812,
"sent_to_hanna_at": "2026-10-21 10:14:03"
}
cloned_from: the proposal this version was cloned from. sent_to_hanna_at: when the approved lines were last written into the opportunity, or null.
Open Wantly from Hanna (browser link)
For a button in Hanna's opportunity window, no API key needed:
https://YOUR_ACCOUNT.wantly.eu/hanna/open?opportunity=OPPORTUNITY_UUID
https://YOUR_ACCOUNT.wantly.eu/hanna/open?opportunity=OPPORTUNITY_UUID&new=1
The first opens the latest proposal of the opportunity, or creates one when there is none. new=1 always creates a new one. The user must be signed in to Wantly.
What Wantly writes back to Hanna
When the client confirms a linked proposal (or a manager presses Send to Hanna), Wantly replaces the opportunity's line items with the products the client selected, at the final unit price, through Hanna's PATCH /opportunities/{uuid}. Print details go into the line description. If the admin mapped a Hanna stage to the proposal status, the stage is changed too. This happens automatically; there is no API call for it.
Errors
{"status":"error","data":"hanna integration disabled"}
{"status":"error","data":"hanna: HTTP 404: not_found"}
{"status":"error","data":"hanna: Hanna rejected the API token (401)."}
{"status":"error","data":"opportunity required"} // GET /api/hanna/proposals without opportunity (HTTP 422)