API reference · v1 · Partner beta
Healthcare procurement over plain HTTPS: requests for quotation, quotations, purchase orders, direct deals, four-eyes approvals and a provider client book — the same API the Wasilah portal runs on. Partner access is in beta; keys on request.
Capabilities
Reference
01
Two sides use the API. Clients — hospitals, clinics, medical centres — ask for quotations, compare them, order and approve. Providers — suppliers, manufacturers, distributors — answer requests, offer direct deals, confirm orders and keep their own client book. Every call acts for one organisation, the one the token belongs to; you never see another organisation’s documents.
Beta: paths and fields follow the OpenAPI spec of the running platform. Some field names are older than the product language (hospitalId means client, supplierRef means provider) and will get aliases before v1 is final.
02
Ask for partner access. You receive a client ID and secret bound to your organisation on Wasilah.
Request access →Client-credentials grant against our OpenID Connect server. Tokens live five minutes — fetch a new one when it expires.
curl -X POST "https://auth.wasilah.net/realms/wasilah/protocol/openid-connect/token" \
-d grant_type=client_credentials \
-d client_id=$WASILAH_CLIENT_ID \
-d client_secret=$WASILAH_CLIENT_SECRET
# → { "access_token": "eyJ…", "expires_in": 300, "token_type": "Bearer" }Send it as a bearer token. /me tells you who you are, which organisation you act for and your role.
curl -X GET "https://api.wasilah.net/api/me" \
-H "Authorization: Bearer $WASILAH_TOKEN"03
https://api.wasilah.net/apiAuthorization: Bearer <token> — OAuth 2.0 / OIDC, token from auth.wasilah.net/realms/wasilah/protocol/openid-connect/tokenContent-Type: application/json with a body.id and a readable businessId: RFQ-20001-26-00042, QUO-10001-26-00017, PO-20001-26-00008 (type, organisation, year, serial).ORG-1xxxx are providers, ORG-2xxxx are clients.2026-11-30T17:00:00Z. Dates without time: 2026-12-15.currency (JOD, SAR, AED, USD).POST /rfqs/{id}/publish), not by writing status. A wrong state answers 409.04
A client (hospital, clinic) describes what it needs; providers answer with quotations. Draft, optional four-eyes approval, publish now or on a schedule, close, award.
status
SCHEDULED → PUBLISHED at the set time · CANCELLED from PUBLISHED
| Method | Path | What it does | Who |
|---|---|---|---|
| GET | /rfqs | List RFQs — filter with status, hospitalId | Both |
| POST | /rfqs | Create a draft RFQ with items and a closing date | Client |
| GET | /rfqs/{id} | One RFQ with its items | Both |
| PUT | /rfqs/{id} | Edit a draft | Client |
| DELETE | /rfqs/{id} | Delete a draft | Client |
| POST | /rfqs/{id}/submit-for-approval | Send to an approver (four-eyes) | Client |
| POST | /rfqs/{id}/approve | Approve a submitted RFQ | Client |
| POST | /rfqs/{id}/reject | Send it back with a reason | Client |
| POST | /rfqs/{id}/publish | Publish to providers now | Client |
| POST | /rfqs/{id}/schedule | Publish automatically at scheduledDate | Client |
| GET | /rfqs/{id}/quotations | All quotations received for the RFQ | Client |
| POST | /rfqs/{id}/select-winning-quotation | Award the RFQ to one quotation | Client |
status and the approval state are separate: a DRAFT can be pending, approved or rejected; only an approved (or approval-free) draft can be published.
curl -X POST "https://api.wasilah.net/api/rfqs" \
-H "Authorization: Bearer $WASILAH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Surgical gloves, Q3",
"category": "Medical consumables",
"closingDate": "2026-11-30T17:00:00Z",
"items": [
{
"description": "Nitrile gloves, size M, powder-free",
"quantity": 20000,
"specifications": {
"standard": "EN 455"
}
},
{
"description": "Nitrile gloves, size L, powder-free",
"quantity": 12000
}
]
}'Response
{
"id": "7f1c…",
"businessId": "RFQ-20001-26-00042",
"title": "Surgical gloves, Q3",
"status": "DRAFT",
"closingDate": "2026-11-30T17:00:00Z",
"createdAt": "2026-10-23T10:12:00Z"
}05
A provider answers an RFQ line by line — have, don’t have, or an alternative — with prices, lead times and terms.
lifecycle
REJECTED by the client
| Method | Path | What it does | Who |
|---|---|---|---|
| POST | /quotations | Draft a quotation for an RFQ | Provider |
| PUT | /quotations/{id} | Edit the draft | Provider |
| POST | /quotations/{id}/submit | Submit it to the client | Provider |
| GET | /quotations | Your quotations | Both |
| GET | /quotations/{id} | One quotation with its items | Both |
| GET | /quotations/rfq/{rfqRef} | Quotations for one RFQ | Client |
| POST | /quotations/{id}/accept | Accept a quotation | Client |
| POST | /quotations/{id}/reject | Decline a quotation | Client |
| DELETE | /quotations/{id} | Delete a draft | Provider |
curl -X POST "https://api.wasilah.net/api/quotations" \
-H "Authorization: Bearer $WASILAH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rfqRef": "RFQ-20001-26-00042",
"supplierRef": "ORG-10001",
"validUntil": "2026-12-15",
"paymentTerms": "Net 60",
"deliveryTerms": "DDP Amman",
"items": [
{
"rfqItemId": "a3e…",
"description": "Nitrile gloves M",
"quantity": 20000,
"unit": "piece",
"unitPrice": 0.042,
"leadTime": "14 days",
"responseType": "HAVE"
},
{
"rfqItemId": "b81…",
"description": "Latex-free vinyl gloves L",
"quantity": 12000,
"unit": "piece",
"unitPrice": 0.035,
"responseType": "ALTERNATIVE"
}
]
}'06
An accepted quotation becomes a purchase order; the client approves it, the provider confirms and fulfils it.
status
PENDING_APPROVAL with four-eyes · CANCELLED
| Method | Path | What it does | Who |
|---|---|---|---|
| POST | /purchase-orders | Create a PO from an accepted quotation (quotationRef) | Client |
| GET | /purchase-orders | Your purchase orders | Both |
| GET | /purchase-orders/{id} | One purchase order | Both |
| PUT | /purchase-orders/{id} | Edit before approval | Client |
| POST | /purchase-orders/{id}/approve | Approve the PO | Client |
| POST | /purchase-orders/{id}/confirm | Confirm the PO | Provider |
curl -X POST "https://api.wasilah.net/api/purchase-orders" \
-H "Authorization: Bearer $WASILAH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"quotationRef": "QUO-10001-26-00017"
}'Response
{
"id": "2c9…",
"businessId": "PO-20001-26-00008",
"quotationRef": "QUO-10001-26-00017",
"status": "DRAFT"
}07
A provider offers something without an RFQ — broadcast to all clients or sent to one. The client accepts or rejects; deals expire on their own.
status
REJECTED · CANCELLED · EXPIRED after validUntil
| Method | Path | What it does | Who |
|---|---|---|---|
| POST | /deals | Create a deal with items and a total | Provider |
| PUT | /deals/{id} | Edit a draft | Provider |
| POST | /deals/{id}/publish | Offer it to every client | Provider |
| POST | /deals/{id}/send | Offer it to one client (clientRef) | Provider |
| POST | /deals/{id}/cancel | Withdraw the offer | Provider |
| GET | /deals/supplier | Deals you offer | Provider |
| GET | /deals/client | Deals offered to you | Client |
| GET | /deals/published | Open deals for everyone | Client |
| POST | /deals/{id}/accept | Accept a deal | Client |
| POST | /deals/{id}/reject | Decline a deal | Client |
curl -X POST "https://api.wasilah.net/api/deals/{id}/send" \
-H "Authorization: Bearer $WASILAH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clientRef": "ORG-20001"
}'Response
{
"businessId": "DEAL-2026-003",
"status": "SENT",
"clientName": "King Hussein Cancer Center",
"totalAmount": 18400,
"currency": "JOD",
"validUntil": "2026-11-15",
"canBeAccepted": true
}08
Four-eyes rules per organisation: which documents need an approver, and the queue of open approval requests.
| Method | Path | What it does | Who |
|---|---|---|---|
| GET | /approval-requests | Open and past approval requests | Both |
| GET | /approval-requests/{id} | One request | Both |
| POST | /approval-requests/{id}/approve | Approve | Both |
| POST | /approval-requests/{id}/reject | Reject with a reason | Both |
| GET | /workflows | Approval workflows of your organisation | Both |
| POST | /workflows | Create a workflow | Both |
| POST | /workflows/{id}/activate | Switch a workflow on (or /deactivate) | Both |
curl -X POST "https://api.wasilah.net/api/approval-requests/{id}/reject" \
-H "Authorization: Bearer $WASILAH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reason": "Budget code missing"
}'09
Providers keep their own customer records — credit limits, payment terms, contacts — and link them to verified organisations on Wasilah. Bulk import from your ERP.
linkStatus
REJECTED
| Method | Path | What it does | Who |
|---|---|---|---|
| GET | /v1/provider-clients | All client records (or /active) | Provider |
| POST | /v1/provider-clients | Add a client record | Provider |
| POST | /v1/provider-clients/import | Bulk import; links automatically where it can | Provider |
| GET | /v1/provider-clients/{id}/suggestions | Matching organisations on Wasilah | Provider |
| POST | /v1/provider-clients/{id}/link | Link to an organisation | Provider |
| PUT | /v1/provider-clients/{id} | Update CRM data | Provider |
| GET | /v1/provider-clients/stats | Totals by link status | Provider |
curl -X POST "https://api.wasilah.net/api/v1/provider-clients/import" \
-H "Authorization: Bearer $WASILAH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clients": [
{
"tradeLicenseNumber": "JO-123456",
"legalName": "Jordan Hospital",
"creditLimit": 50000,
"paymentTerms": "Net 30",
"contactEmail": "[email protected]"
},
{
"tradeLicenseNumber": "JO-778899",
"legalName": "Al Khalidi Medical Center",
"paymentTerms": "Net 45"
}
]
}'Response
{
"totalRecords": 2,
"imported": 2,
"skipped": 0,
"linkedAutomatically": 1,
"errors": []
}10
Who is calling, which organisation they act for, and the members of that organisation.
| Method | Path | What it does | Who |
|---|---|---|---|
| GET | /me | The caller: user, organisation, role, portal | Both |
| GET | /organizations/my | Your organisation | Both |
| PUT | /organizations/{id} | Update your organisation profile | Both |
| GET | /organizations/{orgId}/members | Members and their roles | Both |
| GET | /v1/providers | Directory of approved providers | Client |
| GET | /v1/providers/{id} | One provider profile | Client |
11
Everything that happened to your documents — new quotation, approval needed, deal accepted — as a feed you can poll.
| Method | Path | What it does | Who |
|---|---|---|---|
| GET | /notifications | All notifications | Both |
| GET | /notifications/unread/count | Unread counter (cheap to poll) | Both |
| PATCH | /notifications/{id}/read | Mark one as read | Both |
| PATCH | /notifications/read-all | Mark all as read | Both |
12
Spend and response figures per organisation, and a complete, append-only history of every document.
| Method | Path | What it does | Who |
|---|---|---|---|
| GET | /analytics/hospital/{hospitalId} | Client figures: spend, RFQs, quotations | Client |
| GET | /analytics/supplier/{supplierId} | Provider figures: win rate, revenue | Provider |
| GET | /audit/{entityType}/{entityId} | Who changed what, when — per document | Both |
13
No token needed.
| Method | Path | What it does |
|---|---|---|
| GET | /public/info | API name, version, auth server |
| GET | /public/health | Health of the API and its dependencies |
| GET | /public/auth-config | OIDC settings for your client |
14
Errors are JSON: { "error": "CONFLICT", "message": "…", "correlationId": "…" }. Quote the correlationId when you contact us — it finds the request in our logs.
| HTTP | error | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | Malformed body or a value the API cannot use. Field validation returns { "error": "Validation failed", "details": { field: message } }. |
| 401 | — | No token, or it expired. Get a new one from the token endpoint. |
| 402 | Feature not available | Your plan does not include this feature; requiredPlan says which one does. |
| 403 | ACCESS_DENIED | Valid token, but your organisation or role may not do this — e.g. a provider accepting a quotation. |
| 404 | NOT_FOUND | No such route or document — documents of other organisations are invisible to you. |
| 409 | CONFLICT | Not allowed in the current state — e.g. publishing an RFQ that still awaits approval. |
| 500 | INTERNAL_ERROR | Our fault. Retry with backoff and quote the correlationId when you contact us. |
15
Not there yet — and said so. In the order we plan to ship it:
Self-service API keys and plans in the developer portal (developer.wasilah.net).
Published per-plan limits with RateLimit headers; today fair use applies.
Push instead of polling: rfq.published, quotation.submitted, order.confirmed, deal.accepted.
A separate environment with test organisations to build against.
Typed clients for TypeScript and Python, generated from the OpenAPI spec.
Tell us what you want to connect — an ERP, a hospital information system, a supplier catalogue. We set up credentials for your organisation and help with the first integration.