Heartswill API documentation · v1 API status Get a key
Heartswill API · v1

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.

Step 1

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…

Step 2

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.

We use these details only to review and set up your partnership.
Step 3

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.

Recommended

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.

Step 4

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"
  }
}
Reference

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.

FieldTypeRules
partner_refstringRequired. Your order or booking reference, up to 200 characters. Hashed on our side and never stored in plain text.
amount_inrintegerRequired. 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.
projectstringNot 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.
eventstringOptional. 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

CallReturns
GET /v1/projectsCauses with id, unit, unit cost and status. Only pilot and active causes accept pledges.
GET /v1/stories?partner=idPublished deliveries with photo fingerprints.
GET /v1/widget?partner=idTotals, 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/ledgerThe full hash-chained ledger.
GET /v1/anchorsDaily 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." } }
StatusCodeWhat to do
400bad_jsonSend a valid JSON body.
401unauthorizedCheck the key and the Bearer prefix.
422invalid_partner_refSend an order reference of 1 to 200 characters.
422invalid_amountSend whole rupees of at least 50.
422invalid_eventOnly order.paid or booking.confirmed.
422pledge_rejectedThe 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.
402insufficient_creditPrepaid partners only. Your credit is lower than the pledge. Top up with the NGO, then retry with the same partner_ref.
422cannot_reverseThe pledge was already settled or delivered, or never existed.
404not_foundCheck the path or tracking code.
500server_errorRetry with the same partner_ref. It is safe.
Ship

Plugins

ShopifyConnect a store in two minutes with an order webhook. No code needed.Open Shopify connect
WooCommerceWordPress plugin that calls the API when an order is paid.Sent with your key
PHP and Node.jsSmall 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.

CardEmbedOpens
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_ref so 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_credit by alerting your team, not by blocking the customer's order.
  • Cancellations and refunds call /v1/pledges/reverse.
  • The track_url appears 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.