Skip to Content
QR Slip VerificationQR Slip Verification API

QR Slip Verification API

The QR Slip Verification API confirms a bank transfer payment from the slip your shopper sends you, for payments made on Beam.

The following operation is available:

  • Verify Charge with QR Slip (POST /api/v1/charges/verify-qr-slip): match a slip against your charges and update the matching charge to SUCCEEDED if it is still PENDING.

For the concepts behind this endpoint, see QR Slip Verification. For the full schema, see the API reference.

Important

Beam enables this API separately from the QR slip verification feature in Lighthouse, so contact Beam support before you build this integration. Until then, every request to this endpoint returns 403 Forbidden. See QR Slip Verification.

Verify a charge with a QR slip

The request uses multipart/form-data. The format field tells Beam which other field carries the QR code:

formatDescription
RAWThe content of the QR code from the bank transfer slip, sent in the raw field. Use this if your own app already scans the QR code from the slip.
IMAGEThe slip image file, sent in the image field. Beam reads the QR code for you.
Note

Send the QR code on the slip, not the QR code that the shopper scanned to pay. See Slips you can verify.

Verify with the raw QR code content

Set format=RAW and put the raw content of the QR code in the raw field:

POST https://api.beamcheckout.com/api/v1/charges/verify-qr-slip Authorization: Basic <base64(merchantId:apiKey)> Content-Type: multipart/form-data; boundary=WebAppBoundary --WebAppBoundary Content-Disposition: form-data; name="format" RAW --WebAppBoundary Content-Disposition: form-data; name="raw" 0041000600000101030040220015077082818AQR086795102TH9104FF93 --WebAppBoundary--
Note

Send the QR code content exactly as your scanner reads it, do not modify the content.

Verify with the slip image

Set format=IMAGE and put the slip image in the image field:

POST https://api.beamcheckout.com/api/v1/charges/verify-qr-slip Authorization: Basic <base64(merchantId:apiKey)> Content-Type: multipart/form-data; boundary=WebAppBoundary --WebAppBoundary Content-Disposition: form-data; name="format" IMAGE --WebAppBoundary Content-Disposition: form-data; name="image"; filename="example-slip.png" < example-slip.png --WebAppBoundary--
Note

The image must be a JPEG or PNG file, and its size must not exceed 2 MB.

Handle the verification response

A 200 means the slip matched one of your charges and that charge is now SUCCEEDED. The body carries the chargeId of the matched charge and the verificationResult of the check:

{ "chargeId": "ch_2xTsz7Qit55pahSvKfJG3UMkpFQ", "verificationResult": "UPDATED_TO_SUCCEEDED" }
verificationResultCharge status before your callWhat Beam doesWhat you do
UPDATED_TO_SUCCEEDEDPENDINGUpdates the charge to SUCCEEDED and sends the related webhooks, such as charge.succeededMark the order as paid
ALREADY_SUCCEEDEDSUCCEEDEDLeaves the charge as it is, because the payment is already confirmedMark the order as paid, if you have not already

Read verificationResult when you need to know which case happened. This is also what makes retries safe. If you send the same slip again, the second call returns 200 with the same chargeId and ALREADY_SUCCEEDED.

When Beam updates a charge to SUCCEEDED, we also sends the related webhooks, such as charge.succeeded. These are the same events you get when a charge succeeds in any other way. See Event Types for the payloads.

Errors

When Beam cannot verify the slip, it returns a standard error response and no charge changes:

Status CodeError Code EnumMeaningRecommended action
400 Bad RequestAPI_VALIDATION_ERRORBeam cannot read a QR code from the image, or the content of the QR code is not validAsk the shopper for a clearer slip, or check the QR code content you sent
403 ForbiddenNO_PERMISSION_ERRORYour merchant account is not allowed to use this APIContact Beam support to enable it
404 Not FoundNOT_FOUND_ERRORThe slip does not match any of your chargesAsk the shopper for the correct slip

For example, when no charge matches the slip:

{ "code": 404, "message": "not found", "error": { "errorCode": "NOT_FOUND_ERROR", "errorMessage": "not found" } }
Important

Check the HTTP status code to know if the payment is verified. verificationResult only separates the two success cases, and it never reports a failure. A slip that Beam cannot read or match comes back as a 4xx error instead.

Testing on Playground

Beam matches a slip against a charge that the shopper paid by bank transfer, and that transfer has to be real. Playground has no real bank transfers, so you cannot test the success case there. What you can test is whether Beam accepts the slip or the QR code content you send, which covers the rest of your integration.

Send your test requests to https://playground.api.beamcheckout.com/api/v1/charges/verify-qr-slip with your Playground API key:

formatWhat you sendWhat Beam returns
IMAGEAn image that Beam cannot read a QR code from400 with API_VALIDATION_ERROR
IMAGEA slip image whose QR code is not a bank transfer QR code400 with API_VALIDATION_ERROR
IMAGEA real bank transfer slip with a valid QR code404 with NOT_FOUND_ERROR
RAWText that is not QR code content, for example a link or a random string400 with API_VALIDATION_ERROR
RAWThe content of a QR code that is not a bank transfer QR code400 with API_VALIDATION_ERROR
RAWThe content of a valid QR code, copied from a real bank transfer slip404 with NOT_FOUND_ERROR
Note

On Playground, a 404 is the result you want. It means Beam read the QR code and looked for a matching charge, and only that charge is missing, because no Playground charge comes from a real bank transfer. Your authentication, your multipart/form-data body, and the QR code itself are all correct.

Test the 200 case in production, with a charge that the shopper paid by bank transfer. Production is also the only place where you see verificationResult. The first call on a PENDING charge returns UPDATED_TO_SUCCEEDED, and the same slip sent again returns ALREADY_SUCCEEDED.

Last updated on