Beta: the Biskèt Partner API may still change before v1 is final. Sandbox access is by request:partners@bisket.ai.
Payments and collected_by
Every order says who collects the customer’s money:
collected_by: partner— you charge the customer (card, MonCash, cash on delivery…). Sendpayment.status: paid(orpendingfor cash on delivery). The order goes straight to the restaurant. Settlement: you owe the restaurant the menu subtotal.collected_by: restaurant— the customer pays into the restaurant’s MonCash through a payment intent. The order waits inawaiting_paymentand reaches the restaurant only once paid. Settlement: the restaurant owes you your markup and delivery fee.
delivery_fee is required on a delivery order and partner_markup when the restaurant collects; send 0 when there is none.
The amounts are always separate: subtotal (menu prices, the restaurant’s), partner_markup and delivery_fee
(yours), partner_funded_discount (yours, paid to the restaurant). The payment amount must equal
subtotal + markup + delivery fee − discount (payment_amount_mismatch
otherwise), and MonCash amounts must be whole gourdes.
A MonCash payment intent
Section titled “A MonCash payment intent”POST /v1/orders/{order_id}/payment_intentswith{ "provider": "moncash", "return_url": "https://…" }. The return URL’s host must be one Biskèt registered for you.- Send the customer to
redirect_url(valid 15 minutes). They pay in MonCash and come back to yourreturn_url. - You receive
payment.succeeded(thenorder.received), orpayment.failed. Biskèt verifies every payment with MonCash itself; the redirect is never trusted. An order unpaid after 60 minutes is cancelled.
// Restaurant-collected payment (collected_by: restaurant): a MonCash payment intent for the order.import { createBisket } from '@bisket-ai/partner-sdk';
export async function main(env: { apiKey: string; locationId: string; returnUrl: string }) { const bisket = createBisket({ apiKey: env.apiKey }); const location_id = env.locationId; const { data: menu } = await bisket.GET('/v1/locations/{location_id}/menu', { params: { path: { location_id } } }); const item = menu!.items.find((i) => i.available && i.variants.length === 0 && i.modifier_groups.length === 0 && i.base_price)!; const amount = item.base_price!.amount; // MonCash takes whole gourdes const { data: order } = await bisket.POST('/v1/locations/{location_id}/orders', { params: { path: { location_id } }, body: { external_id: `PAY-${Date.now()}`, partner_order_number: 'PAY', customer: { first_name: 'Ana' }, items: [{ item_id: item.id, variant_id: null, quantity: 1, unit_price: { amount, currency: 'HTG' }, modifiers: [] }], subtotal: { amount, currency: 'HTG' }, collected_by: 'restaurant', partner_markup: { amount: 0, currency: 'HTG' }, // required when the restaurant collects (0 allowed) delivery_fee: { amount: 0, currency: 'HTG' }, // required for delivery (0 allowed) payment: { method: 'moncash', status: 'pending', amount: { amount, currency: 'HTG' } }, }, }); const { data: intent } = await bisket.POST('/v1/orders/{order_id}/payment_intents', { params: { path: { order_id: order!.id } }, body: { provider: 'moncash', return_url: env.returnUrl }, }); // Send the customer to intent.redirect_url. In the sandbox, finish it yourself: const { data: paid } = await bisket.POST('/v1/sandbox/payment_intents/{payment_intent_id}/simulations', { params: { path: { payment_intent_id: intent!.id } }, body: { outcome: 'succeeded' }, }); return { intentStatus: paid!.status, redirect: Boolean(intent!.redirect_url) };}Refunds are not API calls: if the restaurant removes lines or refuses a paid order, the ledger books what it owes back
(restaurant_collected_refund_due), and you refund the customer. See settlement.