Skip to content

Security and help

FAQ and troubleshooting

Answers to the questions integrations raise, and what to check when something does not work.

General

Which currencies and cards are supported?

Payments are in Algerian dinars (DZD) only. Payers pay with CIB and Edahabia cards, processed by SATIM.

How much does Raïs cost?

A paid payment costs SATIM's fee (0.7% of the amount, never less than 10.00 DA and never more than 300.00 DA) plus Raïs's (0.3%); a refund costs 10.00 DA. There is no subscription and no setup fee, a failed payment costs nothing, and every figure excludes VAT. See Pricing and fees.

What are the smallest and largest payments?

The smallest payment is 50.00 DA (5000 centimes), SATIM's minimum. The largest is 999999999999 centimes. The smallest refund is 1.00 DA.

Can I call the API from a browser or a mobile app?

No. Secret keys must never leave your server, and the API sends no CORS headers on purpose. Create payments on your server and give the browser or the app the checkout_url. See Mobile and app integrations.

Where do I create keys and webhook endpoints?

In the dashboard, under Developers: API keys, Webhooks and Events.

Payments

Why do I get invalid_amount?

Amounts are integers in centimes. 5000.5, "5000" and 1500.00 are refused. To charge 1,500 DA, send 150000.

Why do I get parameter_unknown?

The request has a field the API does not know, usually a typo. The param in the error names it.

How long can a payer take to pay?

A payment stays payable for 24 hours by default. Set expires_in to anything from 300 seconds to 30 days. After that its status is expired and it cannot be paid.

The payer came back but the payment is still pending

Your server may be asking before the result has reached Raïs. Retrieving a pending payment asks the gateway for the outcome, so retry after a moment, and rely on the webhook. If the payer abandoned the page, it stays pending until it expires. Nothing is sent when it expires: see the next question.

How do I know that a payment expired?

There is no event for it. A payment that nobody paid reads as expired as soon as expires_at has passed: retrieve it, or compare expires_at with the clock. Close the matching order in your own system at that time.

The payer paid and closed the page. Will I still be told?

Yes. Raïs asks the gateway about unpaid payments in the background, starting about two minutes after the payment session opened and for up to 48 hours, and sends payment.succeeded when the gateway says it was paid. See Payments.

My filter has no effect

Unknown query parameters are ignored, so GET /payments?stauts=paid returns every payment. Check the spelling: the filters are status, reference, created_gte and created_lte.

A payment failed. Can the payer try again?

It depends on why it failed. If the bank declined the card (failed with failure.code: payment_declined), the payment is final: create a new payment, with a new Idempotency-Key. If the payer only left the page, pressed Back to or met an error before paying, the payment is still pending: the same checkout_url keeps working until expires_at, and the result page offers a Try again button. A cancelled or expired payment is final too.

Yes. checkout_url is a plain link to the hosted page: share it with the payer. Anyone who holds it can pay it, so send it only to the payer.

Webhooks

The signature does not match

The usual causes, in order:

  1. You verified parsed and re-serialised JSON instead of the raw body. Read the bytes before any parsing.
  2. A proxy or a framework changed the body (decoded it, re-encoded it, or added a newline).
  3. You used the secret of another endpoint or another environment: sandbox and live endpoints have different secrets.
  4. You compared the whole header with the hex digest. The header has t= and v1= parts.
  5. Your clock is more than 300 seconds off.

Test your code with the official test vectors.

No webhook arrives

Check, in this order: the endpoint is enabled (after 20 consecutive failed deliveries it is switched off); it subscribes to the event type; its environment matches the payment (sandbox endpoints get sandbox events only); the address is reachable from the internet and not localhost or a private address; a live endpoint uses https://; and your server answers with 2xx and not a redirect. The delivery log of the dashboard shows each attempt and what your server answered.

I received the same event twice

Delivery is at least once. De-duplicate on the event id. See Webhooks.

How long do retries go on?

Up to 8 attempts over about 20 hours, then the delivery is marked failed and can be resent from the dashboard.

Checkout and return URLs

status=paid is in the address, but the API says pending

Believe the API. The address can be opened by anybody, with any parameters. See Hosted checkout and return URLs.

status=failed is in the address, but the API says pending

The payer's attempt did not go through, but the payment is not over: they can press Try again and pay until expires_at. Do not cancel the order because of the address. See Hosted checkout and return URLs.

The payer was not sent back to my site

The result page never sends the payer back by itself: it stays on screen so they can read the payment's details, and a Return to button opens your success_url or cancel_url. The button is missing when the payment has no success_url or cancel_url and your store has no default, or when the address does not pass the rules for the environment (for example http:// on a live payment), in which case Raïs does not use it.

The checkout does not show in my iframe

It cannot be embedded: it forbids being framed, to protect payers. Redirect to it or open it in a browser tab.

Check that the scheme in success_url matches the one your app registers, that the payer's browser session is allowed to open it (use ASWebAuthenticationSession or Custom Tabs, not a plain web view), and that you did not add a space or a non-ASCII character to the address.

Refunds and receipts

payment_not_refundable

Only paid and partially_refunded payments can be refunded.

My refund is pending

The gateway's answer was lost, and the amount is reserved until the refund is settled by hand. Do not repeat it with a new key, and contact support with the refund id. See Refunds.

The receipt answers 404

Only paid, partially refunded and refunded payments have a receipt, and a key only sees receipts of its own store and environment. See Receipts.

insufficient_balance

A live refund is taken out of your store's balance together with its fee (10.00 DA), so the balance must cover both: "The store's balance is not sufficient to cover this refund and its fee." Top up your balance, wait for payments to come in, or refund a smaller amount. See Refunds.

Are the fees returned when I refund a payment?

No. The fee of a payment is not returned when it is refunded, in full or in part, and the refund has its own fee of 10.00 DA. See Pricing and fees.

Going live

My live key answers 401 invalid_api_key

The key is unknown, revoked or expired, it is used from an address outside its allowlist, or its store is not approved for live payments (any more). The business has to be verified before a live key can exist: see Going live. The API never says which of these it is.

I used a live key with a sandbox payment id

Sandbox and live are separate. The payment is not found (404) because it belongs to the other environment.

Is Raïs PCI DSS or SOC 2 certified?

Raïs does not claim either certification. What the documentation states is what the platform does: the card is typed on a page hosted by Raïs or SATIM and never reaches your servers, keys are stored hashed, saved cards are encrypted. See Security and safety.

Quick reference

You seeProbablyDo
401 invalid_api_keyA wrong, revoked or expired key, a call from an address outside the allowlist, or a store that is suspended or not approved for live paymentsCheck the key, its environment and the store
403 insufficient_scopeThe key lacks the scopeCreate a key with the scope
400 invalid_amountA float or a stringSend an integer in centimes
400 amount_too_smallLess than 50.00 DARaise the amount
400 invalid_urlA bad return URL for the environmentUse https, or your app scheme
404 payment_not_foundAnother store or environment, or a bad idUse the key of the right store and environment
409 payment_not_cancellableThe payment is not pendingRefund it instead if it is paid
400 insufficient_balanceA live refund and its fee are more than your balanceTop up your balance, or refund less
422 idempotency_key_reusedThe same key with different parametersUse a new key for a new request
429 rate_limit_exceededToo many requests, or too many failed authentications from this addressWait for Retry-After, and stop using revoked keys
503 gateway_unavailableThe gateway cannot be reachedRetry shortly with the same key

Still stuck? Write to salam@rais.app with the Rais-Request-Id of the request that failed.