Products · Build a dot

Take payments

Take a payment in Dash's own payment sheet with dash.payments.request, choose how people can pay, confirm the payment on your server and test it.

Your dot doesn't build a checkout. It asks Dash for a payment, and Dash shows its own payment sheet. The person pays the way they already do in Dash: from a linked account, by card or with mobile money. The money goes to your business's Space, which owns the dot.

Declare payments

Add payments to dot.json's permissions, with what people pay for:

dot.json
{
  "permissions": { "payments": "Pay for ferry tickets" }
}

Monime's review reads the reason. Dash doesn't ask the person for this permission, because they confirm every payment in the sheet.

Ask for a payment

Call this.dash.payments.request with the order. Amounts are in minor units, as in Monime's API, so SLE 75.00 is 7500:

pages/tickets/controller.ts
// One of the page's actions
async pay(state) {
  const result = await this.dash.payments.request({
    order: {
      name: 'Lungi ferry tickets',
      reference: state.orderId,
      lineItems: [
        { name: 'Adult ticket', unitPrice: { currency: 'SLE', value: 7500 }, quantity: state.adults },
      ],
    },
  });
  if (result.status === 'completed') {
    this.navigation.replace('tickets/confirmed', { orderId: state.orderId });
  } else if (result.status === 'pending') {
    this.setState({ note: "We're waiting for your payment to go through." });
  } else {
    this.setState({ note: "The payment didn't go through. Try again." });
  }
},

Dash adds up the total. An order holds:

  • A name of 3 to 64 characters.
  • Your own reference for the order, up to 64 characters. Use a new one for each order. Your server's order ID works well. Asking again with the same reference gives back the first payment, and never pays twice.
  • 1 to 16 lineItems, all in one currency, SLE or USD. Each has a name, a unitPrice and a quantity from 1 to 100,000. An imageUrl shows a picture beside the item. It must be https, on a host in network.hosts.
  • An optional description.
  • Up to 64 metadata pairs, which stay with the payment and its webhooks. The Payments reference lists the rules for keys and values.

How a payment ends

If something goes wrong before the person picks a way to pay, request rejects with one of these codes:

CodeWhat happened
cancelledThe person closed the sheet
invalidMonime won't take the order. The message says what to change
deniedYour dot or Space can't take payments right now
failedDash couldn't reach Monime. Trying again may work
timeoutDash stopped waiting before the person picked a way to pay

Monime rejects an order below its smallest amount as invalid. A dot that isn't published yet gets denied, as does a call Dash held back.

A second request while your dot's payment sheet is open also gets denied, and the open sheet carries on. To stop a double tap, set the Button's loading while you wait for the result.

Once they pick one, it resolves with the payment's status:

StatusWhat it means
completedThe money is paid
pendingNot confirmed yet
expiredThe person didn't finish in time
cancelledThe person closed the sheet after picking a way to pay
failedOnly from get: a pending payment that failed later

If a way to pay fails, the sheet stays open, and the person can try again or pick another.

request takes no timeout, as Dash decides how long the sheet waits. After the person picks a way to pay, cancel() only stops your dot waiting. The payment carries on.

Check a pending payment

Read a payment again with this.dash.payments.get(reference). You get undefined if your dot never asked for it, or the person never picked a way to pay. Check a pending one when the person comes back to the page:

TypeScript
hooks: {
  async onShow() {
    const payment = await this.dash.payments.get(this.state.orderId);
    if (payment?.status === 'completed') {
      this.setState({ paid: true, note: '' });
    }
  },
},

Choose how people pay

Leave out methods to offer all three ways to pay. To offer fewer, or to set a method's options, list them in the order the sheet should show them:

TypeScript
await this.dash.payments.request({
  order,
  methods: [
    { type: 'momo', providers: ['m17'] },
    { type: 'link' },
  ],
});
MethodPays withSettings
linkAn account the person linked in Dashproviders
cardA cardNone
momoMobile moneyproviders, phoneNumber

providers lists the only providers that can pay, by Monime's IDs. Leave it out, or leave it empty, for any. Mobile money takes m17 (Orange Money) and m18 (Africell Money). A linked account is at a bank, so it takes only the banks: slb001 (Sierra Leone Commercial Bank), slb004 (Guaranty Trust Bank), slb007, slb009 and slb013.

phoneNumber is the only number that can pay with mobile money, written as +23276123456.

Where the money goes

The money goes to the Space's main account. To pay into another of the Space's accounts, give its ID:

TypeScript
await this.dash.payments.request({ order, financialAccountId: 'fac-k6VgVTfSmLruHpiQgMg4DUeySZx' });

The account must belong to the Space that owns the dot and hold the order's currency, or the request rejects with invalid.

Confirm on your server

Anyone can change what a dot reports. Treat the result as something to show the person, not proof of payment. Deliver the ticket only once Monime confirms the payment to your server, by webhook or by looking it up with your Space's API key.

The result names what to look up:

Paid withFieldWhat it is
A cardcheckoutSessionIdA checkout session
Mobile moneypaymentCodeIdA payment code
A linked accountpaymentIdThe payment

Each result also has the order's reference and total amount, and orderNumber once the payment completes, for the person's receipt. requestId is Dash's ID for the request. Monime's support asks for it if something goes wrong.

Test payments

In the simulator, Dash's sheet is a stand-in. Pick a way to pay, then choose how the payment ends: Paid, Pending, Declined or Expired. Declined keeps the sheet open. No money moves.

In a live test on a phone, payments are real, and the money goes to your Space. They only work once the dot is published and dot.json has the id Monime gave it. Until then, request and get reject with denied, and the rest of the dot runs as usual. Keep test orders small.

In a test, fake the call like any other:

TypeScript
const page = await testPage(tickets, {
  host: {
    'dash.payments.request': () => ({
      method: 'momo',
      paymentCodeId: 'pmc-test',
      reference: 'order-1042',
      requestId: 'req-test',
      status: 'completed',
      amount: { currency: 'SLE', value: 15000 },
    }),
  },
});

Keep reading