Skip to content
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…). Send payment.status: paid (or pending for 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 in awaiting_payment and 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.

  1. POST /v1/orders/{order_id}/payment_intents with { "provider": "moncash", "return_url": "https://…" }. The return URL’s host must be one Biskèt registered for you.
  2. Send the customer to redirect_url (valid 15 minutes). They pay in MonCash and come back to your return_url.
  3. You receive payment.succeeded (then order.received), or payment.failed. Biskèt verifies every payment with MonCash itself; the redirect is never trusted. An order unpaid after 60 minutes is cancelled.
payments.ts
// 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.