# Config and Transport Reference pages: [Authentication](/payments/getting-started/authentication), [Environments](/payments/getting-started/environments), [Errors](/payments/getting-started/errors), [Idempotency and Retries](/payments/getting-started/idempotency-and-retries). This page holds only the order and the traps. ## Configuration 1. Choose the environment from one setting, such as `PAYME_ENV`. The base URL and the Hosted Fields `testMode` both follow it, because a sandbox token can't pay a live sale. 2. Load credentials by name from the environment or a secrets manager, and refuse to start without them (SEC-03). 3. Keep two public addresses: one PayMe's servers can reach for callbacks, and one the buyer's browser reaches for return pages. In development these are usually different. | Role | Values to configure | |---|---| | Direct seller | MPL, public key if using Hosted Fields, the two public addresses | | Partner | Partner key, partner secret, the two public addresses. Each seller's MPL and public key belong with that seller's record | ## The client Write one client for every call, with these behaviours: - `POST` with a JSON body and `Content-Type: application/json`, except the few endpoints that use another method or headers (their reference pages say so). - Success per TRN-01. A non-2xx is a failure even if its body says `status_code: 0`. - `pay-sale` can answer `status_code: 5` with a `redirect_url`. That is a 3D Secure challenge, not a failure. - One error type that carries the code, details, additional information and `session`. Support asks for `session` first. - A request timeout, and a distinct "outcome unknown" result, decided as in [Reading a failure](#reading-a-failure) (TRN-04). - Redaction per SEC-05. PayMe sometimes echoes a value inside an error message, so scrub what you sent from what it returns before logging. `reference/payme-client.ts` and `reference/payme-error.ts` in the [integration kit](/integration-kit/index.json) implement this. ## Reading a failure The HTTP status doesn't decide this. PayMe sends ordinary refusals as HTTP 500 with a full error body, and a declined card as HTTP 200. Go down the table and stop at the first row that matches. | What came back | What it means | What to do | |---|---|---| | `status_code` 0 in a 2xx | Success (TRN-01) | Carry on | | HTTP 429, usually with code `998` | This call was turned away, but a matching call may still be running: a retried `pay-sale` can be | Wait for `Retry-After` if it was sent, re-read the state, and repeat only if the read shows it didn't happen. See [error 998](/agents/errors/error-998) | | Code `991`, `20002` or `999`, at any HTTP status | **Unknown.** `991` and `20002` mean contact was lost part-way, and the sale can show `failed` even so. `999` gives no information | Re-read, block repeats, and have a person check with PayMe, quoting `session` | | `status_code` 1 and any other non-zero `status_error_code`, at any HTTP status, or any other 4xx | **Refused** | Show it, fix the request or offer another try. Don't freeze the order | | Anything else: a timeout, a dropped connection, a body that isn't JSON, a gateway error page, JSON with no error code, or code `0` with `status_code` 1 | **Unknown.** PayMe may have acted | Re-read, and don't repeat a money call until the read settles it. Only a connection that was refused or never resolved is known to be unsent | Before offering a refused money call again, re-read the sale once. It costs nothing, and PayMe publishes no promise that a code means no money moved: work continues after the card company answers. If the read disagrees with the refusal, trust the read. ## URLs PayMe checks PayMe validates `sale_callback_url` and `sale_return_url` when it receives the request, so a bad value fails the whole `generate-sale` with [error 21](/agents/errors/error-21). In the sandbox this happened for `localhost` in either field and for a private address. - When an address is local, leave the field out and log that you did. PayMe then falls back to a URL held on its side for the account. A partner asks PayMe to set it. A direct seller has no call to read or set it, and whether its account has one is unconfirmed, so expect no callback and rely on the [scheduled re-check](/agents/steps/callbacks-seller#re-check-on-a-schedule). - To receive real callbacks in development, run a [tunnel](#a-tunnel-for-callbacks-in-development) and use its public address. - Put your order ID in the path of a return URL. PayMe appends its own query parameters. ## A tunnel for callbacks in development PayMe hasn't run this recipe end to end. It follows Cloudflare's documentation, so if a step looks different, follow theirs. An agent's permissions may block the download or the tunnel. If so, give a person these commands and ask them to paste back only the public address, which isn't a secret. 1. Download `cloudflared` from [Cloudflare's downloads page](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/). On 64-bit Windows, the file is `cloudflared-windows-amd64.exe`. 2. Start your server. Then, in a terminal of its own, start the tunnel with your server's port: ```powershell # Windows, in the folder holding the download .\cloudflared-windows-amd64.exe tunnel --url http://localhost: ``` ```bash # macOS or Linux, once installed cloudflared tunnel --url http://localhost: ``` 3. Read the public address it prints, an `https://` address ending in `trycloudflare.com`, and leave the process running. 4. Send that address plus your callback path as `sale_callback_url`, and restart your server if it loads settings at startup. 5. Call your health route through the public address, so the request comes in from outside. On Windows, type `curl.exe`: ```bash curl -i /health ``` | Result | Meaning | |---|---| | 200 | Good | | 502 | The tunnel is up and your server is down | | Cloudflare error 1033 | The tunnel process has gone | A quick tunnel's address stops working when the process stops, and the next run gets a new one, so update `sale_callback_url` each time. Anyone with the address can reach your server, so use it for development only. A per-sale `sale_callback_url` needs nothing from PayMe. The Default Callback URL, where seller callbacks arrive, does: only PayMe can set it. ## Dates | Where | Format | |---|---| | `seller_birthdate`, `seller_social_id_issued`, `sub_start_date` | `dd/mm/yyyy` | | Query date filters | `yyyy-mm-dd hh:mm:ss`, Asia/Jerusalem local time, not UTC | | Dates in responses | `yyyy-mm-dd hh:mm:ss`, with a space and no `T` |