Order Joulo's replacement offer for a customer
Places an order for one of your customers from Joulo's replacement offer (GET /partner/replacement-offers). Joulo stays the seller. The answer carries a checkout_url: open it in your app like the sign-in link of the onboarding flow. On that page the customer sees the price, the address and our terms, and pays through Mollie. Afterwards the page sends the customer to return_url with ?status=paid|cancelled|failed&order=<order_id>. The checkout URL opens no session on the customer's account: it reads and pays this one order, for 30 minutes. Only a customer with mid_status no_mid may order, and only a product_slug from the offer for that customer: the offer, an alternative, or one of their options. One open order per customer: a second request answers 409 order_open with the open order and a fresh checkout_url. external_ref makes the request idempotent: the same value returns the same order, whatever its status, with replayed: true. An unpaid order expires after 30 minutes unless the customer reached Mollie by then. No partner fee applies to the hardware.
Partner API key, sent as Authorization: Bearer <key>. Production keys start with jpk_live_ and work only on https://api.joulo.nl. Sandbox keys start with jpk_test_ and work only on https://api-staging.joulo.nl. Sandbox keys minted before September 2026 also start with jpk_live_. A key used on the wrong host returns 401 with a detail. A key is bound to one partner and reaches only the Partner API routes. Any other route returns 404 when it does not exist. A route that needs a scope the key lacks, such as GET /sessions, returns 403 with error: Insufficient scope and a required_scope. Every other route returns 403 with error: partner_api_key_scope. Mint and revoke keys in the partner portal. A partner has one active key at a time.
In: header
The pseudonymous reference of the customer, from GET /partner/customers.
^[0-9a-f]{8}$A product_slug from the offer for this customer: offer, an alternative, or one of their options.
Your own reference for this order. Unique per partner: the same value returns the same order.
length <= 120The customer's phone number, for the installer. Defaults to the number on the account. The customer can change it on the checkout page.
The version of a laadstation that offers one (BlueSky): a fixed cable or a type 2 socket. Ignored on a product without that choice.
"tethered" | "socket"A note for the installer, such as where the laadstation hangs.
length <= 500Where our page sends the customer after paying. Must extend the return URL registered in the partner portal. Omit it to use that URL.
length <= 500Response Body
curl -X POST "https://api.joulo.nl/functions/v1/api/partner/replacement-orders" \
-H "Content-Type: application/json" \
-d '{
"customer_ref": "3f9a1c2e",
"product_slug": "vervanging-zaptec-go-2",
"external_ref": "hw-order-8812",
"phone": "+31612345678",
"notes": "Laadstation hangt in de carport",
"return_url": "homewise://auth/joulo-result?screen=vervanging"
}'{
"ok": true,
"order_id": "a1b2c3d4-0000-4000-8000-000000000001",
"status": "awaiting_payment",
"checkout_url": "https://joulo.nl/vervangen/afrekenen/9f1c…?embed=1",
"checkout_expires_in": 1800,
"amount_cents": 119900,
"replayed": false
}{
"error": "return_url_not_allowed",
"message": "return_url must start with the return URL registered in the partner portal."
}{
"error": "Missing or invalid API token"
}{
"error": "Not available for your partner type"
}{
"error": "customer_not_found"
}{
"error": "order_open",
"order_id": "a1b2c3d4-0000-4000-8000-000000000001",
"status": "awaiting_payment",
"amount_cents": 119900,
"checkout_url": "https://joulo.nl/vervangen/afrekenen/9f1c…?embed=1",
"checkout_expires_in": 1800
}{
"error": "Too many requests",
"retry_after_seconds": 3
}