> ## Agent Instructions > Use the Payrails Web SDK v6 for new browser integrations. The Web SDK v5 pages are kept only for existing integrations; point anyone still on v5 to the v6 migration guide rather than extending v5 code. > Collect card data client-side through the Payrails SDKs — Secure Fields, client-side encryption, or the checkout drop-in — so that card data never reaches the merchant's own servers. Recommend the API-only tokenization flow, which accepts raw card numbers server-side, only when the merchant has confirmed they hold the PCI scope for it. > Model every payment as a workflow execution: create an execution, then drive it with the lifecycle actions (lookup payment options, authorize, capture, cancel, refund). Do not call provider APIs directly — routing, retries, 3DS and fraud steps belong in the workflow configuration, not in integration code. > Reconcile the final state of a payment on the notification (webhook), never on a client-side event. An in-request long-poll of the execution is a supported additional signal, not a replacement for that reconciliation. > Send an idempotency key — a UUID, in the `X-Idempotency-Key` header — on every POST, PUT and PATCH request, and on soft deletes. GET requests need none, and hard deletes cannot be idempotent. > Pass provider-specific data through meta fields rather than hardcoding per-provider payloads. Payrails translates meta fields into each provider's own format. > Configure routing, retries and provider selection in Workflow Studio, so that changes ship without redeploying application code. # Set up your Payrails account and environment Source: https://docs.payrails.com/docs/account-setup Set up the account foundations every Payrails module shares: API credentials and mTLS, users and roles, and workspaces. Before integrating any Payrails module—whether it’s Payment Acceptance, Token Vault, Fraud Management, Reconciliation, or Analytics—you’ll need to set up the foundational elements of your account and environment. This section guides you through everything required to get started securely and efficiently. Payrails is modular, but your setup is centralized: once configured, these settings apply across all modules and teams in your organization, ensuring a consistent and secure foundation for your integration. ## What You’ll Set Up Each of the following sections walks you through a key part of your integration foundation. You will be provided staging and production environments to separate testing from live traffic, and will manage below aspects for each separately. ### 1. API Credentials and mTLS Learn how to generate, rotate, and manage API credentials for secure access across environments, as well as configure the mutual TLS for added security. ### 2. Users, Roles & Permissions Invite your team, assign permissions, and control access across workspaces and modules. ### 3. Organizations & Workspaces Understand how organizations are structured in Payrails and how workspaces isolate data, environments, and permissions. # API Credentials Source: https://docs.payrails.com/docs/account-setup/api-credentials Create and manage the client ID and client secret that authenticate your Payrails API calls, scoped per environment and workspace. ## Overview When starting to work with Payrails, one of the first steps is obtaining your API credentials for your account to authenticate Payrails APIs. Authentication ensures that only authorized users or systems can access the API, helping protect sensitive data, prevent misuse, and maintain the integrity of services. API credentials are created and managed in the Payrails Portal. The Client ID and Client Secret are the credentials you use to start interacting with the Payrails API in both staging and production environments. Credentials are scoped per environment and can be created at the organization level or for a specific workspace to match your operational model. Use these credentials from your backend services to request an access token, and then call Payrails APIs with that token. ## Prerequisites * Admin or Developer role in the Payrails Portal to access the API credentials page. See roles and permissions for details. * Decision on scope: organization‑level or a specific workspace. * A secrets manager available to store the `Client Secret` securely. ## Configuration steps Follow these steps to create credentials in the Portal. Empty credentials page 1. Log in to the Payrails Portal. 2. Navigate to `Settings → API credentials`. 3. Select Create credentials. 4. Name the credential: * **Name** (required): Use a descriptive label (for example, “Checkout backend — staging”). * **Description** (optional): Add operational context (owner, system, rotation policy). New api credentials - step 1 5. Choose scope: * **Organization** — credential is valid for the entire organization. * **Workspace** — credential is limited to a selected workspace. Choose the workspace from the selector. * Apply least‑privilege. Grant only what the system needs. 6. Create the credential. The portal shows the `Client ID` and the `Client Secret`. New api credentials - step 2 7. Copy both values and store the secret in your secrets manager. The secret is displayed once during creation. 8. Use these credentials in your system to request an access token to call Payrails APIs. ## Rotate and revoke Rotating your client secret improves security and supports compliance. Api credentials details 1. Navigate to `Settings → API Credentials`. 2. Select the API credential for which you want to rotate the secret. 3. Click on "Rotate Secret" and follow instructions. Credentials rotation dialog 4. Copy the new `Client Secret` and update your services to use it for token requests. 5. After rotation, the previous Client Secret becomes invalid immediately. Notes * You can have multiple `Client IDs` (and their secrets) active at the same time. Use this to ensure uninterrupted access during migrations. * Revoke a credential if it's no longer needed or suspected to be compromised. Revocation is immediate and irreversible. ## FAQs and edge cases Admin and Developer roles. Yes. Create separate API Credentials for systems or deployments to isolate risk and simplify rotation. Yes. Multiple `Client IDs` and secrets can be active concurrently to ensure uninterrupted access during changes. No. Create separate credentials for Staging and Production. No. Copy it during creation or rotation and store it in a secrets manager. One hour. Request a new token after expiry. There is no upper limit for generating access tokens. # Idempotent Requests Source: https://docs.payrails.com/docs/account-setup/idempotent-requests Use the X-Idempotency-Key header to retry a Payrails API request safely, without creating duplicate records or repeating an update. Our API offers idempotency features to ensure safe retries of requests without unintentional duplicate operations. Integrating an idempotency key can prove invaluable if you're working on actions like record creation or updates. This key allows you to re-initiate a request, especially in situations like connectivity disruptions, ensuring no unwanted duplications or repeated updates. ## Making an idempotent request For an idempotent request, include an extra header: `X-Idempotency-Key: ` Upon receiving a request with a unique idempotency key, our system commits to memory the status code and the response body. This holds irrespective of whether the request was a success or a failure. Any subsequent requests with the same key will fetch identical responses, preserving this consistency even in case of server errors. ## What is an idempotency key? This key is a unique marker, generated on the client side, which our server leans on to detect and avert potential repetitions stemming from retried requests. Key aspects include: * **Generation:** While the method for generating unique keys rests with you, we accept only UUIDs as idempotency keys. This ensures a low likelihood of overlapping keys. * **Storage considerations:** It's important to note that results are only stored if an API endpoint has started processing. Should the incoming parameters fail validation, or if another conflicting request is being processed simultaneously, no idempotent result will be stored. In such scenarios, it's safe to reinitiate these requests. ## Idempotency in different HTTP Methods * **POST, PUT, PATCH:** All requests must be paired with idempotency keys to ensure safe retries. * **GET:** Attaching idempotency keys to GET requests is unnecessary and should be refrained from, given that it is inherently idempotent. * **DELETE:** We require an idempotency key in soft-delete operations. However, hard-delete operations cannot be idempotent because the previous record will not exist on subsequent calls. # mTLS Configuration Source: https://docs.payrails.com/docs/account-setup/mtls-configuration Learn how to set up a secure connection with Payrails through mTLS. ## Overview Mutual TLS (mTLS) adds certificate‑based authentication to your API traffic with Payrails. In addition to OAuth client credentials, mTLS verifies the calling system by requiring a valid client certificate during the TLS handshake. This strengthens inbound authentication and helps meet enterprise security and compliance requirements. This guide covers two flows: * Certificate exchange: request, issue, download, rotate, and revoke mTLS client certificates in the Payrails Portal. * Use and test: configure Postman (or another HTTP client) to present the certificate and validate calls. Certificates are scoped per environment: you will need to create one for staging and one for production. ## Prerequisites * Admin or Developer role in the Payrails Portal. * Existing API credentials (Client ID/Secret) for your service if you also use OAuth. See API credentials * A secure place to store private keys and certificates (for example, your secrets manager or key vault). * Postman desktop app (for the test flow), a terminal with curl or any HTTP client that supports client certificates. ## Configuration steps ### Request and manage mTLS certificates Create a client certificate for your service and download it for installation. MTLS certificates list empty 1. In the Payrails Portal, go to `Settings → mTLS certificates`. 2. Select `Create certificate` and provide a description if desired: owner, rotation policy or related service. 3. Provide organization details to generate the CSR command: * Organization name: your legal company name. * Country and state/province: if unsure, use your headquarters. These inputs are not binding. MTLS CSR organization details 4. Generate your private key and CSR: * The interface displays a pre‑filled OpenSSL command. Copy it and run it in your terminal from the directory where you want the files saved. * The Common Name (`CN`) of the CSR must be the value that the Payrails Portal shows in the command. Payrails rejects a CSR with any other `CN`, so copy the command from the Payrails Portal each time instead of reusing a saved command or script. * The command creates two files: a private key and a Certificate Signing Request (CSR). * Store the private key securely; you will use it when configuring your client later. * Keep the CSR file ready for submission in the next step. MTLS CSR command generated 5. Submit the CSR generated in step 4. 6. The certificate is issued automatically after submission: click `Download` to download it. MTLS certificate issued download 7. Install the certificate in your service or keep it ready for local testing (see the Postman section below). 8. Click on `Continue to configuration` to [test and configure your mTLS certificate](#test-and-configure-your-mtls-certificate). ## Validate and test ### Test and configure your mTLS certificate You can test your mTLS certificate with cURL or Postman, follow the instructions on the screen. MTLS test configure overview MTLS test configure curl MTLS test configure postman ### Configure curl to use mTLS The exact command to use mTLS with CLI depends on the tool you're using. Here's an example with curl to retrieve an access token from Payrails API: ``` curl --cert domain.pem --key domain.key \ --location --request POST 'https:///auth/token/' \ --header 'Accept: application/json' \ --header 'x-api-key: ' ``` * `domain.pem`: the certificate file [downloaded](#request-and-manage-mtls-certificates) (or sent to you) in Step 2, * `domain.key`: the private key file generated in Step 1, * If the private key requires a passphrase, you will also need to provide it with `--pass` argument. * `Client ID` and `Client Secret` are the API credentials. [See how to retrieve them](/docs/account-setup/api-credentials#configuration-steps). ### Configure Postman to use mTLS From certificate details MTLS certificate details postman setup 1. Open the certificate from the list to view `Certificate details`. 2. Select `Download .pem` and save the file. 3. Select `Configure in Postman` to open the guided steps. Step 1 of 3 — Test with cURL (optional) * Copy the cURL command shown in the interface and run it in your terminal from the directory where your `-####.key` and `-####.pem` are saved. * Replace placeholders with a valid `Client ID` and `Client Secret` from your API credentials. * On success, the response includes an access token. If it fails, verify the credentials and that both the key and certificate paths are correct. Step 2 of 3 — Configure in Postman 1. Open Postman and go to `Settings → Certificates`, then select `Add certificate`. 2. Host: enter the host value shown in the interface for your environment. 3. `CRT file`: select the downloaded `-####.pem` certificate from Payrails. 4. `KEY file`: select the previously saved `-####.key` private key you generated during the CSR step. 5. Select `Add` to save the certificate mapping. Step 3 of 3 — Test in Postman 1. Create a `POST` request to the endpoint indicated in the interface (for example, `/token`). 2. Include your API credentials as instructed on screen (for example, `client_id` in path variables and `client_secret` in authorization details). 3. Send the request. A successful TLS handshake and authorization returns an access token. ## Troubleshooting * Handshake failed in Postman: * Verify the host and port match the values shown in the interface. * Ensure the client certificate is attached to that host entry and imported correctly. * If a passphrase was shown at download time, confirm it is entered correctly. * `CommonName (CN) '' must be ''` when you submit the CSR: the `CN` in the CSR is not the value that the Payrails Portal shows. This happens when you reuse a saved OpenSSL command or script, for example one that sets the `CN` to an API domain. Copy the current command from the Payrails Portal, run it again, and submit the new CSR. * 401/403 after handshake: OAuth or API authorization failed. Acquire a valid access token and ensure the calling client has required permissions. * Revoked certificate: issuance of a new certificate is required; revoked certificates cannot be re‑enabled. * Maximum number of active certificates reached: we limit the number of certificates to prevent abuse. If you reached your limit, either revoke an existing certificate that is no longer in use or contact your Payrails administrator to increase your limit. MTLS certificate limit warning ## Why is my certificate marked as Deprecated? MTLS certificate deprecated status As part of an improvement to the stability of our platform, we are migrating away from Cloudflare as a Certificate Authority (CA) for our MTLS authentication. We have introduced new Payrails-managed CAs for both staging and production. These CAs are already active and currently operate in parallel with the existing Cloudflare CAs. **All Cloudflare issued certificates are still valid but marked as deprecated as they would need to be replaced by certificates issued by Payrails CA instead.**\ **Once the transition to Payrails CA is done, Cloudflare certificates will automatically be revoked.** **Action required by 23 March 2026** To ensure continued mTLS connectivity, please: 1. Regenerate your client certificate via the Payrails Portal (for staging and/or production, as applicable). Please note that the Portal now supports direct certificate generation for staging, in addition to production. 2. Deploy the newly generated certificate in your environment. 3. Confirm that traffic is no longer relying on the previous Cloudflare CA. All newly generated certificates are now signed by the Payrails CAs. Once all merchants have migrated, we will fully decommission the Cloudflare CA. We would appreciate it if you could complete the migration **by 23 March 2026** to help ensure continued, uninterrupted mTLS connectivity. If you have questions about the transition, please let us know. # Organization Source: https://docs.payrails.com/docs/account-setup/organization Your organization with unified view across all your workspaces, ensuring streamlined access and management. ## Introduction The **organization context** represents your Payrails account and consolidates all [workspaces](/docs/account-setup/workspaces) under a single organizational structure. This update simplifies navigation, centralizes settings, and enhances role-based permissions (see: [User Roles & Permissions](/docs/account-setup/user-management)). ### Key Features 1. **Global insights** Analyze aggregated data from all workspaces, with filters for workspace-specific details. 2. **Improved [User Roles & Permissions](/docs/account-setup/user-management) system** Define roles and permissions at both the organization and workspace context to ensure that each team member has appropriate access, enhancing both security and operational efficiency. 3. **Flexible workspace management** Switch seamlessly between the organization-level context and individual workspaces using the new picker in the left menu, which also includes the sign-out option. This feature enhances your ability to compare statistics across workspaces and manage configurations from a centralized perspective. Organization context overview ### Roles & permissions The new organization context includes a refined roles and permissions system, enabling precise access control across organizations and workspaces. **Role categories** 1. **Organization roles** * **Admin**: Full control over the organization, including access rights, users, and all connected workspaces. Ideal for strategic leads like CFOs or Heads of Payment. * **Developer**: Designed for technical roles, with access to manage APIs, integrations, and certificates while viewing aggregated workspace data. Note: Developers cannot access user data. * **Viewer**: Read-only access to organization-level insights, suited for oversight roles. Organization roles overview 2. **Workspace roles** * **Admin**: Comprehensive access to configure and manage specific workspaces. Suitable for general managers or other leadership roles. * **Operator**: Limited access focused on operational tasks, such as processing refunds, without configuration permissions. Ideal for support roles like customer support or payment managers. * **Viewer**: Read-only access designed for monitoring individual workspaces. Admins can assign organization-level roles and adjust workspace-specific permissions as needed, enabling tailored access for each user. This flexibility ensures enhanced security and operational efficiency. Workspace roles overview ### User management: simplified invitations To ensure smooth setup, organization admins automatically gain admin rights across all workspaces. Workspace-level roles for developers or viewers must be assigned manually. Admins can invite users to the organization and assign roles during the invitation process. **Clone workspaces: accelerate setup** The new cloning feature simplifies creation of additional workspaces. Duplicate configurations, integrations, notification settings, and user roles to maintain consistency and save time. Workspace cloning overview ### How does this benefit you? * **Simplified Management:** Enjoy a holistic view of your organization's payment setups and operations, leading to smarter decision-making and greater adaptability. * **Enhanced Security:** Clearly defined roles ensure team members can access only what they need, reducing risks while maintaining flexibility. * **Efficient Onboarding and Configuration:** Reduce the time and complexity involved in setting up new workspaces, making it easier to expand your operations quickly and securely. # User Management Source: https://docs.payrails.com/docs/account-setup/user-management Learn about user authentication, roles and permissions, and how to manage lifecycle of users. ## Role-Based Access Control (RBAC) Role-Based Access Control (RBAC) is a robust security model that organizes access permissions based on user roles. In RBAC, users are assigned specific roles, each with well-defined permissions. Rather than assigning permissions directly to individual users, access is governed through roles. This streamlined approach simplifies administration, enhances overall security, and ensures that users only possess the access necessary for their designated roles. This minimizes the risk of unauthorized actions, contributing to improved system management. There are two primary methods through which users interact with the Payrails system. Users can utilize the merchant portal for tasks such as configuring workflows or gaining insights into executions and reports. Alternatively, they can interact programmatically via API and SDK. In both scenarios, user roles are assigned to the individuals managing user accounts or to the machines involved in machine-to-machine communication. ## Best Practices As part of our commitment to security and compliance with PCI DSS requirements, we provide the following guidelines to help customers create strong authentication credentials and protect their accounts from unauthorized access. * **Least Privilege Principle:** Assign the minimum necessary permissions to users based on their roles. This reduces the risk of unauthorized access and potential security breaches. * **Regular Audits:** Periodically review and update user roles and permissions to align with organizational changes. Remove unnecessary access for users who have changed roles or responsibilities. * **Training:** Provide training sessions for users on the assigned roles and the associated permissions. This ensures that everyone is aware of the actions they can perform within the system. ### Guidance on Selecting Strong Authentication Factors A strong password is critical for securing your account. When creating a password, follow these best practices: * Use a minimum of 12 characters (longer is better). * Include a mix of uppercase and lowercase letters, numbers, and special characters. * Avoid dictionary words, common phrases, or easily guessable information (e.g., "password," "123456," "qwerty," your name, or birthdate). * Do not use variations of personal information, such as reversed spellings or adding numbers to familiar words. * Consider using passphrases (e.g., "Blue!Ocean&77\@Sunset") for enhanced security. ### How to Protect Your Authentication Factors Your password is the key to your account. Take the following measures to keep it secure: * Do not share your password with anyone, including colleagues, friends, or customer support personnel. * Do not write down your password or store it in an easily accessible location. * Use a password manager to securely store and generate unique passwords. * Enable multi-factor authentication (MFA) whenever possible for added security. ### Avoid Reusing Previously Used Passwords To prevent unauthorized access, never reuse passwords from other systems or previous credentials. Each account should have a unique password. This prevents attackers from using stolen passwords from one system to gain access to another. ### Changing Your Password if Compromised If you suspect that your password has been compromised, take immediate action: 1. **Change your password immediately** using the password reset feature. 2. **Notify Payrails security team** at \[[security@payrails.com](mailto:security@payrails.com)] if you suspect unauthorized access. 3. **Monitor your account activity** for any suspicious transactions. 4. **Update any other accounts** that used the same password (if applicable). By following these guidelines, you can help protect your account and ensure the security of your authentication credentials. If you have any questions, please contact our security team. ## FAQ For answers to common questions about roles, passwords, and SSO access, see [Frequently asked questions](/docs/account-setup/user-management/frequently-asked-questions). # Authentication Source: https://docs.payrails.com/docs/account-setup/user-management/authentication Learn more about possible alternative authentication methods. ## User authentication The Payrails portal supports two user authentication methods: 1. Single Sign-On (SSO) 2. Non-SSO Each user type has distinct characteristics regarding access and permissions within the portal. ### Single Sign-On (SSO) SSO users access the portal through a centralized authentication system. Upon joining the portal, SSO users are assigned the default user role called "Viewer." This role is designed for limited access, allowing users to view only the Dashboard section within the merchant portal. Users requiring additional access must contact their administrator to obtain relevant permissions for the portal. #### Activating SSO authentication for you Payrails portal By default, SSO access is not activated for merchants within the Payrails portal. Merchants interested in using SSO functionality must contact their Payrails business partner. At the moment merchants portal supports OKTA as an SSO provider. ### Non-Single Sign-On (Non-SSO) Non-SSO users access the portal through traditional authentication methods. Unlike SSO users, they do not receive automatic role assignments upon joining the portal. Instead, administrators manually assign roles and permissions based on the user's responsibilities and access requirements. # Frequently Asked Questions Source: https://docs.payrails.com/docs/account-setup/user-management/frequently-asked-questions Learn answers to frequently asked questions. To request additional permissions, reach out to your administrator or the designated role manager. They can assess your request, considering the principle of least privilege, and make necessary adjustments if required. No, each account is assigned a single role to maintain clarity and adhere to the principle of least privilege. If your responsibilities change, contact the administrator to reassess and adjust your role accordingly. If you suspect unauthorized access or notice any unusual activity, immediately report it to your administrator. They will investigate the issue and take appropriate measures to secure the system. Additionally, change your password immediately and ensure that multi-factor authentication (MFA) is enabled. It is recommended to change your password periodically and immediately if you suspect it has been compromised. Avoid reusing previous passwords and use a password manager to generate and store secure passwords. Yes, role changes take effect immediately upon assignment. However, it's recommended to log out and log back in to ensure the updated roles and permissions are applied consistently. Roles and permissions should be audited regularly, at least quarterly, or whenever there are organizational changes. Regular audits help ensure that access levels align with current business requirements and reduce security risks. No, the roles are predefined to maintain consistency and security. If you have specific access requirements, discuss them with your administrator, and they can assess whether adjustments are necessary within the existing role structure. There is a known limitation with our portal which prevents direct connection from your SSO portal (for example, Okta) to our portal. To access the portal with your SSO login, you need to access via the direct portal URL instead (for example, `https://yourcompany.payrails.io/`). # Roles & Permissions Source: https://docs.payrails.com/docs/account-setup/user-management/roles-permissions Find all assigned roles and permissions for each API service. ## User Roles There are dedicated roles for [workspace](/docs/account-setup/workspaces) and [organization](/docs/account-setup/organization) context within the portal. ### Organization roles * **Admin** - Can access and manage everything, including all workspaces and their aggregated data. Will be Admin in all workspaces. * **Developer** - Can access workspaces they are added to and manage everything except users for the organization. Will have access to aggregated data from the workspaces they are added to. * **Viewer** - Can access workspaces they are added to and view data related to the organization. Will have access to aggregated data from the workspaces they are added to. * **None** - Can only access workspaces they are added to. Will not have access to the organization or an aggregated view. ### Workspace roles * **Admin** - Can manage everything in the workspace, including users and access. * **Operator** - Can view data and trigger actions such as refunds, but has no access to configurations. * **Viewer** - Can only view data. ## Roles & Permissions Matrix Visualize the roles and their corresponding permissions across various services with our comprehensive matrix. This tool illustrates the access levels of each role to specific actions within key service categories, including Auth, Ledger, Merchant, and Payment. Below, we present individual Role & Permissions Matrices for each service: ### Portal | **Action description** | **Org-Admin** | **Org-Developer** | **Org-Viewer** | **WS-Admin** | **WS-Operator** | **WS-Viewer** | | - | - | - | - | - | - | - | | View organization context | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ | | List all workspaces | ✓ | ✗ | ✗ | ✗ | ✓ | ✗ | | List assigned workspaces | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ | | Create a workspace | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | Update a workspace | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ |
### User Management | **Action description** | **Org-Admin** | **Org-Developer** | **Org-Viewer** | **WS-Admin** | **WS-Operator** | **WS-Viewer** | | - | - | - | - | - | - | - | | List users | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | List external users | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | View user details | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | View user logged in info | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Export list of users | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Export list of external users | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | Create users | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | Assign role | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Assign/Unassign organization and workspace roles | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | Assign/Unassign workspace roles | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | | Block a user | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | Unblock a user | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | Reset a user password | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | Reset a user MFA | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | Sync a user or all users | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | List roles | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | List organization and workspace roles | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | View role details | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ |
### Authentication | **Action description** | **Org-Admin** | **Org-Developer** | **Org-Viewer** | **WS-Admin** | **WS-Operator** | **WS-Viewer** | | - | - | - | - | - | - | - | | List clients | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | View client details | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | Create a client | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | Delete a client | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | Rotate API secret | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | List API secret | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | Create API secret | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ | | List MTLS certificate | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | Read a MTLS certificate | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | Create a MTLS certificate | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | Import a MTLS certificate | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Revoke a MTLS certificate | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ |
### Executions & Payments & Actions | **Action description** | **Org-Admin** | **Org-Developer** | **Org-Viewer** | **WS-Admin** | **WS-Operator** | **WS-Viewer** | | - | - | - | - | - | - | - | | List executions | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | View execution details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Lookup | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Authorize an execution | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | Cancel an execution | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | | Capture an execution | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | | Confirm an execution | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | Create an execution | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | | Refund an execution | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | | List payments | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | View payment details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | List actions | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | View action details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
### Alerts | **Action description** | **Org-Admin** | **Org-Developer** | **Org-Viewer** | **WS-Admin** | **WS-Operator** | **WS-Viewer** | | - | - | - | - | - | - | - | | Update a field | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | List alert logs | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | | Evaluate an alert | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | | Update an alert | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | View alert configs details | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | | List alert configs | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | | Create an alert config | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | | Update an alert config | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | | Delete an alert config | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ |
### Notifications | **Action description** | **Org-Admin** | **Org-Developer** | **Org-Viewer** | **WS-Admin** | **WS-Operator** | **WS-Viewer** | | - | - | - | - | - | - | - | | View notification config details | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | List notification configs | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | Create a notification config | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | Update a notification config | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | Delete a notification config | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ |
### Merchant Configuration | **Action description** | **Org-Admin** | **Org-Developer** | **Org-Viewer** | **WS-Admin** | **WS-Operator** | **WS-Viewer** | | - | - | - | - | - | - | - | | List workflows | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | | View workflow details | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | | Create a workflow | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | List rulesets | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | | View ruleset details | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | | Create ruleset | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | Consumercheckout read config (SDK) | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | | Consumercheckout write config (SDK) | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | | List frauds | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | View fraud details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | List holders | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ | | View holder details | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ | | Create Holder | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | Read config (SDK) | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | | View field details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | List fields | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Create a field | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Read BINs | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | List all currencies from current payments | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | List raw notifications sent by providers | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
### Integrations | **Action description** | **Org-Admin** | **Org-Developer** | **Org-Viewer** | **WS-Admin** | **WS-Operator** | **WS-Viewer** | | - | - | - | - | - | - | - | | List providers active | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | List providers | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | View provider details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Update providers | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Proxy providers | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ | | List provider configuration | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Get provider configuration by id | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Create provider config | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ | | Delete provider config | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Update provider config | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ | | Assign provider config to workspaces | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ | | List integrations | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
### Tokenization | **Action description** | **Org-Admin** | **Org-Developer** | **Org-Viewer** | **WS-Admin** | **WS-Operator** | **WS-Viewer** | | - | - | - | - | - | - | - | | Get instrument details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | List Instruments | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Create instrument | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Update instrument | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | Delete instrument | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | | Tokenize instrument | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | List tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Get token details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Create token | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Update token | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Delete token | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Vault read config | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | View and select vault in the portal | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | List API logs | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Get API log details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
### Analytics | **Action description** | **Org-Admin** | **Org-Developer** | **Org-Viewer** | **WS-Admin** | **WS-Operator** | **WS-Viewer** | | - | - | - | - | - | - | - | | Get dataset details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | List datasets | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Get export details | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | List exports | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Create an export | ✓ | ✓ | ✗ | ✓ | ✓ | ✓ | | Read analytics | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | # Single Sign-On Source: https://docs.payrails.com/docs/account-setup/user-management/single-sign-on How to configure and maintain SAML SSO in Payrails using your organization's identity provider. ## Overview Payrails supports Single Sign‑On (SSO) using SAML, allowing organizations to authenticate users with their existing identity provider (IdP). SSO is configured per environment (Staging and Production) in the Payrails Portal. This centralizes authentication, improves your security posture, and reduces operational overhead associated with managing separate credentials. Supported IdPs include Okta, JumpCloud, Google Workspace, Microsoft Entra/Azure AD, and Auth0 (as an external IdP). ## Prerequisites * Access to your IdP with permission to create or configure a SAML application. * A test user in your IdP to validate end‑to‑end authentication before broad rollout. * A SAML metadata URL provided by your IdP. File uploads/XML are not supported—URL only. * Recommended reading to understand the basics: Okta’s Beginner's Guide to SAML — [https://developer.okta.com/docs/concepts/saml/](https://developer.okta.com/docs/concepts/saml/) ## Configuration Steps 1. In the Payrails Portal, go to `Settings → Identity → SSO`. Payrails SSO settings page 2. From the provider dropdown, choose your IdP (Okta, JumpCloud, Google Workspace, Microsoft Entra/Azure AD, or Auth0). This helps the Portal tailor the guidance you see. 3. Copy the values shown by Payrails for your IdP setup: * `Entity ID / Audience URI` * `ACS (Assertion Consumer Service) URL` 4. In your IdP, create a new SAML application and set: * Audience/Entity ID = Payrails `Entity ID / Audience URI` * ACS/Callback URL = Payrails `ACS URL` 5. Back in Payrails, paste your IdP’s `SAML Metadata URL` into the configuration form (URL only). 6. Select `Save` to apply the configuration. The connection becomes active for that environment. Payrails SSO configuration form 7. To rotate certificates/metadata later, press `Refresh` to pull the latest metadata from the same URL. Use `Edit configuration` only if the metadata URL itself changes. Only one SSO configuration is supported per environment. ## Validation & Testing Validate the configuration in Staging before enabling Production. 1. Assign a test user to the SAML application in your IdP. 2. Sign out of the Portal, then initiate sign‑in using SSO in your staging/non‑production environment. 3. Complete the IdP login; you should be redirected back to Payrails and signed in. 4. Confirm the user lands in the expected workspace(s) and can access permitted areas. 5. Assign the appropriate roles and permissions at the workspace or organization level so the user has the intended access. 6. If rotating certificates or metadata, use `Refresh` (as long as the metadata URL hasn’t changed). If the URL changed, open `Edit configuration`, update the URL, save, and re‑test. ## Troubleshooting Use the following checks to diagnose common setup issues (no specific error messages referenced): * Verify the `SAML Metadata URL` is reachable and current (after any cert rotation). * Confirm the `Entity ID/Audience URI` and `ACS URL` exactly match the Payrails values (no whitespace or typos). * Ensure the IdP NameID resolves to the user’s email used in Payrails. * Check time synchronization (IdP and client clocks) to avoid assertion validity issues. * Make sure the user is assigned to the SAML application in your IdP. ## FAQs & Edge Cases Not currently. Only a single SSO configuration per environment is supported. Disabling is not supported. You can remove the configuration. Removing SSO immediately stops new SSO logins for that environment. SSO accounts are created as new identities. Username/password users can continue using their credentials unless your organization admins choose to disable those accounts. Not supported. ## Related Topics * Workspaces: [/docs/account-setup/workspaces](/docs/account-setup/workspaces) * Organizations: [/docs/account-setup/organization](/docs/account-setup/organization) * User Roles & Permissions: [/docs/account-setup/organization](/docs/account-setup/organization) * Roles & Permissions (overview): \[roles-permissions) # Workspaces Source: https://docs.payrails.com/docs/account-setup/workspaces Learn about workspaces which helps to create segregated and separately managed spaces within your organization. ## Introduction Workspaces in Payrails are designed to help you effectively manage and organize your account. They provide a dedicated environment for configurations, payments, executions, and integrations. Workspaces improve team collaboration, while maintaining secure access control, ensuring that your operations run smoothly. Each Workspace is linked to your Payrails account [Organization](/docs/account-setup/organization). ### What are the benefits of using workspaces? Workspaces are a great tool for ensuring Simplicity and Security. #### Simplicity * Each workspace has a dedicated payment acceptance workflow configuration. This allows you to setup different workflows for separate workspaces. * They let you organize your payment management by business vertical, geographical location, organizational structure or any other logical separation you want to use. * Segregate integration configurations for different workspaces to avoid managing all your integrations in one page. * View and monitor insights on workflows (payments, executions) and analytics separately. #### Security * Manage people having access to the Payrails portal and specific workspaces with [Role-Based Access Control (RBAC)](/docs/account-setup/organization) ### How to set up workspaces? The agnostic nature of workspaces allows you to let them represent your companies business setup or any other logical structure you choose. You can use them to structure your Payrails account by: * **Country:** Each workspace represents a country. You can configure individual payment acceptance workflows for each country. (e.g. Germany, Brazil, UAE, etc.) This is the most used version. * **Region:** Each workspace represents a geographic country. You can configure individual payment acceptance workflows for each region. (North America, South America, EU, DACH, Benelux, etc.) * **Business verticals:** Each workspace represents a business vertical relevant to you. (e.g. Car Sharing, Taxi, Food Delivery) or currencies (EUR, USD, YEN) * **Currency:** Each workspace represents a separate currency. (e.g. EUR, USD, YEN) * **Payment methods:** Each workspace represents a payment method or provider. (Visa, Mastercard, Amex, etc.) Workspace setup examples ### How are payments linked to workspaces? Copy the workspace ID from the Portal and add them to the execution API calls as described in the API reference: [Create an execution](/reference/createexecution) ### What parts of the Payrails portal are managed in the workspace context? Within the Portal you'll find two logical contexts. 1. [Organization](/docs/account-setup/organization) - Your organization is your Payrails account. This is where global settings, configuration & users are managed. Data from all workspaces are aggregated in the organization context. 2. Workspace - Is always part of your organization. Data, settings and user management are restricted and confined within a given workspace. Payments, executions and users can be managed on both contexts. But, only data relevant for a given context will be shown. Let's assume there is a workspace for Germany and France and the organization is called ACME GmbH. Payments of Germany will not be shown in the France workspaces but are accessible in the organization context of ACME GmbH. More info on data separation and access can be found on the [Organization](/docs/account-setup/organization) page. ### How to create a new workspace? #### Prerequisites Only Organization-Admins have the permission to create new workspaces. If you think you should have that role please reach out to your Organization-Admin to change your role accordingly. #### Create a workspace There are 3 ways to create a new workspace: 1. Portal: 1. Create a new blank workspace, 2. Create a new workspace by cloning an existing workspace and all associated settings and users. 2. API: Create a new blank workspace via API. **Create an execution** Once you have created your workspace, you can execute a workflow for the particular workspace by passing the workspace ID as a parameter using the following curl command: ```sh theme={null} curl --request POST \ --url https://demo-api.staging.payrails.io/merchant/workflows/workflowCode/executions \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "workspaceId": "some-workspaceID-string" }' ``` For subsequent operations on the execution, such as refunding or canceling a payment, passing the workspace ID is not necessary because the workspace information will be inherited from the execution data. However, if you want to programmatically create a new provider configuration, you can pass the workspace ID as a parameter to create it within the workspace. For reference, check the API documentation: [/reference/listactiveproviderconfigs](/reference/listactiveproviderconfigs). For a detailed API guide to executions, check the following URL:\ [/reference/createexecution](/reference/createexecution). **Note:** If no workspace ID parameter is passed, the execution will be performed in the default workspace, which is called "Default Workspace" in the portal. ### FAQ No, at the moment, this is not possible, but it's part of the future development roadmap. Yes, upon creation of a new workspace, you have the option to copy workflow configurations, notification configurations and integration instances from any other workspace No. As long as you have access to the Portal, you can access a workspace within the Portal. Yes, notifications (webhooks) can be defined per workspace, default, or other workspace. # Dashboards Source: https://docs.payrails.com/docs/analytics-and-reporting/dashboards Filter a Payrails analytics dashboard, save the filter state as a custom view, and set a default view for each time you open it. ## Apply filters and save custom views * Navigate to Analytics and choose the dashboard that aligns with your analytical needs. * Apply filters available in the top bar. * Click My Views and save the current filter state. * You can set a saved view as the default for the dashboard. When you reopen the dashboard, the default saved view will automatically be applied. You can change the default to another saved view or remove the default at any time. ``` ```js theme={null} function openThreeDsChallenge(redirectUrl) { const iframe = document.getElementById("threeds-iframe"); iframe.src = redirectUrl; document.getElementById("threeds-modal").hidden = false; } // The Payrails return page posts back to the opener once your backend // has re-read the execution status. window.addEventListener("message", (event) => { if (event.origin !== window.location.origin) return; if (event.data?.type !== "threeds:complete") return; window.location.assign(`/order-confirmation/${event.data.orderReference}`); }); ``` ## Backend implementation The backend authenticates with Payrails, creates the execution, calls authorize against the tokenized `paymentInstrumentId`, and returns a clean two-case contract to the storefront. This code uses Python and the `requests` library; the same shape applies to any HTTP client. ### Authentication The Payrails OAuth token endpoint returns a token valid for one hour. Cache the token in memory and refresh on expiry. ```python theme={null} import os import requests PAYRAILS_HOST = os.environ['PAYRAILS_HOST'] PAYRAILS_CLIENT_ID = os.environ['PAYRAILS_CLIENT_ID'] PAYRAILS_CLIENT_SECRET = os.environ['PAYRAILS_CLIENT_SECRET'] def get_access_token() -> str: """Return a fresh Payrails OAuth token.""" response = requests.post( f'https://{PAYRAILS_HOST}/auth/token/{PAYRAILS_CLIENT_ID}', headers={'x-api-key': PAYRAILS_CLIENT_SECRET}, timeout=10, ) response.raise_for_status() return response.json()['access_token'] ``` ```java theme={null} import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; import org.json.JSONObject; public class PayrailsClient { static final String HOST = System.getenv("PAYRAILS_HOST"); static final String CLIENT_ID = System.getenv("PAYRAILS_CLIENT_ID"); static final String CLIENT_SECRET = System.getenv("PAYRAILS_CLIENT_SECRET"); private static final HttpClient HTTP = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(10)) .build(); public static String getAccessToken() throws Exception { HttpRequest req = HttpRequest.newBuilder() .uri(URI.create("https://" + HOST + "/auth/token/" + CLIENT_ID)) .header("x-api-key", CLIENT_SECRET) .timeout(Duration.ofSeconds(10)) .POST(HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse resp = HTTP.send(req, HttpResponse.BodyHandlers.ofString()); if (resp.statusCode() >= 300) { throw new RuntimeException("Auth failed: " + resp.body()); } return new JSONObject(resp.body()).getString("access_token"); } } ``` ```ts theme={null} const HOST = process.env.PAYRAILS_HOST! const CLIENT_ID = process.env.PAYRAILS_CLIENT_ID! const CLIENT_SECRET = process.env.PAYRAILS_CLIENT_SECRET! export async function getAccessToken (): Promise { const response = await fetch( `https://${HOST}/auth/token/${CLIENT_ID}`, { method: 'POST', headers: { 'x-api-key': CLIENT_SECRET }, }, ) if (!response.ok) { throw new Error(`Auth failed: ${await response.text()}`) } const body = await response.json() as { access_token: string } return body.access_token } ``` ```csharp theme={null} using System.Net.Http; using System.Net.Http.Json; using System.Text.Json.Serialization; public partial class PayrailsClient { private static readonly string Host = Environment.GetEnvironmentVariable("PAYRAILS_HOST")!; private static readonly string ClientId = Environment.GetEnvironmentVariable("PAYRAILS_CLIENT_ID")!; private static readonly string ClientSecret = Environment.GetEnvironmentVariable("PAYRAILS_CLIENT_SECRET")!; private static readonly HttpClient Http = new() { Timeout = TimeSpan.FromSeconds(10) }; public async Task GetAccessTokenAsync() { using var request = new HttpRequestMessage( HttpMethod.Post, $"https://{Host}/auth/token/{ClientId}"); request.Headers.Add("x-api-key", ClientSecret); using var response = await Http.SendAsync(request); response.EnsureSuccessStatusCode(); var body = await response.Content.ReadFromJsonAsync(); return body!.AccessToken; } private record TokenResponse( [property: JsonPropertyName("access_token")] string AccessToken); } ``` ```go theme={null} package payrails import ( "encoding/json" "fmt" "net/http" "os" "time" ) var ( Host = os.Getenv("PAYRAILS_HOST") ClientID = os.Getenv("PAYRAILS_CLIENT_ID") ClientSecret = os.Getenv("PAYRAILS_CLIENT_SECRET") httpClient = &http.Client{Timeout: 10 * time.Second} ) func GetAccessToken() (string, error) { url := fmt.Sprintf("https://%s/auth/token/%s", Host, ClientID) req, err := http.NewRequest(http.MethodPost, url, nil) if err != nil { return "", err } req.Header.Set("x-api-key", ClientSecret) resp, err := httpClient.Do(req) if err != nil { return "", err } defer resp.Body.Close() if resp.StatusCode >= 300 { return "", fmt.Errorf("auth failed: %d", resp.StatusCode) } var data struct { AccessToken string `json:"access_token"` } if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { return "", err } return data.AccessToken, nil } ``` ### Initialize the SDK session This call returns the SDK configuration the frontend uses to boot. The storefront's `/payments/init` endpoint on your backend proxies the call so the OAuth token stays on the server. The body passes `workflowCode`, `holderReference`, `workspaceId`, and the `type` that matches the element your storefront is about to mount. Use `"secureFields"` for Secure Fields and Card Form. Use `"tokenization"` for Card List, Apple Pay, and Google Pay. The response is the payload the frontend hands to `Payrails.init(...)` — return it from `/payments/init` verbatim. ```python theme={null} def get_client_init( holder_reference: str, init_type: str, ) -> dict[str, Any]: """Fetch a client/init payload from Payrails for the storefront SDK.""" token = get_access_token() response = requests.post( f'https://{PAYRAILS_HOST}/merchant/client/init', headers={ 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json', 'x-idempotency-key': str(uuid.uuid4()), }, json={ 'workflowCode': PAYRAILS_WORKFLOW_CODE, 'holderReference': holder_reference, 'workspaceId': PAYRAILS_WORKSPACE_ID, 'type': init_type, }, timeout=10, ) response.raise_for_status() return response.json() ``` ```java theme={null} // inside class PayrailsClient public static JSONObject getClientInit( String holderReference, String initType ) throws Exception { String token = getAccessToken(); JSONObject body = new JSONObject(Map.of( "workflowCode", WORKFLOW_CODE, "holderReference", holderReference, "workspaceId", WORKSPACE_ID, "type", initType )); HttpRequest req = HttpRequest.newBuilder() .uri(URI.create("https://" + HOST + "/merchant/client/init")) .header("Authorization", "Bearer " + token) .header("Content-Type", "application/json") .header("x-idempotency-key", UUID.randomUUID().toString()) .timeout(Duration.ofSeconds(10)) .POST(HttpRequest.BodyPublishers.ofString(body.toString())) .build(); HttpResponse resp = HTTP.send(req, HttpResponse.BodyHandlers.ofString()); if (resp.statusCode() >= 300) { throw new RuntimeException("Client init failed: " + resp.body()); } return new JSONObject(resp.body()); } ``` ```ts theme={null} export type ClientInitType = 'secureFields' | 'tokenization' export async function getClientInit ( holderReference: string, initType: ClientInitType, ): Promise> { const token = await getAccessToken() const response = await fetch( `https://${HOST}/merchant/client/init`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', 'x-idempotency-key': randomUUID(), }, body: JSON.stringify({ workflowCode: WORKFLOW_CODE, holderReference, workspaceId: WORKSPACE_ID, type: initType, }), }, ) if (!response.ok) { throw new Error(`Client init failed: ${await response.text()}`) } return response.json() } ``` ```csharp theme={null} public partial class PayrailsClient { public async Task GetClientInitAsync( string holderReference, string initType) { var token = await GetAccessTokenAsync(); var body = new { workflowCode = WorkflowCode, holderReference, workspaceId = WorkspaceId, type = initType, }; using var request = new HttpRequestMessage( HttpMethod.Post, $"https://{Host}/merchant/client/init") { Content = JsonContent.Create(body), }; request.Headers.Add("Authorization", $"Bearer {token}"); request.Headers.Add("x-idempotency-key", Guid.NewGuid().ToString()); using var response = await Http.SendAsync(request); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync() ?? throw new InvalidOperationException("Empty client init response"); } } ``` ```go theme={null} func GetClientInit( holderReference string, initType string, ) (map[string]any, error) { token, err := GetAccessToken() if err != nil { return nil, err } body, _ := json.Marshal(map[string]any{ "workflowCode": WorkflowCode, "holderReference": holderReference, "workspaceId": WorkspaceID, "type": initType, }) url := fmt.Sprintf("https://%s/merchant/client/init", Host) req, _ := http.NewRequest(http.MethodPost, url, bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") req.Header.Set("x-idempotency-key", uuid.NewString()) resp, err := httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode >= 300 { return nil, fmt.Errorf("client init failed: %d", resp.StatusCode) } var result map[string]any if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } return result, nil } ``` ### Create the execution The first call creates the execution and locks the metadata. The body carries `merchantReference`, `holderReference`, `workspaceId`, and the `meta` block. The body does not carry `amount`, `paymentComposition`, or `initialActions` — those live on the authorize call. ```python theme={null} import uuid from typing import Any PAYRAILS_WORKSPACE_ID = os.environ['PAYRAILS_WORKSPACE_ID'] PAYRAILS_WORKFLOW_CODE = 'payment-acceptance' def create_execution( merchant_reference: str, holder_reference: str, meta: dict[str, Any], ) -> str: """Create a Payrails execution with metadata only. Returns the executionId.""" token = get_access_token() response = requests.post( f'https://{PAYRAILS_HOST}/merchant/workflows' f'/{PAYRAILS_WORKFLOW_CODE}/executions', headers={ 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json', 'x-idempotency-key': str(uuid.uuid4()), }, json={ 'merchantReference': merchant_reference, 'holderReference': holder_reference, 'workspaceId': PAYRAILS_WORKSPACE_ID, 'meta': meta, }, timeout=10, ) response.raise_for_status() return response.json()['id'] ``` ```java theme={null} import java.util.Map; import java.util.UUID; import org.json.JSONObject; // inside class PayrailsClient static final String WORKSPACE_ID = System.getenv("PAYRAILS_WORKSPACE_ID"); static final String WORKFLOW_CODE = "payment-acceptance"; public static String createExecution( String merchantReference, String holderReference, Map meta ) throws Exception { String token = getAccessToken(); JSONObject body = new JSONObject(Map.of( "merchantReference", merchantReference, "holderReference", holderReference, "workspaceId", WORKSPACE_ID, "meta", meta )); HttpRequest req = HttpRequest.newBuilder() .uri(URI.create("https://" + HOST + "/merchant/workflows/" + WORKFLOW_CODE + "/executions")) .header("Authorization", "Bearer " + token) .header("Content-Type", "application/json") .header("x-idempotency-key", UUID.randomUUID().toString()) .timeout(Duration.ofSeconds(10)) .POST(HttpRequest.BodyPublishers.ofString(body.toString())) .build(); HttpResponse resp = HTTP.send(req, HttpResponse.BodyHandlers.ofString()); if (resp.statusCode() >= 300) { throw new RuntimeException("Create execution failed: " + resp.body()); } return new JSONObject(resp.body()).getString("id"); } ``` ```ts theme={null} import { randomUUID } from 'node:crypto' const WORKSPACE_ID = process.env.PAYRAILS_WORKSPACE_ID! const WORKFLOW_CODE = 'payment-acceptance' export async function createExecution ( merchantReference: string, holderReference: string, meta: Record, ): Promise { const token = await getAccessToken() const response = await fetch( `https://${HOST}/merchant/workflows/${WORKFLOW_CODE}/executions`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', 'x-idempotency-key': randomUUID(), }, body: JSON.stringify({ merchantReference, holderReference, workspaceId: WORKSPACE_ID, meta, }), }, ) if (!response.ok) { throw new Error(`Create execution failed: ${await response.text()}`) } const body = await response.json() as { id: string } return body.id } ``` ```csharp theme={null} using System.Net.Http.Json; public partial class PayrailsClient { private static readonly string WorkspaceId = Environment.GetEnvironmentVariable("PAYRAILS_WORKSPACE_ID")!; private const string WorkflowCode = "payment-acceptance"; public async Task CreateExecutionAsync( string merchantReference, string holderReference, Dictionary meta) { var token = await GetAccessTokenAsync(); var body = new { merchantReference, holderReference, workspaceId = WorkspaceId, meta, }; using var request = new HttpRequestMessage( HttpMethod.Post, $"https://{Host}/merchant/workflows/{WorkflowCode}/executions") { Content = JsonContent.Create(body), }; request.Headers.Add("Authorization", $"Bearer {token}"); request.Headers.Add("x-idempotency-key", Guid.NewGuid().ToString()); using var response = await Http.SendAsync(request); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(); return result!.Id; } private record ExecutionResponse(string Id); } ``` ```go theme={null} import ( "bytes" "github.com/google/uuid" ) var ( WorkspaceID = os.Getenv("PAYRAILS_WORKSPACE_ID") WorkflowCode = "payment-acceptance" ) func CreateExecution( merchantReference string, holderReference string, meta map[string]any, ) (string, error) { token, err := GetAccessToken() if err != nil { return "", err } body, _ := json.Marshal(map[string]any{ "merchantReference": merchantReference, "holderReference": holderReference, "workspaceId": WorkspaceID, "meta": meta, }) url := fmt.Sprintf("https://%s/merchant/workflows/%s/executions", Host, WorkflowCode) req, _ := http.NewRequest(http.MethodPost, url, bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") req.Header.Set("x-idempotency-key", uuid.NewString()) resp, err := httpClient.Do(req) if err != nil { return "", err } defer resp.Body.Close() if resp.StatusCode >= 300 { return "", fmt.Errorf("create execution failed: %d", resp.StatusCode) } var data struct { ID string `json:"id"` } if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { return "", err } return data.ID, nil } ``` ### Authorize the execution The second call dispatches the authorize against the tokenized `paymentInstrumentId`. The HTTP response is an acknowledgment; the actual outcome (frictionless approval, 3-D Secure required, or decline) arrives via long-poll or webhook. ```python theme={null} def authorize_execution( execution_id: str, amount: dict[str, str], payment_instrument_id: str, payment_method_code: str, return_url: str, ) -> dict[str, Any]: """Dispatch the authorize. Outcome arrives via long-poll or webhook.""" token = get_access_token() response = requests.post( f'https://{PAYRAILS_HOST}/merchant/workflows' f'/{PAYRAILS_WORKFLOW_CODE}/executions/{execution_id}/authorize', headers={ 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json', 'x-idempotency-key': str(uuid.uuid4()), }, json={ 'amount': amount, 'returnInfo': {'success': return_url}, 'paymentComposition': [{ 'paymentMethodCode': payment_method_code, 'integrationType': 'api', 'amount': amount, 'storeInstrument': False, 'paymentInstrumentId': payment_instrument_id, }], }, timeout=15, ) response.raise_for_status() return response.json() ``` ```java theme={null} // inside class PayrailsClient public static JSONObject authorizeExecution( String executionId, Map amount, String paymentInstrumentId, String paymentMethodCode, String returnUrl ) throws Exception { String token = getAccessToken(); JSONObject paymentComposition = new JSONObject(Map.of( "paymentMethodCode", paymentMethodCode, "integrationType", "api", "amount", amount, "storeInstrument", false, "paymentInstrumentId", paymentInstrumentId )); JSONObject body = new JSONObject(Map.of( "amount", amount, "returnInfo", Map.of("success", returnUrl), "paymentComposition", new Object[]{ paymentComposition } )); HttpRequest req = HttpRequest.newBuilder() .uri(URI.create("https://" + HOST + "/merchant/workflows/" + WORKFLOW_CODE + "/executions/" + executionId + "/authorize")) .header("Authorization", "Bearer " + token) .header("Content-Type", "application/json") .header("x-idempotency-key", UUID.randomUUID().toString()) .timeout(Duration.ofSeconds(15)) .POST(HttpRequest.BodyPublishers.ofString(body.toString())) .build(); HttpResponse resp = HTTP.send(req, HttpResponse.BodyHandlers.ofString()); if (resp.statusCode() >= 300) { throw new RuntimeException("Authorize failed: " + resp.body()); } return new JSONObject(resp.body()); } ``` ```ts theme={null} export interface Amount { value: string; currency: string } export async function authorizeExecution ( executionId: string, amount: Amount, paymentInstrumentId: string, paymentMethodCode: string, returnUrl: string, ): Promise> { const token = await getAccessToken() const response = await fetch( `https://${HOST}/merchant/workflows/${WORKFLOW_CODE}` + `/executions/${executionId}/authorize`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', 'x-idempotency-key': randomUUID(), }, body: JSON.stringify({ amount, returnInfo: { success: returnUrl }, paymentComposition: [{ paymentMethodCode, integrationType: 'api', amount, storeInstrument: false, paymentInstrumentId, }], }), }, ) if (!response.ok) { throw new Error(`Authorize failed: ${await response.text()}`) } return response.json() } ``` ```csharp theme={null} public partial class PayrailsClient { public record Amount(string Value, string Currency); public async Task AuthorizeExecutionAsync( string executionId, Amount amount, string paymentInstrumentId, string paymentMethodCode, string returnUrl) { var token = await GetAccessTokenAsync(); var body = new { amount, returnInfo = new { success = returnUrl }, paymentComposition = new[] { new { paymentMethodCode, integrationType = "api", amount, storeInstrument = false, paymentInstrumentId, }, }, }; using var request = new HttpRequestMessage( HttpMethod.Post, $"https://{Host}/merchant/workflows/{WorkflowCode}" + $"/executions/{executionId}/authorize") { Content = JsonContent.Create(body), }; request.Headers.Add("Authorization", $"Bearer {token}"); request.Headers.Add("x-idempotency-key", Guid.NewGuid().ToString()); using var response = await Http.SendAsync(request); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync() ?? throw new InvalidOperationException("Empty authorize response"); } } ``` ```go theme={null} type Amount struct { Value string `json:"value"` Currency string `json:"currency"` } func AuthorizeExecution( executionID string, amount Amount, paymentInstrumentID string, paymentMethodCode string, returnURL string, ) (map[string]any, error) { token, err := GetAccessToken() if err != nil { return nil, err } body, _ := json.Marshal(map[string]any{ "amount": amount, "returnInfo": map[string]string{"success": returnURL}, "paymentComposition": []map[string]any{{ "paymentMethodCode": paymentMethodCode, "integrationType": "api", "amount": amount, "storeInstrument": false, "paymentInstrumentId": paymentInstrumentID, }}, }) url := fmt.Sprintf("https://%s/merchant/workflows/%s/executions/%s/authorize", Host, WorkflowCode, executionID) req, _ := http.NewRequest(http.MethodPost, url, bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") req.Header.Set("x-idempotency-key", uuid.NewString()) resp, err := httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode >= 300 { return nil, fmt.Errorf("authorize failed: %d", resp.StatusCode) } var result map[string]any if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } return result, nil } ``` ### Storefront-facing endpoint The endpoint the storefront calls runs the two Payrails calls, long-polls for the result, and returns a clean two-case contract. On `actionRequired === "3ds"`, the storefront opens the 3-D Secure container; otherwise it renders the order confirmation page. The authorize call returns an acknowledgment; the actual outcome (frictionless approval, 3-D Secure required, or decline) arrives via long-poll or webhook. This endpoint uses the long-poll inline so the storefront receives a single resolved response. The webhook still fires in parallel and remains the source of truth for order reconciliation; the [Webhook reconciliation](#webhook-reconciliation) section covers the handler. ```python theme={null} def place_order( payment_instrument_id: str, payment_method_code: str, amount: dict[str, str], order_reference: str, customer_reference: str, ) -> dict[str, Any]: """End-to-end place-order endpoint called by the storefront.""" execution_id = create_execution( merchant_reference=order_reference, holder_reference=customer_reference, meta={ 'order': {'reference': order_reference}, 'customer': {'reference': customer_reference}, 'tags': {'channel': 'web'}, }, ) authorize_execution( execution_id=execution_id, amount=amount, payment_instrument_id=payment_instrument_id, payment_method_code=payment_method_code, return_url=f'https://yourdomain.example/payment-return/{execution_id}', ) result = poll_execution( execution_id, wait_while=['created', 'authorizeRequested'], ) if result.get('actionRequired') == '3ds': return { 'actionRequired': '3ds', 'redirectUrl': result['requiredAction']['href'], 'executionId': execution_id, } return { 'status': result.get('status'), 'executionId': execution_id, 'orderReference': order_reference, } ``` ```java theme={null} // inside class PayrailsClient public static Map placeOrder( String paymentInstrumentId, String paymentMethodCode, Map amount, String orderReference, String customerReference ) throws Exception { String executionId = createExecution( orderReference, customerReference, Map.of( "order", Map.of("reference", orderReference), "customer", Map.of("reference", customerReference), "tags", Map.of("channel", "web") ) ); authorizeExecution( executionId, amount, paymentInstrumentId, paymentMethodCode, "https://yourdomain.example/payment-return/" + executionId ); JSONObject result = pollExecution(executionId, new String[]{"created", "authorizeRequested"}); if ("3ds".equals(result.optString("actionRequired"))) { return Map.of( "actionRequired", "3ds", "redirectUrl", result.getJSONObject("requiredAction").getString("href"), "executionId", executionId ); } return Map.of( "status", result.optString("status"), "executionId", executionId, "orderReference", orderReference ); } ``` ```ts theme={null} export async function placeOrder ( paymentInstrumentId: string, paymentMethodCode: string, amount: Amount, orderReference: string, customerReference: string, ): Promise> { const executionId = await createExecution( orderReference, customerReference, { order: { reference: orderReference }, customer: { reference: customerReference }, tags: { channel: 'web' }, }, ) await authorizeExecution( executionId, amount, paymentInstrumentId, paymentMethodCode, `https://yourdomain.example/payment-return/${executionId}`, ) const result = await pollExecution( executionId, ['created', 'authorizeRequested'], ) if (result.actionRequired === '3ds') { const ra = result.requiredAction as { href: string } return { actionRequired: '3ds', redirectUrl: ra.href, executionId, } } return { status: result.status, executionId, orderReference, } } ``` ```csharp theme={null} public partial class PayrailsClient { public async Task> PlaceOrderAsync( string paymentInstrumentId, string paymentMethodCode, Amount amount, string orderReference, string customerReference) { var executionId = await CreateExecutionAsync( orderReference, customerReference, new Dictionary { ["order"] = new { reference = orderReference }, ["customer"] = new { reference = customerReference }, ["tags"] = new { channel = "web" }, }); await AuthorizeExecutionAsync( executionId, amount, paymentInstrumentId, paymentMethodCode, $"https://yourdomain.example/payment-return/{executionId}"); var result = await PollExecutionAsync( executionId, new[] { "created", "authorizeRequested" }); if (result.RootElement.TryGetProperty("actionRequired", out var ar) && ar.GetString() == "3ds") { var href = result.RootElement .GetProperty("requiredAction") .GetProperty("href").GetString(); return new Dictionary { ["actionRequired"] = "3ds", ["redirectUrl"] = href!, ["executionId"] = executionId, }; } return new Dictionary { ["status"] = result.RootElement.GetProperty("status").GetString()!, ["executionId"] = executionId, ["orderReference"] = orderReference, }; } } ``` ```go theme={null} func PlaceOrder( paymentInstrumentID string, paymentMethodCode string, amount Amount, orderReference string, customerReference string, ) (map[string]any, error) { executionID, err := CreateExecution(orderReference, customerReference, map[string]any{ "order": map[string]string{"reference": orderReference}, "customer": map[string]string{"reference": customerReference}, "tags": map[string]string{"channel": "web"}, }) if err != nil { return nil, err } returnURL := fmt.Sprintf("https://yourdomain.example/payment-return/%s", executionID) if _, err := AuthorizeExecution( executionID, amount, paymentInstrumentID, paymentMethodCode, returnURL, ); err != nil { return nil, err } result, err := PollExecution(executionID, []string{"created", "authorizeRequested"}) if err != nil { return nil, err } if result["actionRequired"] == "3ds" { ra := result["requiredAction"].(map[string]any) return map[string]any{ "actionRequired": "3ds", "redirectUrl": ra["href"], "executionId": executionID, }, nil } return map[string]any{ "status": result["status"], "executionId": executionID, "orderReference": orderReference, }, nil } ``` ## 3-D Secure handling 3-D Secure runs only when the issuer requires a challenge. Your backend learns of this through one of two channels — both are valid: * **The `executionActionPending` webhook.** Preferred at scale. Requires a custom `notify` step on the workflow paused branch with `eventType: "executionActionPending"`. The default `payment-acceptance` template does not emit a webhook on the 3-D Secure pause. * **Long-polling `GET /executions/{id}`.** Available without workflow configuration. Use `waitWhile[status]=["created","authorizeRequested"]` to block until the execution leaves the pre-authorize states. The authorize HTTP response itself acknowledges the call. Do not rely on it to carry `actionRequired` or `requiredAction.href` — those fields surface on the polled execution state (or the webhook body), not necessarily on the authorize response. Once your backend has the resolved state, the canonical field to read is `requiredAction.href`. On a polled execution, the same URL is mirrored as `links.redirect`. The legacy field `links["3ds"]` only appears for the deprecated `3DS` action type and is often empty; read `requiredAction.href` instead. The choice of rendering container — iframe, modal, new tab, or full-page redirect — is yours. The only requirements: the container loads external URLs, and `returnInfo.success` is HTTPS and on your own domain. On the frictionless path, the execution moves straight to status `authorized`, `actionRequired` stays empty, and the customer never touches a Payrails-hosted URL. **Do not redirect the customer to `links.consumerWait`** That field carries a Payrails-hosted intermediate URL that the Drop-in SDK uses to orchestrate redirects on the customer's behalf. Redirecting to it from a server-to-server checkout routes every authorization — including the frictionless majority — through a Payrails-hosted page. The `requiredAction.href` pattern documented on this page produces a URL only when a challenge is actually required. ## Webhook reconciliation Your backend confirms every order on the `executionActionCompleted` webhook, not on the storefront event. The storefront's state is optimistic; the webhook is the source of truth. Every webhook delivery carries an HMAC signature header. Verify the signature before processing the body; the [Receive notifications](/docs/orchestration/payment-acceptance/receive-notifications) page documents the algorithm and header name. ```python theme={null} import json def handle_webhook(raw_body: bytes, signature_header: str) -> tuple[int, str]: """Webhook entry point. Returns (status_code, body).""" if not verify_payrails_signature(raw_body, signature_header): return 401, 'invalid signature' event = json.loads(raw_body) if event['event'] == 'executionActionCompleted': details = event['details'] if details['action'] == 'authorize' and details['success']: mark_order_paid( order_reference=details['execution']['merchantReference'], execution_id=details['execution']['id'], ) return 200, 'ok' ``` ```java theme={null} // inside class PayrailsWebhookHandler public WebhookResult handleWebhook(byte[] rawBody, String signatureHeader) { if (!verifyPayrailsSignature(rawBody, signatureHeader)) { return new WebhookResult(401, "invalid signature"); } JSONObject event = new JSONObject(new String(rawBody, StandardCharsets.UTF_8)); if ("executionActionCompleted".equals(event.getString("event"))) { JSONObject details = event.getJSONObject("details"); JSONObject execution = details.getJSONObject("execution"); if ("authorize".equals(details.getString("action")) && details.getBoolean("success")) { markOrderPaid( execution.getString("merchantReference"), execution.getString("id")); } } return new WebhookResult(200, "ok"); } public record WebhookResult(int status, String body) {} ``` ```ts theme={null} export interface WebhookResult { status: number; body: string } export async function handleWebhook ( rawBody: Buffer, signatureHeader: string, ): Promise { if (!verifyPayrailsSignature(rawBody, signatureHeader)) { return { status: 401, body: 'invalid signature' } } const event = JSON.parse(rawBody.toString('utf-8')) if (event.event === 'executionActionCompleted') { const { action, success, execution } = event.details if (action === 'authorize' && success) { await markOrderPaid(execution.merchantReference, execution.id) } } return { status: 200, body: 'ok' } } ``` ```csharp theme={null} public class PayrailsWebhookHandler { public async Task<(int Status, string Body)> HandleWebhookAsync( byte[] rawBody, string signatureHeader) { if (!VerifyPayrailsSignature(rawBody, signatureHeader)) { return (401, "invalid signature"); } using var doc = JsonDocument.Parse(rawBody); var root = doc.RootElement; if (root.GetProperty("event").GetString() == "executionActionCompleted") { var details = root.GetProperty("details"); var execution = details.GetProperty("execution"); if (details.GetProperty("action").GetString() == "authorize" && details.GetProperty("success").GetBoolean()) { await MarkOrderPaidAsync( execution.GetProperty("merchantReference").GetString()!, execution.GetProperty("id").GetString()!); } } return (200, "ok"); } } ``` ```go theme={null} type WebhookResult struct { Status int Body string } func HandleWebhook(rawBody []byte, signatureHeader string) WebhookResult { if !VerifyPayrailsSignature(rawBody, signatureHeader) { return WebhookResult{Status: 401, Body: "invalid signature"} } var event struct { Event string `json:"event"` Details struct { Action string `json:"action"` Success bool `json:"success"` Execution struct { MerchantReference string `json:"merchantReference"` ID string `json:"id"` } `json:"execution"` } `json:"details"` } if err := json.Unmarshal(rawBody, &event); err != nil { return WebhookResult{Status: 400, Body: "invalid body"} } if event.Event == "executionActionCompleted" && event.Details.Action == "authorize" && event.Details.Success { MarkOrderPaid( event.Details.Execution.MerchantReference, event.Details.Execution.ID, ) } return WebhookResult{Status: 200, Body: "ok"} } ``` The handler exits with `200` as soon as the handler records the event. Anything that can fail — order-database updates, downstream messaging, analytics — runs asynchronously after the response returns. A slow handler causes Payrails to retry the delivery, which forces your idempotency logic to do extra work. Implement `verify_payrails_signature` per the [Receive notifications](/docs/orchestration/payment-acceptance/receive-notifications) documentation. ## Long-poll patterns A long-poll on `GET /executions/{id}?waitWhile[status]=...` blocks until the execution leaves the listed pre-terminal states. Two cases use it in this architecture: * **Inside the place-order request,** to wait for the 3-D Secure decision. Pre-terminal states: `created`, `authorizeRequested`. The poll resolves either to `authorized` (frictionless) or to `authorizePending` (3-D Secure required, `requiredAction.href` populated). * **On the payment-return page after the challenge resolves,** to wait for the final outcome. Pre-terminal states: `authorizePending`. The poll resolves to `authorized` or to a failure state. ```python theme={null} import json def poll_execution( execution_id: str, wait_while: list[str], timeout_seconds: int = 30, ) -> dict[str, Any]: """Long-poll for the execution to leave the listed pre-terminal states.""" token = get_access_token() response = requests.get( f'https://{PAYRAILS_HOST}/merchant/workflows' f'/{PAYRAILS_WORKFLOW_CODE}/executions/{execution_id}', params={'waitWhile[status]': json.dumps(wait_while)}, headers={'Authorization': f'Bearer {token}'}, timeout=timeout_seconds, ) response.raise_for_status() return response.json() ``` ```java theme={null} // inside class PayrailsClient public static JSONObject pollExecution( String executionId, String[] waitWhile ) throws Exception { String token = getAccessToken(); String waitWhileJs = new JSONArray(waitWhile).toString(); String query = "?waitWhile[status]=" + java.net.URLEncoder.encode(waitWhileJs, StandardCharsets.UTF_8); HttpRequest req = HttpRequest.newBuilder() .uri(URI.create("https://" + HOST + "/merchant/workflows/" + WORKFLOW_CODE + "/executions/" + executionId + query)) .header("Authorization", "Bearer " + token) .timeout(Duration.ofSeconds(30)) .GET() .build(); HttpResponse resp = HTTP.send(req, HttpResponse.BodyHandlers.ofString()); if (resp.statusCode() >= 300) { throw new RuntimeException("Poll failed: " + resp.body()); } return new JSONObject(resp.body()); } ``` ```ts theme={null} export async function pollExecution ( executionId: string, waitWhile: string[], timeoutSeconds: number = 30, ): Promise> { const token = await getAccessToken() const query = new URLSearchParams({ 'waitWhile[status]': JSON.stringify(waitWhile), }) const url = `https://${HOST}/merchant/workflows/${WORKFLOW_CODE}` + `/executions/${executionId}?${query}` const controller = new AbortController() const timeout = setTimeout(() => controller.abort(), timeoutSeconds * 1000) try { const response = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` }, signal: controller.signal, }) if (!response.ok) { throw new Error(`Poll failed: ${await response.text()}`) } return response.json() } finally { clearTimeout(timeout) } } ``` ```csharp theme={null} public partial class PayrailsClient { public async Task PollExecutionAsync( string executionId, string[] waitWhile, int timeoutSeconds = 30) { var token = await GetAccessTokenAsync(); var waitWhileJs = JsonSerializer.Serialize(waitWhile); var url = $"https://{Host}/merchant/workflows/{WorkflowCode}" + $"/executions/{executionId}" + $"?waitWhile[status]={Uri.EscapeDataString(waitWhileJs)}"; using var request = new HttpRequestMessage(HttpMethod.Get, url); request.Headers.Add("Authorization", $"Bearer {token}"); using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds)); using var response = await Http.SendAsync(request, cts.Token); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync(cancellationToken: cts.Token) ?? throw new InvalidOperationException("Empty poll response"); } } ``` ```go theme={null} import ( "context" "net/url" ) func PollExecution( executionID string, waitWhile []string, ) (map[string]any, error) { token, err := GetAccessToken() if err != nil { return nil, err } waitWhileJSON, _ := json.Marshal(waitWhile) params := url.Values{} params.Set("waitWhile[status]", string(waitWhileJSON)) pollURL := fmt.Sprintf("https://%s/merchant/workflows/%s/executions/%s?%s", Host, WorkflowCode, executionID, params.Encode()) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() req, _ := http.NewRequestWithContext(ctx, http.MethodGet, pollURL, nil) req.Header.Set("Authorization", "Bearer "+token) resp, err := httpClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode >= 300 { return nil, fmt.Errorf("poll failed: %d", resp.StatusCode) } var result map[string]any if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } return result, nil } ``` The webhook remains the source of truth for order reconciliation. The long-poll is the in-request signal so the storefront receives a single resolved response. The two run in parallel and converge on the same execution state. ## Recommendations ### Idempotency keys Every write call to Payrails carries an `x-idempotency-key` header. The value is a fresh UUIDv4. Payrails dedupes retries against the same key, so a network-retry of the same logical call is safe. The idempotency key must be a valid UUID. Composite strings such as `order-123_attempt-1` are rejected by the Payrails API as malformed. Allocate a fresh UUIDv4 per logical operation and persist it alongside the operation so retries reuse the same key. ### Metadata immutability The `meta` block on the create-execution call locks once the authorize action completes. Anything that needs to surface on dashboards, webhooks, settlement reports, or PSP portals must be on the create-execution body. Treat the second call (`authorize`) as payment-specific only. The `meta.order.reference` and `meta.customer.reference` fields are not updatable after authorize. If your system assigns the internal order identifier after the Payrails call, keep the join in your own database. Example: the cart identifier is known at checkout time, while the order identifier becomes available only after authorization. ### Frictionless authorizations show no Payrails UX On the frictionless path, the customer never touches a Payrails-hosted URL. The authorize response carries an empty `actionRequired` and your backend renders the order confirmation page directly. The 3-D Secure container only opens when `actionRequired === "3ds"`. The [3-D Secure handling](#3-d-secure-handling) section explains the reason to read `requiredAction.href` rather than `links.consumerWait`. Payrails populates `consumerWait` on every authorize response for use by SDK-driven flows; `requiredAction.href` exists only when a challenge is required, so frictionless paths skip Payrails-hosted UX entirely. ## Next steps * Review the [Secure Fields reference](/docs/orchestration/checkout-sdks/web-v5-legacy/secure-fields) for the per-field event surface (`READY`, `CHANGE`, `FOCUS`, `BLUR`) and the styling options available on the iframes. * Read [Receive notifications](/docs/orchestration/payment-acceptance/receive-notifications) for the canonical HMAC signing format and the full event catalog. * See [Payment status](/docs/resources/payments/payment-status) for the meaning of every status value your reconciliation logic must handle, including `Unknown` (which routes to manual reconciliation, not automatic retry). * Use [Test payments](/docs/orchestration/payment-acceptance/test-payments) to exercise both the frictionless and 3-D Secure paths during testing, including the Test PSP for simulating declines and challenges. # Guides and API reference Source: https://docs.payrails.com/index Guides, SDKs, and API reference for Payrails: enable payment methods, connect PSPs, and launch checkout on web, iOS, Android, and React Native.
# Build with Payrails

