Hosted checkout
The fastest way to collect a payment — open a Mediquo checkout URL, no UI to build.
The hosted checkout runs the entire payment flow at checkout.mediquo.com. You
open a URL with the payment details; Mediquo renders the portal, processes the
payment, and reports the result. There's nothing to build, theme, or maintain.
This is the integration the Mediquo native apps use inside a WebView, and it
works equally well in an <iframe> or a new tab.
There are four routes, depending on how the payment session is created — the same split as the web components:
| Route | Use when | Who creates the session |
|---|---|---|
/appointment | You're charging for a booked appointment | Mediquo, from a slot and service |
/immediate-videocall | You're charging for a paid immediate videocall | Mediquo, from a videocall schedule |
/ | You're charging for anything else (card) | Your backend, ahead of time |
/apple-pay | Apple Pay on a verified domain (Safari sheet or Chrome desktop QR + iPhone iOS 18+) | Your backend, ahead of time (session_id / order_id) |
Charge for an appointment
Send the user to /appointment with the booking details in the URL:
https://checkout.mediquo.com/appointment?api_key=KEY&slot_id=SLOT123&service_id=SVC456#token=USER_TOKENParameters
Parameter names are snake_case.
| Parameter | Required | Default | Notes |
|---|---|---|---|
api_key | Yes | — | Your Mediquo API key. |
token | Yes | — | User auth token. #fragment only — see below. |
slot_id | Yes | — | The booked appointment slot. |
service_id | Yes | — | The service being charged. |
locale | No | es_ES | One of es_ES, en_US, pt_PT, de_DE, ca_ES. |
consultation_reason | No | — | Free text recorded on the consultation. |
discount_code | No | — | Discount code applied to the appointment charge. Invalid or expired codes are ignored and the full price is charged. |
env | No | production | development or production. |
Charge for an immediate videocall
Send the user to /immediate-videocall with the videocall schedule id. Mediquo
creates the Addon Payments session and runs the same portal / polling flow as
appointments. Coupons and Stripe do not apply on this route.
https://checkout.mediquo.com/immediate-videocall?api_key=KEY&video_call_schedule_id=VCS123#token=USER_TOKENParameters
api_key, token, locale and env are the same as above. Instead of a slot,
this route takes the schedule to pay for:
| Parameter | Required | Default | Notes |
|---|---|---|---|
video_call_schedule_id | Yes | — | Id of the videocall schedule to charge. |
On success the relayed payload is { videoCallId } — the videocall created by
the Addon webhook once payment is confirmed. See
<mq-immediate-videocall-checkout>
for the matching web component.
Charge for a custom session
When the charge isn't an appointment, create the payment session on your backend
first, then send the user to / with the resulting session in the URL:
https://checkout.mediquo.com/?api_key=KEY&session_id=SESS123&payment_url=https%3A%2F%2F…#token=USER_TOKENParameters
api_key, token, locale and env are the same as above. Instead of a slot,
this route takes the session your backend created:
| Parameter | Required | Default | Notes |
|---|---|---|---|
session_id | Yes | — | The id used to poll the payment status. |
payment_url | Yes | — | Fully-qualified payment portal URL. URL-encode it before adding it to the query string. |
These are the same { sessionId, paymentUrl } a provideSession callback returns
with the <mq-checkout> component —
here you pass them in the URL instead of a callback.
There's no discount_code parameter on this route: the price is fixed when your
backend creates the session, so apply any discount there.
Apple Pay (/apple-pay)
For Apple Pay, open the verified domain in Safari or SFSafariViewController
(not a normal in-app WKWebView). Create the payment session on your backend first,
then:
https://checkout.mediquo.com/apple-pay?api_key=KEY&session_id=SESS123&amount=29.99¤cy=EUR&country=ES&label=Consulta#token=USER_TOKEN| Parameter | Required | Notes |
|---|---|---|
api_key, token, locale, env | same as above | token in #fragment only |
session_id | Yes | Backend order id (order_id) |
amount | Yes | Decimal string shown in the Apple Pay sheet (e.g. 29.99) |
currency | Yes | ISO 4217 (e.g. EUR) |
country | Yes | ISO 3166-1 alpha-2 (e.g. ES) |
label | Yes | Line item label in the Apple Pay sheet |
Native apps should present Card vs Apple Pay in native UI, then open / (card)
or /apple-pay accordingly. See mq-apple-pay-checkout.
The user token
Put the user token in the URL #fragment (#token=...), never the query
string. The fragment is never sent to servers, so the token stays out of access
logs and the Referer header. A token placed in the query string is ignored and
the page reports it as missing.
If a required parameter is missing or invalid, the page shows a plain-text message listing what's wrong and does not start the payment.
Handle the outcome
The page reports the result with a single message — the same shape on every platform:
{ "type": "success" | "denied" | "error", "payload": { ... }, "v": 1 }In a web or <iframe> embed, listen for it on the window:
window.addEventListener("message", (event) => {
const { type, payload } = JSON.parse(event.data);
if (type === "success") {
console.log("payment confirmed", payload);
}
});Native apps receive the same message through their WebView bridge, so a single build covers iOS, Android, and the web.
type | payload | Meaning |
|---|---|---|
success | { appointmentId } on /appointment, { videoCallId } on /immediate-videocall, { sessionId, reference } on / | The payment was confirmed. |
denied | { sessionId } | The gateway rejected the payment. |
error | { reason } | Authentication failed, the session couldn't be created, or the flow timed out. |
For full control over the look and feel instead, embed the web components directly.