Skip to main content

Get payment link status API

Reads back a payment link by your reference, with the status of the link and the outcome of the payment made through it. Use it to recover the result of a payment when a notification did not reach you, and to check the state of a link before you issue a new one.


Endpoint

GET https://app.papi.mg/engine/api/payment-links/{merchantPaymentReference}

ItemValue
Base URLhttps://app.papi.mg/engine/api
Path/payment-links/{merchantPaymentReference}
MethodGET
Request bodyNone
Response bodyJSON
Legacy URL

This endpoint exists only on the engine URL. The legacy URL https://app.papi.mg/dashboard/api/payment-links supports link creation (POST) only. It does not support this GET.


Authentication

Every request must carry your shop's API key in the Token header. The reference is resolved inside the shop that the API key belongs to only.


Request headers

HeaderRequiredValueDescription
Token<YOUR_API_KEY>API key of your shop.

No other header is read by this endpoint. The LinkToken header used by the payment page is not accepted as an authentication method here.


Path parameters

ParameterTypeRequiredConstraintsDescription
merchantPaymentReferencestringMatched exactly (case-sensitive). May contain dots. URL-encode reserved characters.Your reference: the reference field you sent when you created the link. It is the same value as merchantPaymentReference in notifications. It is not Papi's payment reference.
tip

Use only letters, digits, -, _ and . in references. Characters such as ?, # or spaces must be URL-encoded (%3F, %23, %20). A reference containing / cannot be read back through this endpoint, even URL-encoded: the server refuses an encoded slash in a path.

A reference is not always unique: you can create a new link with the same reference after the previous one was paid, expired, or disabled. When several links in your shop share the reference, the endpoint returns exactly one link, chosen in this order:

  1. A paid link, if one exists, whatever its age. If several are paid, the most recent paid link.
  2. Otherwise, the most recent link.

So if an order was paid and a new link was issued for it later, this endpoint still reports the paid link. You are always told that the money came in.

This lookup considers every link of your shop with this reference, including links created by hand from the dashboard.


Request example

curl -X GET "https://app.papi.mg/engine/api/payment-links/ORDER-123" \
-H "Token: <YOUR_API_KEY>"

Success response

Status: 200 OK

{
"data": {
"linkStatus": "PAID",
"paymentStatus": "SUCCESS",
"paymentMethod": "MVOLA",
"currency": "MGA",
"displayCurrency": "MGA",
"amount": 15000.0,
"clientName": "Client Name",
"description": "Payment for Order #123",
"merchantPaymentReference": "ORDER-123",
"papiPaymentReference": "c1f4a5b0-6f5e-4e1b-9f0e-2b7d8a9c3d21",
"notificationToken": "5b8f0c3e-2a7d-4f61-9e0b-7c4d1a2e9f38",
"message": null,
"payerEmail": "customer@example.com",
"payerPhone": "+261 34 00 000 00",
"paymentLink": "https://payment-form.papi.mg/yourshop/payments/eyJhbGciOiJIUzI1NiJ9...",
"shortLink": "https://link.papi.mg/8NW7R",
"linkCreationDateTime": 1788065989011,
"linkExpirationDateTime": 1788281989011,
"isTestMode": false
}
}

Response fields

Every field is present in the response. A field without a value is null.

The fields have the same names and meanings as in the notification body, with one exception: Papi's reference is called papiPaymentReference here (it is paymentReference in the notification). This avoids any confusion with your merchantPaymentReference.