Guides, SDKs, and API reference for building payments with Payrails.

Get started

Set up your account and make your first payment.

Payment methods

Configure and enable payment methods for your checkout.

# Accept a Dispute Source: https://docs.payrails.com/reference/acceptdispute https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/{disputeId}/accept Concede a dispute without submitting a defense. Use this when you choose not to contest the chargeback. # Action a Dispute Alert Source: https://docs.payrails.com/reference/actiondisputealert https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/alerts/{alertId}/action Submit the merchant's chosen outcome for a pre-chargeback dispute alert. The outcome is forwarded to the alert provider and the alert is moved to a terminal status. Runs synchronously and returns once the provider has been notified. # Add Descriptors to Enrollment Source: https://docs.payrails.com/reference/adddescriptorstoenrollment https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/alert-enrollments/{enrollmentId}/descriptors Add one or more merchant descriptors to an existing dispute alert enrollment. # Search & list API Logs Source: https://docs.payrails.com/reference/apilogs https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/api/logs Fetch a list of API Logs for the given query parameters. # Attach Tags to a Dispute Source: https://docs.payrails.com/reference/attachdisputetags https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/{disputeId}/tags Attach one or more Tags to a Dispute. For single-select tag types, attaching a new tag automatically replaces any existing tag of that type. For multi-select tag types, tags are added idempotently. # Authorize a payment Source: https://docs.payrails.com/reference/authorizeaction https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode}/executions/{executionId}/authorize Request a payment authorization during a workflow execution. # Bulk Attach Tags to Disputes Source: https://docs.payrails.com/reference/bulkattachdisputetags https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/tags-bulk Attaches the same set of tags to multiple disputes in a single operation. For single-select tag types, attaching replaces any existing tag of that type on each dispute. For multi-select tag types, tags are added idempotently. Fails fast if any dispute ID or tag ID is invalid. # Bulk manually reconcile records Source: https://docs.payrails.com/reference/bulkmanualreconcilerecords https://cdn.payrails.io/docs/api/openapi.min.json?nav=reconciliation post /reconciliation/records/reconcile Marks multiple reconciliation records as manually reconciled in a single bulk operation, capturing operator supplied reasons and comments. Records must not already be in a reconciled resolution. The response includes a summary of successes and failures. # Bulk Replace Dispute Tags by Type Source: https://docs.payrails.com/reference/bulkreplacedisputetagsbytype https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute put /dispute/disputes/tags-bulk Atomically replaces all tags of the specified type on multiple disputes with the provided set. Sending an empty tagIds array removes all tags of that type from every dispute. Tags of other types are not affected. Fails fast if any dispute ID or tag ID is invalid. # Cancel a payment Source: https://docs.payrails.com/reference/cancelaction https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode}/executions/{executionId}/cancel Request a payment cancelation during a workflow execution. # Capture a payment Source: https://docs.payrails.com/reference/captureaction https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode}/executions/{executionId}/capture Request a payment capture during a workflow execution. # Initialize a client SDK Source: https://docs.payrails.com/reference/clientinit https://cdn.payrails.io/docs/api/openapi.min.json?nav=get-started post /merchant/client/init Fetch the necessary information used to initialize Payrails SDK on your client. # Confirm a payment Source: https://docs.payrails.com/reference/confirmaction https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode}/executions/{executionId}/confirm Request a payment confirmation during a workflow execution. # Get connection version details Source: https://docs.payrails.com/reference/connectionversiondetail https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault get /token/connections/{connectionId}/versions/{connectionVersionId} Get connection version details by connection id and version id. # Create a provider config with authenticated onboarding Source: https://docs.payrails.com/reference/createauthenticatedproviderconfig https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider post /payment/providers/{providerId}/configs/authenticated Trigger an action to create the provider config after completing an authenticated onboarding flow. # Create a drop-in link Source: https://docs.payrails.com/reference/createdropinlink https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant post /merchant/dropInLinks Create a drop-in link. # Create an execution Source: https://docs.payrails.com/reference/createexecution https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode}/executions Create a workflow execution. # Create a holder Source: https://docs.payrails.com/reference/createholder https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant post /merchant/holders Create a holder. # Create an instrument Source: https://docs.payrails.com/reference/createinstrument https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment post /payment/instruments Create a payment instrument. # Create a provider config Source: https://docs.payrails.com/reference/createproviderconfig https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider post /payment/providers/{providerId}/configs Trigger an action to create the provider config. # Create a provider config onboarding URL Source: https://docs.payrails.com/reference/createproviderconfigonboardingurl https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider post /payment/providers/{providerId}/configs/{providerConfigId}/onboarding-url Build a redirect onboarding URL for a provider config. If the provider config does not exist yet, use the same provider config ID later when creating the authenticated provider config. # Create a report run Source: https://docs.payrails.com/reference/createreportrun https://cdn.payrails.io/docs/api/openapi.min.json?nav=reporting post /analytics/reportRuns Create a report run for the provided report. # Create a new Ruleset Source: https://docs.payrails.com/reference/createruleset https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant post /merchant/rulesets Create a new merchant Ruleset. # Create SSO connection Source: https://docs.payrails.com/reference/createssoconnection https://cdn.payrails.io/docs/api/openapi.min.json?nav=get-started post /auth/sso/connections Create a new SSO identity provider connection. # Create Tag Source: https://docs.payrails.com/reference/createtag https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/tags Create a new Tag. # Create a token Source: https://docs.payrails.com/reference/createtoken https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment post /payment/instruments/{instrumentId}/tokens Create a token for a payment instrument. # Create a connection Source: https://docs.payrails.com/reference/createvaultconnections https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault post /token/connections Saves the connection data and returns connection with ID. # Create a new version of a connection Source: https://docs.payrails.com/reference/createvaultconnectionversions https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault post /token/connections/{connectionId}/versions Saves the connection version data and returns connection version with ID. # Create a workflow configuration Source: https://docs.payrails.com/reference/createworkflowconfiguration https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode} Create a new workflow configuration version for the given workflow code. # Create a workspace Source: https://docs.payrails.com/reference/createworkspace https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant post /merchant/workspaces Create a new workspace. # Create workspaces Source: https://docs.payrails.com/reference/createworkspaces https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant post /merchant/workspaces/bulk-create Create workspaces in bulk. # Defend a Dispute Source: https://docs.payrails.com/reference/defenddispute https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/{disputeId}/defend Submit evidence to contest a dispute. Use this to send your defense materials directly to the payment provider. # Delete a connection Source: https://docs.payrails.com/reference/deleteconnection https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault delete /token/connections/{connectionId} Soft-delete a connection by marking it as deleted. Only connections without an active (live) version can be deleted. # Delete a drop-in link Source: https://docs.payrails.com/reference/deletedropinlink https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant delete /merchant/dropInLinks/{dropInLinkId} Mark a drop-in link as deleted. # Delete field by alias Source: https://docs.payrails.com/reference/deletefieldbyalias https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault delete /token/records/fields/{alias} Delete a field by the given alias. # Delete field by record ID and type Source: https://docs.payrails.com/reference/deletefieldbyrecordidandtype https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault delete /token/records/{recordId}/fields/{fieldType} Delete a field by the given record ID and field type. # Delete an instrument Source: https://docs.payrails.com/reference/deleteinstrument https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment delete /payment/instruments/{instrumentId} Delete an instrument from a holder. # Delete record by ID Source: https://docs.payrails.com/reference/deleterecord https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault delete /token/records/{recordId} Delete a record and all fields associated with it. # Delete a record by the alias of one of its fields Source: https://docs.payrails.com/reference/deleterecordbyalias https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault delete /token/records Delete a record and all fields associated with it by the alias of one of its fields. # Delete Tag Source: https://docs.payrails.com/reference/deletetag https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute delete /dispute/tags/{tagId} Soft-delete a Tag. Deleted tags can no longer be attached to disputes. # Delete a token by ID Source: https://docs.payrails.com/reference/deletetoken https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment delete /payment/instruments/{instrumentId}/tokens/{tokenId} Delete a token from Payrails and the provider. # Delete a token by reference Source: https://docs.payrails.com/reference/deletetokenfromprovider https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment delete /payment/providers/{providerId}/tokens/{tokenReference} Delete a token from Payrails and the provider. # Detach a Tag from a Dispute Source: https://docs.payrails.com/reference/detachdisputetag https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute delete /dispute/disputes/{disputeId}/tags/{tagId} Remove a Tag from a Dispute. This operation is idempotent. # Detokenize records and aliases Source: https://docs.payrails.com/reference/detokenizerecords https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault post /records/detokenize Reveal data stored in the Payrails Vault. An item is addressed by record identifier, by record alias, or by field alias, and a single request can mix all three. The response returns one entry per requested item. Match a result to what you sent by the keys it carries rather than by its position - a failed item echoes the key it was addressed by. An item that cannot be resolved carries an `error` and does not fail the rest of the request: * `request.not-found`: nothing matches the key the item was addressed by. The `detail` says which key that was - `recordId`, `recordAlias` or `alias`. * `vault.field.not-available`: the field holds no value that can be revealed - it was never given one, it expired out of volatile storage, or it reached the number of reveals allowed for it. A record addressed by `recordId` or `recordAlias` reports this only when none of its fields could be revealed; otherwise it comes back with the fields that could. A request holds at most 50 items. One carrying more is rejected with `413` and nothing is revealed. Every reveal counts against what the field is allowed, so a record addressed by several items of one request is revealed once - repeating an item costs no more of that allowance than asking once does. This endpoint is served on the Payrails Vault host and accepts a Vault access token. It is available by request and requires an approval by Payrails. # Download an evidence file by ID Source: https://docs.payrails.com/reference/downloaddisputeevidence https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/{disputeId}/evidences/{evidenceId} Download an evidence file from a given ID. # Download the representment evidence bundle Source: https://docs.payrails.com/reference/downloadrepresentmentbundle https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/{disputeId}/evidences/download Download a ZIP archive containing the dispute's current representment file plus every evidence file linked to the dispute, for audit purposes. # Edit representment sections Source: https://docs.payrails.com/reference/editdisputerepresentmentsections https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute put /dispute/disputes/{disputeId}/evidences/representment-sections Update the written sections of your dispute response. Use this endpoint to revise the content before finalizing your representment. If a PDF has already been generated for this dispute, editing the sections will discard it so it can be regenerated with your changes. # Enroll Descriptors for Dispute Alerts Source: https://docs.payrails.com/reference/enrolldisputealert https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/alert-enrollments Enroll one or more merchant descriptors with a pre-chargeback alert program. Runs synchronously and returns once the provider has accepted the enrollment. Behaviour depends on the program: - **Ethoca / CDRN / RDR** (actionable, descriptor-based): one or more `descriptors` are required. The request is forwarded to the provider (Chargeblast), which assigns a merchant reference. Returns once the provider has accepted the enrollment. - **VerifiINFORM / SAFE** (account-level, reporting-only): no descriptors; `externalReference` (the provider merchant ID for that program) is required instead. No provider API call is made — the enrollment row is created locally and used to resolve incoming fraud-report alert webhooks. Re-enrolling an existing (providerConfigId, program) pair resumes that enrollment: for actionable programs it appends new descriptors to the existing provider merchant; for account-level programs it updates the stored externalReference. # Get field details by alias Source: https://docs.payrails.com/reference/fieldbyalias https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault get /token/records/fields/{alias} Get field details for the given alias. # Get field details by alias list Source: https://docs.payrails.com/reference/fieldsinfobyaliases https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault get /token/records/fields Get field details for multiple provided aliases. The order in which aliases returned may not match the order in which you passed the aliases in request. Not found fields will be ignored: if you request fields by aliases a, b, c and there is no field with alias b, then only fields a and c are returned. # Get a URL for file upload. Source: https://docs.payrails.com/reference/fileupload https://cdn.payrails.io/docs/api/openapi.min.json?nav=analytics post /analytics/files/upload Request a presigned "PUT" URL to upload a file. The maximum file size allowed is 5 GB. # Update fraud order status Source: https://docs.payrails.com/reference/fraudupdateaction https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode}/executions/{executionId}/orderUpdate Update the fraud provider with the fraud order status. # Generate cryptogram for a Network Token Source: https://docs.payrails.com/reference/generatecryptogram https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment post /payment/instruments/{instrumentId}/generateCryptogram Generate cryptogram for a Network Token of a given instrument. # Generate representment PDF Source: https://docs.payrails.com/reference/generatedisputerepresentmentpdf https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/{disputeId}/evidences/generate-representment Compile your representment sections into a PDF and attach it to the dispute. Call this after you are satisfied with the written sections and ready to finalize your representment. # Generate representment plan Source: https://docs.payrails.com/reference/generatedisputerepresentmentplan https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/{disputeId}/evidences/generate-plan Generate a representment plan for a dispute. # Get an action by ID Source: https://docs.payrails.com/reference/getaction https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow get /merchant/actions/{actionId} Get a workflow action for the given ID. # Fetch a list of workspaces Source: https://docs.payrails.com/reference/getallworkspaces https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant get /merchant/workspaces Fetch a list of workspaces based on user permissions. # Get an API Log event by ID Source: https://docs.payrails.com/reference/getapilogevent https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/api/logs/{apiLogEventId} Get API Log event by ID. # Get issuer info by BIN Source: https://docs.payrails.com/reference/getbinlookup https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/binLookup/{bin} Provides card issuer information based on a bank identification number (BIN) or issuer identification number (IIN). # Get connection details Source: https://docs.payrails.com/reference/getconnection https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault get /token/connections/{connectionId} Get connection details for the given connection ID. # Get the default workflow configuration Source: https://docs.payrails.com/reference/getdefaultworkflowconfigurationversion https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow get /merchant/workflows/{workflowCode}/versions/default Get the default workflow configuration version. # Get Dispute by ID Source: https://docs.payrails.com/reference/getdispute https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/{disputeId} Retrieve a dispute by its ID. Use the include parameters to expand related objects such as payment details, evidence files, and representment sections in a single request. # Get Dispute Activities by Dispute ID Source: https://docs.payrails.com/reference/getdisputeactivities https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/{disputeId}/activities List all timeline activities for a given dispute, ordered chronologically. # Get Dispute Alert by ID Source: https://docs.payrails.com/reference/getdisputealert https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/alerts/{alertId} Retrieve a single pre-chargeback dispute alert by its ID. # Get Dispute Documents by Dispute ID Source: https://docs.payrails.com/reference/getdisputedocuments https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/{disputeId}/documents List the stored bank/scheme documents for a given dispute, each with a presigned download link generated at request time. # Get a dispute service run by ID Source: https://docs.payrails.com/reference/getdisputerun https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/runs/{runId} Retrieve a single dispute service run by its ID, including its execution attempts. A run that exists but belongs to a workspace you cannot access returns 404. Use this to inspect the outcome of a backfill, including its window, the disputes and payments it loaded, and any unsupported operations. # Get a drop-in link Source: https://docs.payrails.com/reference/getdropinlink https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant get /merchant/dropInLinks/{dropInLinkId} Fetch a single drop-in link by ID. # Get an execution by ID Source: https://docs.payrails.com/reference/getexecution https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow get /merchant/workflows/{workflowCode}/executions/{executionId} Get a workflow execution for the given ID. # Get file by ID. Source: https://docs.payrails.com/reference/getfilebyid https://cdn.payrails.io/docs/api/openapi.min.json?nav=analytics get /analytics/files/{fileId} Return file details and processing status by ID. # Get Fraud check by ID Source: https://docs.payrails.com/reference/getfraud https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/frauds/{fraudId} Find a Fraud check from a given ID. # Get Fraud Operation Logs by Fraud Operation ID Source: https://docs.payrails.com/reference/getfraudoperationlogs https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/frauds/{fraudId}/operations/{fraudOperationId}/logs Find fraud operation logs from a given `operationID`. # Get Fraud Operations by Fraud ID Source: https://docs.payrails.com/reference/getfraudoperations https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/frauds/{fraudId}/operations Find a fraud operation from a given `fraudID`. # Get a holder by ID Source: https://docs.payrails.com/reference/getholder https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant get /merchant/holders/{holderId} Get a holder for the given id. # Get an instrument by ID Source: https://docs.payrails.com/reference/getinstrument https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/instruments/{instrumentId} Get instrument by ID. # Request an access token Source: https://docs.payrails.com/reference/getoauthtoken https://cdn.payrails.io/docs/api/openapi.min.json?nav=get-started post /auth/token/{clientId} Retrieve an access token to authenticate your requests to Payrails' services. The access token will be valid for a limited duration indicated by the `expires_in` field in the response. You should store the token on your side until it expires, at which point you will need to obtain a new one by making a new request. # Get payment by ID Source: https://docs.payrails.com/reference/getpayment https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/payments/{paymentId} Find a Payment from a given ID. # Get Payment Operation Logs by Payment Operation ID Source: https://docs.payrails.com/reference/getpaymentoperationlogs https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/payments/{paymentId}/operations/{paymentOperationId}/logs Find payment operation logs from a given `operationID`. # Get Payment Operations by Payment ID Source: https://docs.payrails.com/reference/getpaymentoperations https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/payments/{paymentId}/operations Find a payment operation from a given `paymentID`. # Get provider by ID Source: https://docs.payrails.com/reference/getprovider https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider get /payment/providers/{providerId} Retrieve the provider by provider ID. # Get record and its fields by ID Source: https://docs.payrails.com/reference/getrecord https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault get /token/records/{recordId} Get a record and all fields associated with the record by the given ID. # Get record and its fields by alias Source: https://docs.payrails.com/reference/getrecordbyalias https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault get /token/records Retrieve a record and all fields associated with the record by the alias of one of its fields. # Get a report by ID Source: https://docs.payrails.com/reference/getreport https://cdn.payrails.io/docs/api/openapi.min.json?nav=reporting get /analytics/reports/{reportId} Get a report by ID. # Get a report run by ID Source: https://docs.payrails.com/reference/getreportrun https://cdn.payrails.io/docs/api/openapi.min.json?nav=reporting get /analytics/reportRuns/{reportRunId} Get a reportRun by ID. # Search & list reports Source: https://docs.payrails.com/reference/getreports https://cdn.payrails.io/docs/api/openapi.min.json?nav=reporting get /analytics/reports Fetch a list of reports. # Get a Ruleset Source: https://docs.payrails.com/reference/getruleset https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant get /merchant/rulesets/{rulesetId}/versions/{version} Fetches a Ruleset by a given ID and version. # Get SSO connection Source: https://docs.payrails.com/reference/getssoconnectionbyid https://cdn.payrails.io/docs/api/openapi.min.json?nav=get-started get /auth/sso/connections/{connectionId} Retrieve a single SSO identity provider connection by its identifier. # Get ThreeDS authentication by ID Source: https://docs.payrails.com/reference/getthreeds https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/threeds/{threeDSId} Find a ThreeDS authentication from a given ID. # Get ThreeDS Operation Logs by ThreeDS Operation ID Source: https://docs.payrails.com/reference/getthreedsoperationlogs https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/threeds/{threeDSId}/operation/{threeDSOperationId}/logs Find ThreeDS operation logs from a given `operationID`. # Get ThreeDS Operations by ThreeDS ID Source: https://docs.payrails.com/reference/getthreedsoperations https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/threeds/{threeDSId}/operations Find ThreeDS operations from a given `threeDSId`. # Get a token by ID Source: https://docs.payrails.com/reference/gettoken https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/instruments/{instrumentId}/tokens/{tokenId} Get a token by its ID in the provider. # Get a token by reference Source: https://docs.payrails.com/reference/gettokenfromprovider https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/providers/{providerId}/tokens/{tokenReference} Get a token by its reference. # Request a Vault access token Source: https://docs.payrails.com/reference/getvaultaccesstoken https://cdn.payrails.io/docs/api/openapi.min.json?nav=get-started post /token/auth Exchange your Payrails access token for a Vault access token. The Vault access token authenticates the `tokenize` and `detokenize` endpoints served on the Payrails Vault host, and grants only the operations your Payrails access token permits. The request body is empty, and these tokens are short-lived (the exact lifetime is returned in `expires_in`). Store it until it expires, then request a new one. This endpoint is available by request and requires an approval by Payrails. # List actions of an execution Source: https://docs.payrails.com/reference/getworkflowactions https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow get /merchant/workflows/{workflowCode}/executions/{executionId}/actions Fetch a list of merchant workflows actions for the given execution. # Get a workflow configuration Source: https://docs.payrails.com/reference/getworkflowconfigurationversion https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow get /merchant/workflows/{workflowCode}/versions/{workflowVersion} Get a workflow configuration version. # Search & list events Source: https://docs.payrails.com/reference/getworkflowhistory https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow get /merchant/workflows/{workflowCode}/executions/{executionId}/history Search & list a workflow execution event history. # Get a workspace by ID Source: https://docs.payrails.com/reference/getworkspace https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant get /merchant/workspaces/{workspaceId} Get a workspace for the given ID. # Getting started Source: https://docs.payrails.com/reference/index Overview of the Payrails API reference: every API area, grouped by domain as in the sidebar, with a link to its main endpoint. The Payrails API reference lists every endpoint of the payment orchestration platform, with its request and response formats, authentication, and errors. Start by requesting an access token. The cards below group the API by domain, in the same order as the sidebar. ## Get started Request an OAuth 2.0 access token for server-side requests. Start a client-side SDK session for a workflow and holder. Manage SSO identity provider connections. ## Workflow List and manage the workflow configurations that define each use case. Create and track workflow executions. Trigger actions that change an execution's state, such as authorize or refund. ## Payment Search and retrieve payments and their operations. Store and manage payment instruments that belong to a holder. Manage the provider tokens mapped to each payment instrument. Get issuer information for a card by its BIN. Search and list API request logs. Search and retrieve fraud checks created by workflow executions. Search and retrieve 3D Secure authentications created by workflow executions. ## Provider List payment providers and get one by ID. Manage the configurations for each provider. ## Merchant Create and manage routing rulesets. Manage holders, which group a customer's accounts, payment instruments, and identities. Create and manage workspaces. Create shareable payment links with full or partial payments. ## Vault Send a one-off request to a provider through the vault proxy. Manage the connections the vault proxy uses. Tokenize and detokenize records and manage their aliases. Initialize the Vault Display SDK. Get the public key used to encrypt data before tokenization. ## Analytics Get an upload URL for a file and retrieve files by ID. ## Reporting List available reports and get one by ID. Generate and retrieve report runs. ## Reconciliation Manually reconcile records in bulk. ## Dispute Manage disputes and chargebacks. # Search & list actions Source: https://docs.payrails.com/reference/listactions https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow get /merchant/actions Fetch a list of merchant workflows actions for the given query parameters. # List active provider configs Source: https://docs.payrails.com/reference/listactiveproviderconfigs https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider get /payment/providers/configs Fetch a list of active provider configs. # Filter & list connections Source: https://docs.payrails.com/reference/listconnections https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault get /token/connections Fetch list of connections for given query parameters. By default, deleted connections are excluded from the results. # List connection versions for connection Source: https://docs.payrails.com/reference/listconnectionversions https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault get /token/connections/{connectionId}/versions Fetch a list of connection versions for the given connectionId. # List Dispute Alert Enrollments Source: https://docs.payrails.com/reference/listdisputealertenrollments https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/alert-enrollments List the pre-chargeback dispute alert enrollments visible in your workspace. # List Dispute Alert Events Source: https://docs.payrails.com/reference/listdisputealertevents https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/alerts/{alertId}/events List the audit timeline events for a pre-chargeback dispute alert, newest first. # Search & list Dispute Alerts Source: https://docs.payrails.com/reference/listdisputealerts https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/alerts Search and list pre-chargeback dispute alerts in your workspace. Use the available filters to narrow results by status, match state, program, and date range. # Search & list Evidences Source: https://docs.payrails.com/reference/listdisputeevidences https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/{disputeId}/evidences Fetch a list of Evidences. # List dispute service runs Source: https://docs.payrails.com/reference/listdisputeruns https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/runs List asynchronous runs in the dispute service, scoped to the workspaces you can access. Runs back operations such as a backfill, which pulls disputes and their related payments from the provider into your dispute and payment records. Use the filters to narrow by run type, status, or resolution; results are ordered most-recent first. # Search & list Disputes Source: https://docs.payrails.com/reference/listdisputes https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes Search and list disputes in your workspace. Use the available filters to narrow results by status, payment, provider, date range, and more. # List drop-in links Source: https://docs.payrails.com/reference/listdropinlinks https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant get /merchant/dropInLinks Fetch a paginated list of drop-in links for the given query parameters. # List Enrollment Descriptors Source: https://docs.payrails.com/reference/listenrollmentdescriptors https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/alert-enrollments/{enrollmentId}/descriptors List the descriptors associated with a dispute alert enrollment. # List Enrollment Events Source: https://docs.payrails.com/reference/listenrollmentevents https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/disputes/alert-enrollments/{enrollmentId}/events List the activity events for a dispute alert enrollment. # Search & list executions Source: https://docs.payrails.com/reference/listexecutions https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow get /merchant/workflows/{workflowCode}/executions Fetch a list of merchant workflows executions for the given query parameters. # Search & list Fraud checks Source: https://docs.payrails.com/reference/listfraudchecks https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/frauds Fetch a list of fraud checks. # Search & list holders Source: https://docs.payrails.com/reference/listholders https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant get /merchant/holders Search & list holders. # Search & list instruments Source: https://docs.payrails.com/reference/listinstruments https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/instruments Fetch a list of payment instruments for the given query parameters. # Search & list payments Source: https://docs.payrails.com/reference/listpayments https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/payments Fetch a list of payments. # List Provider Configs by Provider Source: https://docs.payrails.com/reference/listproviderconfigs https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider get /payment/providers/{providerId}/configs Fetch a list of provider configs with a relationship to the provider. # Search & list providers Source: https://docs.payrails.com/reference/listproviders https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider get /payment/providers Fetch a list of providers. # Search & list report runs Source: https://docs.payrails.com/reference/listreportruns https://cdn.payrails.io/docs/api/openapi.min.json?nav=reporting get /analytics/reportRuns Fetch a list of report runs. # List Rulesets Source: https://docs.payrails.com/reference/listrulesets https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant get /merchant/rulesets Fetch a list of rulesets for the given query parameters. # Get SAML IdP configuration values Source: https://docs.payrails.com/reference/listsamlconnectionconfigs https://cdn.payrails.io/docs/api/openapi.min.json?nav=get-started get /auth/sso/connections/saml-configs Retrieve configuration values required to connect supported SAML identity providers for the active merchant. # List SSO connections Source: https://docs.payrails.com/reference/listssoconnections https://cdn.payrails.io/docs/api/openapi.min.json?nav=get-started get /auth/sso/connections Retrieve SSO identity provider connections using optional filters and cursor-based pagination. # List Tags Source: https://docs.payrails.com/reference/listtags https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute get /dispute/tags Search and list Tags available to the caller's workspace. # Search & list ThreeDS entities Source: https://docs.payrails.com/reference/listthreeds https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/threeds Fetch a list of ThreeDS entities. # Search & list tokens Source: https://docs.payrails.com/reference/listtokens https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment get /payment/instruments/{instrumentId}/tokens Fetch a list of tokens for a payment instrument. # Search & list workflow configurations Source: https://docs.payrails.com/reference/listworkflowconfigurations https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow get /merchant/workflows/{workflowCode} Fetch a list of workflow configuration versions for the given workflow code and query parameters. # Lookup payment options Source: https://docs.payrails.com/reference/lookupaction https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode}/executions/{executionId}/lookup Trigger an action to lookup the payment options for a workflow execution. This action synchronously returns the necessary data to present the payment options to the customer on the client-side. # Manually Match a Payment to a Dispute Alert Source: https://docs.payrails.com/reference/matchdisputealertpayment https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/alerts/{alertId}/match Manually link a payment to an unmatched dispute alert. Intended for a portal user to resolve an alert the automatic matcher could not link (or left ambiguous) by supplying the payment id directly. User-only — the request is rejected if the caller is not an authenticated portal user. Runs synchronously and returns once the payment has been linked. # Meta Source: https://docs.payrails.com/reference/meta Every field of the meta object: the order, customer, vendor, client context and risk data you attach to executions and drop-in links. # Invoke an outbound proxy connection Source: https://docs.payrails.com/reference/outboundconnectioninvocation https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault post /token/connections/{connectionId}/proxy Proxies an outbound request to the destination using the provided headers. Please note that you can configure connection using any of HTTP methods, not only POST. # Update a provider config status Source: https://docs.payrails.com/reference/patchproviderconfig https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider patch /payment/providers/{providerId}/configs/{providerConfigId} Trigger an action to patch the provider config. # Update SSO connection Source: https://docs.payrails.com/reference/patchssoconnection https://cdn.payrails.io/docs/api/openapi.min.json?nav=get-started patch /auth/sso/connections/{connectionId} Update the status or metadata of an existing SSO identity provider connection. # Updates a workflow configuration version Source: https://docs.payrails.com/reference/patchworkflowconfigurationversion https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow patch /merchant/workflows/{workflowCode}/versions/{workflowVersion} Updates the description and/or archived attributes of a workflow configuration version. At least one of them must be provided. # Create a payout Source: https://docs.payrails.com/reference/payoutaction https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode}/executions/{executionId}/payout Request a payout during a workflow execution. # Provider config by ID Source: https://docs.payrails.com/reference/providerconfiggetbyid https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider get /payment/providers/{providerId}/configs/{providerConfigId} Retrieve the provider config by its ID. # Provision a Network Token Source: https://docs.payrails.com/reference/provisionnetworktokenpublic https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment post /payment/instruments/{instrumentId}/provisionNetworkToken Provision a network token for a given payment instrument. # Get record and aliases for a given instrumentId. Source: https://docs.payrails.com/reference/recordsforinstrument https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault get /token/instruments/{instrumentId}/records Get record, aliases, and all associated fields for a given instrumentId. # Refund a payment Source: https://docs.payrails.com/reference/refundaction https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode}/executions/{executionId}/refund Request a payment refund during a workflow execution. # Refund a Dispute Alert Source: https://docs.payrails.com/reference/refunddisputealert https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/alerts/{alertId}/refund Initiate a payment refund for a matched pre-chargeback dispute alert. The refund is issued against the alert's original payment execution and the alert moves to `RefundInitiated` until the refund settles. When the payment was already refunded, no money moves and the alert is resolved directly. User-only: system and API-key callers are rejected. Gated by the `disputeAlertManualRefundEnabled` feature flag. # Regenerate representment plan Source: https://docs.payrails.com/reference/regeneratedisputerepresentmentplan https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/{disputeId}/evidences/regenerate-plan Discard the current representment plan and generate a fresh one from scratch. Use this when the AI-generated plan does not meet your needs and you want to start over. Returns the new plan immediately. Not available after the defense has been submitted or while another operation is in progress. # Replace Dispute Tags by Type Source: https://docs.payrails.com/reference/replacedisputetagsbytype https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute put /dispute/disputes/{disputeId}/tags Atomically replaces all tags of the specified type attached to a dispute with the provided set. Sending an empty tagIds array removes all tags of that type. Tags of other types are not affected. # Update the default workflow configuration Source: https://docs.payrails.com/reference/setdefaultworkflowconfigurationversion https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow put /merchant/workflows/{workflowCode}/versions/default Update the default workflow configuration version. # Set live version of a connection Source: https://docs.payrails.com/reference/setliveversion https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault put /token/connections/{connectionId}/versions/live Set certain version of connection as live version or deactivates connection by removing current live version. # Start a payment session Source: https://docs.payrails.com/reference/startpaymentsessionaction https://cdn.payrails.io/docs/api/openapi.min.json?nav=workflow post /merchant/workflows/{workflowCode}/executions/{executionId}/startPaymentSession Request the start of a payment session during a workflow execution. This action synchronously returns the necessary data to handle the session on the client-side. # Submit evidence files Source: https://docs.payrails.com/reference/submitdisputeevidence https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/{disputeId}/evidences/submit Finalize and submit previously uploaded evidence files for a dispute. Once submitted, the evidence is locked in and forwarded as part of your response to the dispute. # Submit representment plan evidences Source: https://docs.payrails.com/reference/submitdisputerepresentmentplanevidences https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/{disputeId}/evidences/submit-plan Confirm your evidence selections for the representment plan and trigger generation of the written representment sections. Returns the generated sections along with a timeline of key events for review. # Tokenize records Source: https://docs.payrails.com/reference/tokenizerecords https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault post /records/tokenize Store card or network token data in the Payrails Vault and receive aliases for it. The response returns one entry per requested record, in the order of the request, in the same representation the record retrieval endpoints return. A record that fails validation carries an `error` and does not fail the rest of the request. A request holds at most 50 records. One carrying more is rejected with `413` and no record is stored. Repeating a request stores new records and returns new aliases. The endpoint provides no idempotency. This endpoint is served on the Payrails Vault host and accepts a Vault access token. It is available by request and requires an approval by Payrails. # Unenroll a Descriptor Source: https://docs.payrails.com/reference/unenrollenrollmentdescriptor https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/alert-enrollments/{enrollmentId}/descriptors/{descriptorId}/unenroll Remove a single descriptor from a dispute alert enrollment. Runs synchronously and returns once the unenroll request has been submitted. # Update a provider config with authenticated onboarding Source: https://docs.payrails.com/reference/updateauthenticatedproviderconfig https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider put /payment/providers/{providerId}/configs/{providerConfigId}/authenticated Trigger an action to update the provider config after completing an authenticated onboarding flow. # Update connection details Source: https://docs.payrails.com/reference/updateconnection https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault patch /token/connections/{connectionId} Update connection details for the given connection ID. # Update an instrument Source: https://docs.payrails.com/reference/updateinstrument https://cdn.payrails.io/docs/api/openapi.min.json?nav=payment patch /payment/instruments/{instrumentId} Update an instrument. # Update a provider config Source: https://docs.payrails.com/reference/updateproviderconfig https://cdn.payrails.io/docs/api/openapi.min.json?nav=provider put /payment/providers/{providerId}/configs/{providerConfigId} Trigger an action to update the provider config. # Update a Ruleset Source: https://docs.payrails.com/reference/updateruleset https://cdn.payrails.io/docs/api/openapi.min.json?nav=merchant put /merchant/rulesets/{rulesetId} Creates a new version of the merchant Ruleset. # Update Tag Source: https://docs.payrails.com/reference/updatetag https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute patch /dispute/tags/{tagId} Update a Tag's name, color, or description. # Upload evidence files Source: https://docs.payrails.com/reference/uploaddisputeevidence https://cdn.payrails.io/docs/api/openapi.min.json?nav=dispute post /dispute/disputes/{disputeId}/evidences Upload evidence files on the dispute. # Initialize a Vault Client SDK Source: https://docs.payrails.com/reference/vaultclientinit https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault post /token/client/init Fetch the necessary information to initialize Display cards SDK on your client. # Execute an instant proxy request Source: https://docs.payrails.com/reference/vaultproxy https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault post /payment/providers/{providerId}/proxy Executes a proxy request from our Vault to an external provider. # Get a public encryption key for tokenization Source: https://docs.payrails.com/reference/vaultpublicinfo https://cdn.payrails.io/docs/api/openapi.min.json?nav=vault get /payment/vault/info Retrieve a public encryption key and a value to use as JWE kid field, to tokenize payment instruments in the vault. The key will be valid for a limited duration indicated by the `expiresIn` field in the response. You should renew the key on your side before it expires, at which point you will need to obtain a new one by making a new request.