Connect in one call. We handle the cause.
Send one request when an order is paid or a booking is confirmed. Heartswill records a pledge to the cause assigned to your business and returns a tracking code for your customer. Within about 30 days the delivery comes back as a sealed story with photos.
We assign your cause
Heartswill chooses the verified NGO and assigns your business a cause. Every pledge from your key goes to it.
Request a partner key
Heartswill reviews your request and sends a hw_live_ key.
Choose how you pay
Prepaid credit, monthly settlement or split at checkout. The money always goes straight to the Foundation.
Call on every confirmed order
POST to /v1/pledges with your order reference and amount.
Show the proof
Print the tracking link on receipts and add the verified badge to your site.
Base URL https://heartswill.com/api/v1
All requests and responses are JSON over HTTPS. Amounts are whole Indian rupees. Times are ISO 8601 in UTC.
The causes on Heartswill
Heartswill selects the NGOs and assigns each business one of these causes after review. They are listed here so you can see exactly what your customers' orders fund. Tap one to see its id in the code samples.
Loading causes…
Request a partner key
Heartswill reviews every partner before issuing a key. Ecommerce stores, service businesses and enterprises all use the same API. You will hear back by email, usually within two working days.
Choose how you pay
Heartswill never touches money. Every rupee goes from you straight to the bank account of the verified NGO running your chosen cause, such as AnandBodh Foundation. Pick the option that suits your business. You can change it later with the Foundation.
Prepaid credit
Top up the NGO first, by bank transfer or UPI. Each pledge is paid from your credit the moment it happens, so customers see Funded straight away. When credit runs out, new pledges are refused with 402 insufficient_credit until you top up. Refunds before delivery return to your credit.
Monthly settlement
Pledges are recorded as Pledged. After month end, pay the exact total. It is recorded against your bank reference and every pledge turns Funded. Anything unpaid for 45 days turns your badge grey and shows as overdue on your public impact card.
Split at checkout
Your customer's payment is split by the gateway, so the NGO's share lands in its account automatically. Until the gateway link is live, split partners settle like monthly partners.
What everyone can see
Each top-up and settlement is written to the public ledger with the amount and only the last 4 characters of the bank reference. GET /v1/widget?partner=id shows your pledged, settled and unpaid totals, and whether anything is overdue. Your remaining prepaid credit is shown only to you, in GET /v1/impact.
Send your first pledge
Call this from your server after payment succeeds or a booking is confirmed. Never call it from the browser, because your key must stay secret.
curl -X POST https://heartswill.com/api/v1/pledges \
-H "Authorization: Bearer $HEARTSWILL_KEY" \
-H "Content-Type: application/json" \
-d '{"partner_ref":"ORDER-24817","event":"order.paid","amount_inr":500}'
const res = await fetch("https://heartswill.com/api/v1/pledges", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HEARTSWILL_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
partner_ref: order.id, // your order or booking reference
event: "order.paid",
amount_inr: 500
})
});
const { data } = await res.json();
// save data.track_code and show data.track_url to the customer
$ch = curl_init("https://heartswill.com/api/v1/pledges");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("HEARTSWILL_KEY"),
"Content-Type: application/json"
],
CURLOPT_POSTFIELDS => json_encode([
"partner_ref" => $order->id,
"event" => "order.paid",
"amount_inr" => 500
])
]);
$data = json_decode(curl_exec($ch), true)["data"];
import os, requests
r = requests.post(
"https://heartswill.com/api/v1/pledges",
headers={"Authorization": f"Bearer {os.environ['HEARTSWILL_KEY']}"},
json={
"partner_ref": order_id,
"event": "order.paid",
"amount_inr": 500,
},
timeout=10,
)
data = r.json()["data"]
Response 201 Created for a new pledge or 200 OK when the same reference was already recorded. status is funded for prepaid partners and pledged for monthly and split partners until they settle.
{
"data": {
"id": "6f1c…",
"status": "pledged",
"project": "girl-education",
"amount_inr": 500,
"units": 2,
"duplicate": false,
"track_code": "K7Q2MX9D",
"track_url": "https://platform.heartswill.com/h/K7Q2MX9D"
}
}
Authentication
Send your partner key as a bearer token. Keys start with hw_live_. Keep the key on your server and in an environment variable. If a key leaks, ask the Foundation to replace it and the old key stops working at once.
Authorization: Bearer hw_live_xxxxxxxxxxxxxxxxxxxxxxxx
Public reads below need no key.
POST /v1/pledges
Records a pledge for one confirmed order or booking.
| Field | Type | Rules |
|---|---|---|
partner_ref | string | Required. Your order or booking reference, up to 200 characters. Hashed on our side and never stored in plain text. |
amount_inr | integer | Required. Whole rupees, at least the cause's minimum: ₹50 for most causes and ₹100 for Karuna, so every pledge funds at least one unit. Units are worked out from the cause's unit cost. |
project | string | Not needed. Heartswill assigns your cause, and every pledge from your key goes to it. Any project you send is ignored; the response tells you which cause was used. |
event | string | Optional. order.paid or booking.confirmed. Any other value is rejected so that carts and pending payments never create pledges. |
Retries are safe
Send the same partner_ref again and you get the original pledge back with "duplicate": true. Nothing is counted twice, so you can retry on timeouts without worry.
GET /v1/impact
Your totals, published stories and funding, including your prepaid balance_inr and a low_balance flag. Needs your key. Check it daily if you are prepaid.
POST /v1/pledges/reverse
Reverses a pledge when an order is cancelled or refunded before settlement. Send the same partner_ref you used for the pledge.
{ "partner_ref": "ORDER-24817" }
Settled monthly pledges cannot be reversed because the money has already reached the NGO. Prepaid pledges can be reversed until items are delivered, and the amount goes back to your credit. The reversal is written to the public ledger.
Tracking codes
Every pledge gets an eight-character track_code and a track_url. Show the link on your receipt email, order page or booking confirmation. Customers see their pledge move from recorded to settled to delivered, then the sealed photos when they arrive.
GET /v1/track/{code} returns the same journey as JSON with no key.
Public reads
| Call | Returns |
|---|---|
GET /v1/projects | Causes with id, unit, unit cost and status. Only pilot and active causes accept pledges. |
GET /v1/stories?partner=id | Published deliveries with photo fingerprints. |
GET /v1/widget?partner=id | Totals, funding (mode, pledged_inr, settled_inr, unsettled_inr, overdue) and recent stories for your impact card. |
GET /v1/track/{code} | The journey of one pledge. |
GET /v1/ledger | The full hash-chained ledger. |
GET /v1/anchors | Daily Bitcoin timestamp proofs. |
Errors
Errors share one shape. Show message in your logs and branch on code.
{ "error": { "code": "invalid_amount", "message": "amount_inr must be a whole number of at least 50." } }
| Status | Code | What to do |
|---|---|---|
| 400 | bad_json | Send a valid JSON body. |
| 401 | unauthorized | Check the key and the Bearer prefix. |
| 422 | invalid_partner_ref | Send an order reference of 1 to 200 characters. |
| 422 | invalid_amount | Send whole rupees of at least 50. |
| 422 | invalid_event | Only order.paid or booking.confirmed. |
| 422 | pledge_rejected | The cause is not accepting pledges yet, the amount is below the cause's minimum (₹100 for Karuna) or the partner is paused. The message says which. |
| 402 | insufficient_credit | Prepaid partners only. Your credit is lower than the pledge. Top up with the NGO, then retry with the same partner_ref. |
| 422 | cannot_reverse | The pledge was already settled or delivered, or never existed. |
| 404 | not_found | Check the path or tracking code. |
| 500 | server_error | Retry with the same partner_ref. It is safe. |
Plugins
| Shopify | Connect a store in two minutes with an order webhook. No code needed. | Open Shopify connect |
| WooCommerce | WordPress plugin that calls the API when an order is paid. | Sent with your key |
| PHP and Node.js | Small server libraries with retries built in. | Sent with your key |
Badges and widget
One standard widget, drawn from GET /v1/widget. You choose the card and the API decides where every click goes, so links stay correct as Heartswill grows.
| Card | Embed | Opens |
|---|---|---|
| Partner impact Totals and delivery stories for your business | data-heartswill-partner="your-partner-id" | Your partner impact tracker, platform.heartswill.com/#partner/your-partner-id |
| Personal One customer's pledge, for receipts and thank-you pages | data-heartswill-pledge="TRACKCODE" | That pledge's own tracker, /h/TRACKCODE |
| Verified badge Green dot only on your registered website | data-heartswill-badge="your-partner-id" | Your partner impact tracker |
<!-- Partner impact card -->
<div data-heartswill-partner="your-partner-id"></div>
<!-- Personal card on a receipt or thank-you page (use the track_code from the pledge response) -->
<div data-heartswill-pledge="K7Q2MX9D"></div>
<script src="https://heartswill.com/embed.js" async></script>
<!-- Verified badge -->
<a data-heartswill-badge="your-partner-id">Every order gives back</a>
<script src="https://platform.heartswill.com/badge.js" async></script>
Strict Content-Security-Policy?
The widget and badge talk only to Heartswill's own domains. Allow https://heartswill.com and https://platform.heartswill.com in script-src and connect-src. Nothing else is needed.
Feed shape: GET /v1/widget?partner=id or ?pledge=CODE returns mode, the figures for that card and links.open, the page a click should open. Build your own design from it if you prefer.
Go-live checklist
- The key is stored in an environment variable on your server only.
- Pledges fire only after payment succeeds or a booking is confirmed.
- Your order ID is sent as
partner_refso retries never double-count. - Your funding option is agreed and, if prepaid, your first top-up has reached the Foundation.
- Your server handles
402 insufficient_creditby alerting your team, not by blocking the customer's order. - Cancellations and refunds call
/v1/pledges/reverse. - The
track_urlappears on the receipt or confirmation. - The badge or impact card is on your site with your partner ID.
- One test order went through and shows up in
/v1/impact.