Create a checkout SDK session
Call POST /v3/checkout/sessions to create a session for the checkout SDK. The response returns the three values you pass to the frontend SDK so it can render the impact component inside your checkout flow, and a sessionId you keep against the order.
The quote is worked out when the consumer's browser loads the checkout, and its quoteId reaches your page through the SDK's events.
For SDK initialisation, events and customisation options, see Checkout SDK.
The merchant object is optional
You can omit
merchantif the organisation has an MCC set at organisation level.
Making the request
The request requires organisationId, consumer and transaction. Set impactType to carbon or nature (defaults to carbon if omitted). The impactType decides which footprint the session generates and which quote runs in the backend.
Set locale to a BCP 47 tag such as en-GB to choose the language of the copy the quote carries, including the footprint equivalents and the impact partner text. It defaults to en-GB, and falls back to en-GB for a locale that is not supported.
curl https://api.ekko.earth/v3/checkout/sessions \
-H "Authorization: Bearer $EKKO_API_KEY" \
-H "Ekko-Version: 2026-10-06.pangolin" \
-H "Content-Type: application/json" \
-d '{
"organisationId": "1f9e36e2-fdf3-4d36-a6ae-a2a146ab5ca1",
"impactType": "carbon",
"locale": "en-GB",
"consumer": {
"reference": "consumer_123",
"postalCode": "SW1A 1AA",
"city": "London",
"countryCode": "GBR"
},
"merchant": {
"name": "Blossom & Bloom",
"mcc": "5992",
"address": {
"line1": "Ground floor",
"line2": "45 Rosewood Avenue",
"city": "London",
"postalCode": "SW1A 1AA",
"countryCode": "GBR"
}
},
"transaction": { "amount": 47.97, "currencyCode": "GBP" },
"orderItems": [
{
"itemReference": "line_1",
"sku": "POT_MEDIUM",
"description": "Flower pot",
"category": "pots",
"quantity": 3,
"unitPrice": { "value": 15.99, "currencyCode": "GBP" }
}
],
"projectFilters": { "credits": { "matchConsumerLocation": true } }
}'orderItems are optional and not used in the footprint calculation, but are recommended for analytics and reporting.
Choosing an impact type
impactType | Footprint | What the consumer funds | Filters that apply |
|---|---|---|---|
carbon (default) | Carbon footprint | Carbon credits | projectFilters.credits |
nature | Biodiversity footprint, in MSA | A contribution to an impact partner | projectFilters.contribution |
A session carries one impact type. An impactType array is rejected. To show both metrics, create two sessions. Filter fields that do not apply to the chosen impact type are ignored.
For background on the biodiversity metric, see nature footprint.
Nature request example
{
"organisationId": "1f9e36e2-fdf3-4d36-a6ae-a2a146ab5ca1",
"impactType": "nature",
"consumer": {
"reference": "consumer_123",
"postalCode": "SW1A 1AA",
"city": "London",
"countryCode": "GBR"
},
"transaction": { "amount": 47.97, "currencyCode": "GBP" },
"projectFilters": {
"contribution": { "matchConsumerLocation": true, "matchTheme": true }
}
}Setting projectFilters.contribution.matchTheme to true ranks impact partners by the transaction's dominant pressure category.
matchConsumerLocationmeans different things per impact typeFor
carbonit matches credit projects to the consumer's location. Fornatureit ranks contribution impact partners by how closely their projects match the consumer's location (state, then country).
The response
A successful request returns HTTP 201 with four values.
{
"sessionId": "a3d8f6b2-9c14-4e7a-b8d5-2e6f1a3c9b78",
"clientSecret": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjIwMjYtMDkiLCJ0eXAiOiJKV1QifQ.eyJzaWQiOiJhM2Q4ZjZiMi05YzE0LTRlN2EtYjhkNS0yZTZmMWEzYzliNzgifQ.ZXhhbXBsZS1zaWduYXR1cmU",
"sessionData": "qQquYfEo3qQbXoE93cOXcKmSmoC8j5yIPj8sb0SKo3TMaaNqh9Bn6yC_fAvOyi7TefKYTK6H5bZ6MAfcE_IMXQbZU_3yekJo55v_DHKIlk2zH5wdDcCTnzdHlH7lIQSOGBNXxDirHqkqeqoq2evY4v4CDlpg72Jei7y_8nJvMnBiJqe7ofR18nlpLUf4GLQtnwYdjHwy3_xDvtwyVJ_xqfHSuLwtGx3g_WWT-SJHcw6Dvk-n2atle9GEdxVkR7Z7vQDfgrsW8SsM5rrAWolwJj79PHrHuwMhsNI6GBgiGumDJ2i_q-8IVsgUwUmjXMck5E0CGhifoKp2ymZ6zJ_oROsAe8U9Mm84nzSx-fX4BbN3k9hdarYiEFwg6aRofR9Erjxnqhb1vxFTemDznu2NYaexCgO58TH2mN8dbRmCppryiXWuUuiAqii1a8BfwpCuSAWahyQbsuFCgXuqNbT2RV_Pu1_0sBf7vWoU5AEZdCk3T8Gi_qNTbHhd4Ab4eRoVF4eYntKum1bWfIlfC2U-9Afpo5p8OhN74nR0QHMH5Uww9wykSs_9V3veBXQuViaLF4TNIt-PTzx9uR_pVQYThc050-8DT64-2Llv7PswKyZaq86ex56hg8V1Y4KKfqcHodRm9DWsFxi_gQlrbT-Oi5deDuJk-ioqyt7MQ95yTp86yReSqD7OsBo4mtDqZ7k97FSsuUZL1HfLFEGpuD0v5z1oWz1X5hKKQwV2cun6xvoaMB_THHo7nCvRfi5_W1pNYIIwFMOO0ZCyhrX73A1uCnlYWeSC3nU34ylL8KrXshJVc_DYk8XZBTB9ZV7RUg",
"expiresAt": "2026-01-07T17:14:58Z"
}| Value | What it is | What to do with it |
|---|---|---|
sessionId | The session's durable identifier | Store it against the order, and pass it to the SDK |
clientSecret | A short-lived credential for the consumer's browser | Pass it to your frontend unchanged |
sessionData | The session's sealed inputs, opaque to your page | Pass it to your frontend unchanged |
expiresAt | When the credential stops working for the consumer | Create a new session if it has passed |
Pass sessionId, clientSecret and sessionData to the Checkout SDK on the frontend, exactly as they came back. The SDK uses them to work out the quote from the consumer's browser.
Treat the
clientSecretas a secretNever log it, never put it in a URL and never store it. It only needs to survive the trip from your server to your checkout page.
Getting the quoteId
The quoteId reaches your checkout page through the SDK's events.
initCheckout({
// ...
on: {
ready: (event) => setQuoteId(event.quoteId),
toggleChanged: (event) => {
setQuoteId(event.quoteId);
updatePaymentAmount(event);
},
},
});Send the quoteId to your server with the order, along with the amounts the consumer chose. At order completion, record the contribution with that quoteId and your own amounts.
curl https://api.ekko.earth/v3/funds/allocations \
-H "Authorization: Bearer $EKKO_API_KEY" \
-H "Ekko-Version: 2026-10-06.pangolin" \
-H "Idempotency-Key: 3f1a7c4e-9b2d-4f8a-a1c6-5e7d9b0f2a34" \
-H "Content-Type: application/json" \
-d '{
"organisationId": "1f9e36e2-fdf3-4d36-a6ae-a2a146ab5ca1",
"quoteId": "7b4f1b1b-47a0-4c2a-a5ed-2cfe5bfc2c4a",
"credits": { "amount": 0.518 }
}'The amounts are always yours: the quote sets the rates, your system decides what the consumer actually paid. See Idempotency for retrying this call safely, and Checkout SDK for the full event payloads.
No events means no quote
If the consumer never reached the checkout page, no quote was worked out and no
quoteIdexists, so there is nothing to allocate. That is the expected outcome for those orders.
Expiry
A session lasts 10 minutes. expiresAt is when the consumer's credential stops working: past that point the SDK cannot work out the quote, so create a new session if the consumer is still on the page.
Expiry does not affect a quoteId you already hold. A consumer may take longer to pay than the session lasts, and the allocation is made against the quote, not the session.
Updated 3 days ago