FieldTypeDescription
linkStatusstringState of the link: ACTIVE, EXPIRED, PAID or DISABLED. See Link status.
paymentStatusstringOutcome of the payment attempt described by this response: SUCCESS, PENDING or FAILED (the same values as the notification). null when nobody has tried to pay.
paymentMethodstringProvider of that payment attempt (MVOLA, AIRTEL_MONEY, ORANGE_MONEY, BRED). null when nobody has tried to pay.
currencystringCurrency of the link (MGA).
displayCurrencystringCurrency shown to the customer (MGA).
amountnumberAmount of the link.
clientNamestringCustomer's name, as sent at creation.
descriptionstringDescription, as sent at creation.
merchantPaymentReferencestringYour reference, as sent at creation.
papiPaymentReferencestringPapi's reference for the payment attempt (a UUID). It is the paymentReference of the notification. null when nobody has tried to pay.
notificationTokenstringThe token returned when the link was created.
messagestringFailure reason of the payment attempt, when there is one. null otherwise.
payerEmailstringCustomer's email, as sent at creation, or null.
payerPhonestringCustomer's phone number in international format, as sent at creation, or null.
paymentLinkstringThe payment URL, as returned at creation.
shortLinkstringShort form of the payment URL, or null when none was generated.
linkCreationDateTimeintegerCreation time, epoch milliseconds.
linkExpirationDateTimeintegerExpiry time, epoch milliseconds.
isTestModebooleanWhether the link is flagged as a test.

linkStatus is evaluated in this order. The first rule that matches gives the status:

OrderConditionlinkStatus
1The link is paid.PAID
2The expiry time is in the past.EXPIRED
3The link is enabled.ACTIVE
4None of the above: the link was switched off.DISABLED

PAID always wins: a paid link is reported as PAID even after it expired or was disabled. A link that was switched off and whose expiry time is in the past is reported as EXPIRED.

Which payment attempt is described

A customer can try to pay several times on the same link (for example, a first attempt fails and a second one succeeds). The payment fields (paymentStatus, paymentMethod, papiPaymentReference, message) describe one attempt:

  • for a PAID link: the successful attempt, even if another attempt was made after it;
  • for any other link: the most recent attempt.

How to read the two statuses together

linkStatuspaymentStatusMeaningWhat to do
ACTIVEnullNobody has tried to pay yet.Wait, or send the link to the customer again.
ACTIVEFAILEDThe last attempt was declined or abandoned. The customer can try again on the same link.Read message for the reason. Wait.
ACTIVEPENDINGAn attempt is in progress at the provider.Check again shortly.
PAIDSUCCESSThe payment went through.Confirm the order.
EXPIREDnull / FAILED / PENDINGThe link expired before a successful payment.Create a new link.
DISABLEDnull / FAILED / PENDINGThe link was switched off from the dashboard.Create a new link if the order must still be paid.

Errors

Error body format:

{
"error": {
"code": "<ERROR_CODE>",
"message": "<Human-readable message, in French>"
}
}
HTTP statusError codeMeaningExample message
401CORE_PERM_0001The Token header is missing, or the API key is unknown.API key invalide
404CORE_404No link with this reference exists in your shop. A reference that exists only in another shop also gives 404.Aucun lien de paiement pour la référence ORDER-123

Example 404 body:

{
"error": {
"code": "CORE_404",
"message": "Aucun lien de paiement pour la référence ORDER-123"
}
}

Practical notes

Recovering a missed notification

A notification is sent once. If your endpoint was down or the call was lost:

  1. Call this endpoint with your reference.
  2. If linkStatus is PAID and paymentStatus is SUCCESS, confirm the order.
  3. If paymentStatus is PENDING, call the endpoint again later.
  4. Otherwise, keep the order unpaid.

You can also resend the notification from the dashboard: see Failed notifications.

Before you create a new link for an order that already had one, call this endpoint:

  • PAID: do not issue a new link. The order is paid.
  • ACTIVE: send the same link to the customer again, or send the same creation request again (it returns the same link, see Idempotency).
  • EXPIRED or DISABLED: create a new link. You can use the same reference.

Polling

This endpoint is intended for recovery and checks, not as a replacement for notifications. If you poll, space the calls out (for example, every few seconds while paymentStatus is PENDING) and stop when the link is PAID, EXPIRED or DISABLED.

Test mode

The endpoint reads test links and live links in the same way. Use isTestMode in the response to tell them apart.